summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Coldrick <adam.coldrick@codethink.co.uk>2015-02-18 15:52:21 +0000
committerMichael Drake <michael.drake@codethink.co.uk>2015-03-09 17:01:23 +0000
commit009b22cc1c79e0576e9d21218be1983aea87e5da (patch)
tree8587cdf6b3cd1e8447ebcfc262716489c4395f3f
parent1139cc409e99a82a1944428a9df4a1170fd0b272 (diff)
downloadsystem-tests-009b22cc1c79e0576e9d21218be1983aea87e5da.tar.gz
Add a Zuul job runner.
-rw-r--r--mason/__init__.py1
-rw-r--r--mason/runners.py161
2 files changed, 162 insertions, 0 deletions
diff --git a/mason/__init__.py b/mason/__init__.py
index 162f0e5..dc5a195 100644
--- a/mason/__init__.py
+++ b/mason/__init__.py
@@ -1,3 +1,4 @@
from . import deployment
from . import publishers
+from . import runners
from . import util
diff --git a/mason/runners.py b/mason/runners.py
new file mode 100644
index 0000000..43fd26e
--- /dev/null
+++ b/mason/runners.py
@@ -0,0 +1,161 @@
+# Copyright 2014 Codethink Ltd.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import json
+import logging
+import os
+import shutil
+
+import cliapp
+
+from . import util
+
+class JobRunner(object):
+
+ """A generic Zuul job runner."""
+
+ logging.getLogger('mason.runners.JobRunner')
+
+ def __init__(self, worker_server, config, function):
+ self._reset()
+
+ self.worker_server = worker_server
+ self.plugin_config = config
+ self.function = function
+
+ self.total_steps = 0
+
+ def _reset(self):
+ self.success = True
+ self.cancelled = False
+ self.job = None
+ self.job_arguments = None
+ self.current_step = 0
+
+
+ def start_job(self, job):
+ self._reset()
+ self.job = job
+
+ if self.job is not None:
+ print "starting job"
+ try:
+ self.job_arguments = json.loads(self.job.arguments.decode('utf-8'))
+ self.send_work_data()
+ self.run_job()
+ self.send_work_complete()
+ except Exception as e:
+ self.success = False
+ self.send_work_data(result='Exception: %s' % e)
+ self.job.sendWorkException(str(e).encode('utf-8'))
+
+ def _get_work_data(self):
+ work_data = {'name': self.function,
+ 'location': os.uname()[1],
+ 'number': self.job.unique,
+ }
+ return work_data
+
+ def send_work_data(self, data=None, result=''):
+ if data is None:
+ data = self._get_work_data()
+ if self.success:
+ data['result'] = 'SUCCESS'
+ else:
+ data['result'] = result
+ logging.debug(json.dumps(data))
+ print data
+ self.job.sendWorkData(json.dumps(data))
+
+ def send_work_complete(self, data=None):
+ if data is None:
+ data = self._get_work_data()
+ self.send_work_data(data)
+ if self.success:
+ print 'sending work-complete'
+ self.job.sendWorkComplete(json.dumps(data))
+ else:
+ print 'sending work-fail'
+ self.job.sendWorkFail()
+
+ def stop_working(self, number=None):
+ if number is None or number == self.job.unique:
+ self.cancelled = True
+
+ def run_job(self):
+ # This function is to be implemented by subclasses
+ pass
+
+ def _do_next_step(self):
+ self._handle_cancellation()
+ self.current_step += 1
+ data = self._get_work_data()
+ data['current-step'] = self.current_step
+ self.send_work_data(data)
+
+ def _handle_cancellation(self):
+ if self.cancelled:
+ data = self._get_work_data()
+ data['result'] = 'Cancelled'
+ self.send_work_data(data)
+ self.job.sendWorkFail()
+ raise Exception('Job cancelled')
+
+ def _do_git_config(self, name='Mason Test Runner', email='mason@runner'):
+ cliapp.runcmd(['git', 'config', '--global', 'user.name', name])
+ cliapp.runcmd(['git', 'config', '--global', 'user.email', email])
+
+ @util.job_step
+ def _create_workspace(self):
+ os.chdir('/root')
+ self.commit = self.job_arguments['ZUUL_COMMIT']
+ self.project = self.job_arguments['ZUUL_PROJECT']
+ self.ref = self.job_arguments['ZUUL_REF']
+ self.workspace = '/root/mason-workspace'
+ self.zuul_url = self.job_arguments['ZUUL_URL']
+
+ self._do_git_config()
+
+ if os.path.exists(self.workspace):
+ shutil.rmtree(self.workspace)
+
+ cliapp.runcmd(['morph', 'init', self.workspace])
+
+ zuul_gits_dir = 'var/lib/zuul/git/'
+
+ repo_dir = os.path.join('/', zuul_gits_dir, self.project)
+ cliapp.runcmd(['morph', 'checkout', repo_dir, self.commit],
+ cwd=self.workspace)
+
+ # Morph allows us to rename the system branch directory from the
+ # ludicrously long name that it chose for us.
+ temp_defs_checkout = os.path.join(
+ self.workspace, self.commit, zuul_gits_dir, self.project)
+ self.defs_checkout = os.path.join(
+ self.workspace, self.commit, self.project)
+ logging.debug(
+ 'Renaming system-branch directory from %s to %s',
+ temp_defs_checkout, self.defs_checkout)
+ os.renames(temp_defs_checkout, self.defs_checkout)
+
+ self.morph_helper = util.MorphologyHelper(self.defs_checkout)
+
+ def _remove_workspace(self):
+ cliapp.runcmd(['rm', '-rf', self.workspace])
+
+ @util.job_step
+ def _clean_up(self):
+ os.chdir('/root')
+ self._remove_workspace()