>From 85abeec30b6ab66010aa57e0edd40a97a6346c2e Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@gnome.org>
Date: Fri, 16 Nov 2012 11:28:43 +0100
Subject: [PATCH 2/2] Add support for the realm kickstart command

This command uses realmd to discover information about the domain
to join, which adds in the right packages, and then joins the domain
post install.
---
 anaconda.spec.in        |  1 +
 pyanaconda/install.py   | 15 ++++++++--
 pyanaconda/kickstart.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/anaconda.spec.in b/anaconda.spec.in
index 0b5ef39..c2d8333 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -122,6 +122,7 @@ Requires: python-pyblock >= %{pythonpyblockver}
 Requires: libuser-python
 Requires: newt-python
 Requires: authconfig
+Requires: realmd
 Requires: firewalld >= %{firewalldver}
 Requires: cryptsetup-luks
 Requires: python-cryptsetup >= %{pythoncryptsetupver}
diff --git a/pyanaconda/install.py b/pyanaconda/install.py
index b6fc3e8..fec0175 100644
--- a/pyanaconda/install.py
+++ b/pyanaconda/install.py
@@ -53,7 +53,7 @@ def doConfiguration(storage, payload, ksdata, instClass):
     from pyanaconda import progress
     from pyanaconda.kickstart import runPostScripts
 
-    progress.send_init(4)
+    progress.send_init(5)
 
     # Now run the execute methods of ksdata that require an installed system
     # to be present first.
@@ -78,6 +78,10 @@ def doConfiguration(storage, payload, ksdata, instClass):
         ksdata.group.execute(storage, ksdata, instClass, u)
         ksdata.user.execute(storage, ksdata, instClass, u)
 
+    if ksdata.realm.discovered:
+        with progress_report(_("Joining realm: %s" % ksdata.realm.discovered)):
+            ksdata.realm.execute(storage, ksdata, instClass)
+
     with progress_report(_("Running post install scripts")):
         runPostScripts(ksdata.scripts)
 
@@ -105,7 +109,7 @@ def doInstall(storage, payload, ksdata, instClass):
     steps = len(storage.devicetree.findActions(type="create", object="format")) + \
             len(storage.devicetree.findActions(type="resize", object="format")) + \
             len(storage.devicetree.findActions(type="migrate", object="format"))
-    steps += 4  # packages setup, packages, bootloader, post install
+    steps += 5  # packages setup, packages, bootloader, post install
     progress.send_init(steps)
 
     # Do partitioning.
@@ -116,10 +120,15 @@ def doInstall(storage, payload, ksdata, instClass):
 
     # Do packaging.
 
+    # Discover information about realms to join, to determine additional packages
+    if ksdata.realm.join_realm:
+        with progress_report(_("Discovering realm to join")):
+            ksdata.realm.discover()
+
     # anaconda requires storage packages in order to make sure the target
     # system is bootable and configurable, and some other packages in order
     # to finish setting up the system.
-    packages = storage.packages + ["authconfig", "firewalld"]
+    packages = storage.packages + ["authconfig", "firewalld"] + ksdata.realm.packages
     payload.preInstall(packages=packages, groups=payload.languageGroups(ksdata.lang.lang))
     payload.install()
 
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
index 2600c65..dddad7f 100644
--- a/pyanaconda/kickstart.py
+++ b/pyanaconda/kickstart.py
@@ -1262,6 +1262,80 @@ class RaidData(commands.raid.F18_RaidData):
                                      parents=request)
             storage.createDevice(luksdev)
 
+class Realm(commands.realm.F19_Realm):
+    def __init__(self, *args):
+        commands.realm.F19_Realm.__init__(self, *args)
+        self.packages = []
+        self.discovered = ""
+
+    def discover(self):
+        if not self.join_realm:
+            return
+
+        try:
+            args = ["discover", "--verbose", "--install", "/"] + \
+                   self.discover_options + [self.join_realm]
+            output = iutil.execWithCapture("/usr/sbin/realm", args,
+                                           stderr="/dev/tty5", fatal=True)
+        except RuntimeError as msg:
+            log.error("Error running /usr/sbin/realm %s: %s", args, msg)
+            return
+        except OSError as msg:
+            # TODO: A lousy way of propagating what will usually be 'no such realm'
+            log.error("Error running /usr/sbin/realm %s: %s", args, msg)
+            return
+
+        # Now parse the output for the required software. First line is the
+        # realm name, and following lines are information as "name: value"
+        self.packages = ["realmd"]
+        self.discovered = ""
+
+        lines = output.split("\n")
+        if not lines:
+            return
+
+        self.discovered = lines.pop(0).strip()
+        for line in lines:
+            parts = line.split(":", 1)
+            if len(parts) == 2 and parts[0].strip() == "required-package":
+                self.packages.append(parts[1].strip())
+
+        log.info("Realm %s needs packages %s" %
+                 (self.discovered, ", ".join(self.packages)))
+
+    def execute(self, *args):
+        if not self.discovered:
+            return
+
+        pw_args = ["--no-password"]
+        for arg in self.join_args:
+            if arg.startswith("--no-password") or arg.startswith("--one-time-password"):
+                pw_args = []
+                break
+
+        args = ["join", "--install", ROOT_PATH, "--verbose"] + pw_args + self.join_args
+        try:
+            rc = iutil.execWithRedirect("/usr/sbin/realm", args,
+                                        stdout="/dev/tty5", stderr="/dev/tty5")
+        except RuntimeError as msg:
+            log.error("Error running /usr/sbin/realm %s: %s", args, msg)
+
+        if rc != 0:
+            log.error("Command failure: /usr/sbin/realm %s: %d", args, rc)
+            return
+
+        log.info("Joined realm %s", self.join_realm)
+
+        for (command, options) in self.after:
+            args = [command, "--install", ROOT_PATH, "--verbose"] + options
+            rc = iutil.execWithRedirect("/usr/sbin/realm", args,
+                                        stdout="/dev/tty5", stderr="/dev/tty5")
+            if rc != 0:
+                log.error("Command failure: /usr/sbin/realm %s: %d", args, rc)
+
+            log.info("Ran /usr/sbin/realm %s", args)
+
+
 class RootPw(commands.rootpw.F18_RootPw):
     def execute(self, storage, ksdata, instClass, users):
         algo = getPassAlgo(ksdata.authconfig.authconfig)
@@ -1443,6 +1517,7 @@ commandMap = {
         "part": Partition,
         "partition": Partition,
         "raid": Raid,
+        "realm": Realm,
         "rootpw": RootPw,
         "selinux": SELinux,
         "services": Services,
-- 
1.8.0

