This patch adds basic preliminary support to cobbler
(https://fedorahosted.org/cobbler) to add as a client OS
provisioning server for autotest. Of course, deeper
integration with autotest is needed, but with this patch,
it is already possible to tell in the autotest web
interface as well as on the cli to reinstall the machine.

By client machine OS provisioning we mean, being able
to install autotest client machines programatically, in
an unattended way. We've been using this code to automate
internal test jobs at Red Hat for quite a while now and
feel this is a needed addition to autotest.

There's still a lot of work to do, such as:
 * Making both the web interface and the CLI aware of
   the list of OS hold by the install server, so people
   can choose in a hassle free way
 * Making autotest register a brand new system on the
   install server

We believe those can be addressed at later patches.

Changes from v1:
 * Refactored the code, passed interfaces to install
   servers to a separate file
 * Allowed to pass any amount of config through
   global_config.ini to the install server,
   in a way that is extensible to other install
   servers if people wish to implement them.

Signed-off-by: Cleber Rosa <[email protected]>
Signed-off-by: Lucas Meneghel Rodrigues <[email protected]>
---
 global_config.ini              |    7 +++
 server/hosts/install_server.py |   97 ++++++++++++++++++++++++++++++++++++++++
 server/hosts/remote.py         |   26 ++++++++++-
 3 files changed, 128 insertions(+), 2 deletions(-)
 create mode 100644 server/hosts/install_server.py

diff --git a/global_config.ini b/global_config.ini
index b1ac4ba..6a5a220 100644
--- a/global_config.ini
+++ b/global_config.ini
@@ -116,6 +116,13 @@ require_atfork_module: False
 # Set to False to disable ssh-agent usage with paramiko
 use_sshagent_with_paramiko: True
 
+[INSTALL_SERVER]
+type: cobbler
+# URL for xmlrpc_server, such as http://foo.com/cobbler_api
+xmlrpc_url:
+user:
+password:
+
 [PACKAGES]
 # Max age of packages in days. All packages older than this will be removed 
from
 # upload_location when the packager is run.
diff --git a/server/hosts/install_server.py b/server/hosts/install_server.py
new file mode 100644
index 0000000..a6b3e6b
--- /dev/null
+++ b/server/hosts/install_server.py
@@ -0,0 +1,97 @@
+"""
+Install server interfaces, for autotest client machine OS provisioning.
+"""
+import os, xmlrpclib, logging, time
+from autotest_lib.client.common_lib import error
+
+
+def remove_hosts_file():
+    """
+    Remove the ssh known hosts file for a machine.
+
+    Sometimes it is useful to have this done since on a test lab, SSH
+    fingerprints of the test machines keep changing all the time due
+    to frequent reinstalls.
+    """
+    known_hosts_file = "%s/.ssh/known_hosts" % os.getenv("HOME")
+    if os.path.isfile(known_hosts_file):
+        logging.debug("Deleting known hosts file %s", known_hosts_file)
+        os.remove(known_hosts_file)
+
+
+class CobblerInterface(object):
+    """
+    Implements interfacing with the Cobbler install server.
+
+    @see: https://fedorahosted.org/cobbler/
+    """
+    def __init__(self, **kwargs):
+        """
+        Sets class attributes from the keyword arguments passed to constructor.
+
+        @param **kwargs: Dict of keyword arguments passed to constructor.
+        """
+        self.xmlrpc_url = kwargs['xmlrpc_url']
+        self.user = kwargs['user']
+        self.password = kwargs['password']
+
+
+    def install_host(self, host, profile=None, timeout=None):
+        """
+        Install a host object with profile name defined by distro.
+
+        @param host: Autotest host object.
+        @param profile: String with cobbler profile name.
+        @param timeout: Amount of time to wait for the install.
+        """
+        if self.xmlrpc_url:
+
+            step_time = 60
+            if timeout is None:
+                # 1 hour of timeout by default
+                timeout = 1 * 3600
+
+            logging.info("Setting up machine %s install", host.hostname)
+            remove_hosts_file()
+            server = xmlrpclib.Server(self.xmlrpc_url)
+            token = server.login(self.user, self.password)
+
+            try:
+                system = server.find_system({"name" : host.hostname})[0]
+            except IndexError, detail:
+                ### TODO: Method to register this system as brand new
+                logging.error("Error finding %s: %s", host.hostname, detail)
+                raise ValueError("No system %s registered on install server" %
+                                 host.hostname)
+
+            system_handle = server.get_system_handle(system, token)
+            if profile:
+                server.modify_system(system_handle, 'profile', profile, token)
+            # Enable netboot for that machine (next time it'll reboot and be
+            # reinstalled)
+            server.modify_system(system_handle, 'netboot_enabled', 'True', 
token)
+            # Now, let's just restart the machine (machine has to have
+            # power management data properly set up).
+            server.save_system(system_handle, token)
+            server.power_system(system_handle, 'reboot', token)
+            logging.info("Installing machine %s with profile %s (timeout %s 
s)",
+                         host.hostname, profile, timeout)
+            install_start = time.time()
+            time_elapsed = 0
+            install_successful = False
+            while time_elapsed < timeout:
+                time.sleep(step_time)
+                system_info = server.get_system(system)
+                install_successful = not system_info.get('netboot_enabled')
+                if install_successful:
+                    break
+                time_elapsed = time.time() - install_start
+
+            if not install_successful:
+                raise error.HostInstallTimeoutError('Machine %s install '
+                                                    'timed out' % 
host.hostname)
+
+            host.wait_for_restart()
+            time_elapsed = time.time() - install_start
+            logging.info("Machine %s installed successfuly after %d s (%d 
min)",
+                         host.hostname, time_elapsed, time_elapsed/60)
diff --git a/server/hosts/remote.py b/server/hosts/remote.py
index d1b4b46..f8b7462 100644
--- a/server/hosts/remote.py
+++ b/server/hosts/remote.py
@@ -2,9 +2,9 @@
 if it is available."""
 
 import os, logging, urllib
-from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib import error, global_config
 from autotest_lib.server import utils
-from autotest_lib.server.hosts import base_classes, bootloader
+from autotest_lib.server.hosts import base_classes, install_server
 
 
 class RemoteHost(base_classes.Host):
@@ -29,6 +29,8 @@ class RemoteHost(base_classes.Host):
 
     VAR_LOG_MESSAGES_COPY_PATH = "/var/tmp/messages.autotest_start"
 
+    INSTALL_SERVER_MAPPING = {'cobbler': install_server.CobblerInterface}
+
     def _initialize(self, hostname, autodir=None, *args, **dargs):
         super(RemoteHost, self)._initialize(*args, **dargs)
 
@@ -53,6 +55,26 @@ class RemoteHost(base_classes.Host):
                     pass
 
 
+    def install(self, profile=None, timeout=None):
+        """
+        Install a profile using the install server.
+
+        @param profile: Profile name inside the install server database.
+        """
+        server_info = {}
+        cfg = global_config.global_config
+        cfg.parse_config_file()
+        for option, value in cfg.config.items('INSTALL_SERVER'):
+            server_info[option] = value
+
+        logging.debug("Install server params from global_config: %s",
+                      server_info)
+
+        ServerInterface = self.INSTALL_SERVER_MAPPING[server_info['type']]
+        server_interface = ServerInterface(**server_info)
+        server_interface.install_host(self, profile=profile, timeout=timeout)
+
+
     def job_start(self):
         """
         Abstract method, called the first time a remote host object
-- 
1.7.6

_______________________________________________
Autotest mailing list
[email protected]
http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

Reply via email to