Add a job.run_control method that can be used inside of server control
files to run other existing server control files. It's implemented as
a wrapper around job.run that redirects some of the messiness from
that method (and generalizes the method to handle this case better).

This CL doesn't provide an equivalent method on the client; I'm not
sure that's really practical, since on the client we don't have the
same guarantee that all the control files are already on the machine,
and if you really need to build up a composite control file you can
already do so on the server through at.run.

Risk: Low
Visibility: Adds some parameters to server_job.run to make it more
generic, and a job.run_control method to wrap it and make it easy
to run a control file from a control file.

Signed-off-by: John Admanski <[email protected]>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@2719 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/server/server_job.py b/server/server_job.py
index f49326a..1ce9822 100755
--- a/server/server_job.py
+++ b/server/server_job.py
@@ -95,8 +95,7 @@
         self.clientdir = os.path.join(self.autodir, 'client')
         self.toolsdir = os.path.join(self.autodir, 'client/tools')
         if control:
-            self.control = open(control, 'r').read()
-            self.control = re.sub('\r', '', self.control)
+            self.control = self._load_control_file(control)
         else:
             self.control = ''
         self.resultdir = resultdir
@@ -176,6 +175,16 @@
         self._register_subcommand_hooks()
 
 
+    @staticmethod
+    def _load_control_file(path):
+        f = open(path)
+        try:
+            control_file = f.read()
+        finally:
+            f.close()
+        return re.sub('\r', '', control_file)
+
+
     def _register_subcommand_hooks(self):
         """
         Register some hooks into the subcommand modules that allow us
@@ -342,11 +351,17 @@
         subcommand.parallel_simple(wrapper, machines, log, timeout)
 
 
+    USE_TEMP_DIR = object()
     def run(self, cleanup=False, install_before=False, install_after=False,
-            collect_crashdumps=True, namespace={}):
+            collect_crashdumps=True, namespace={}, control=None,
+            control_file_dir=None):
         # use a copy so changes don't affect the original dictionary
         namespace = namespace.copy()
         machines = self.machines
+        if control is None:
+            control = self.control
+        if control_file_dir is None:
+            control_file_dir = self.resultdir
 
         self.aborted = False
         namespace['machines'] = machines
@@ -359,41 +374,44 @@
 
         if self.resultdir:
             os.chdir(self.resultdir)
-
             self.enable_external_logging()
-            status_log = os.path.join(self.resultdir, 'status.log')
+
         collect_crashinfo = True
         temp_control_file_dir = None
         try:
             if install_before and machines:
                 self._execute_code(INSTALL_CONTROL_FILE, namespace)
-            if self.resultdir:
-                server_control_file = SERVER_CONTROL_FILENAME
-                client_control_file = CLIENT_CONTROL_FILENAME
+
+            # determine the dir to write the control files to
+            if control_file_dir and control_file_dir is not self.USE_TEMP_DIR:
+                temp_control_file_dir = None
             else:
-                temp_control_file_dir = tempfile.mkdtemp()
-                server_control_file = os.path.join(temp_control_file_dir,
-                                                   SERVER_CONTROL_FILENAME)
-                client_control_file = os.path.join(temp_control_file_dir,
-                                                   CLIENT_CONTROL_FILENAME)
+                temp_control_file_dir = control_file_dir = tempfile.mkdtemp(
+                    suffix='temp_control_file_dir')
+            server_control_file = os.path.join(control_file_dir,
+                                               SERVER_CONTROL_FILENAME)
+            client_control_file = os.path.join(control_file_dir,
+                                               CLIENT_CONTROL_FILENAME)
             if self.client:
-                namespace['control'] = self.control
-                utils.open_write_close(client_control_file, self.control)
+                namespace['control'] = control
+                utils.open_write_close(client_control_file, control)
                 shutil.copy(CLIENT_WRAPPER_CONTROL_FILE, server_control_file)
             else:
                 namespace['utils'] = utils
-                utils.open_write_close(server_control_file, self.control)
+                utils.open_write_close(server_control_file, control)
             self._execute_code(server_control_file, namespace)
 
             # disable crashinfo collection if we get this far without error
             collect_crashinfo = False
         finally:
             if temp_control_file_dir:
-                # Clean up temp. directory used for copies of the control files.
+                # Clean up temp directory used for copies of the control files
                 try:
                     shutil.rmtree(temp_control_file_dir)
                 except Exception, e:
-                    print 'Error', e, 'removing dir', temp_control_file_dir
+                    print 'Error %s removing dir %s' % (e,
+                                                        temp_control_file_dir)
+
             if machines and (collect_crashdumps or collect_crashinfo):
                 namespace['test_start_time'] = test_start_time
                 if collect_crashinfo:
@@ -527,6 +545,15 @@
                         optional_fields={"kernel": kernel})
 
 
+    def run_control(self, path):
+        """Execute a control file found at path (relative to the autotest
+        path). Intended for executing a control file within a control file,
+        not for running the top-level job control file."""
+        path = os.path.join(self.autodir, path)
+        control_file = self._load_control_file(path)
+        self.run(control=control_file, control_file_dir=self.USE_TEMP_DIR)
+
+
     def add_sysinfo_command(self, command, logfile=None, on_every_test=False):
         self._add_sysinfo_loggable(sysinfo.command(command, logfile),
                                    on_every_test)