diff options
Diffstat (limited to 'mason/tests/build.py')
-rw-r--r-- | mason/tests/build.py | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/mason/tests/build.py b/mason/tests/build.py new file mode 100644 index 0000000..625252d --- /dev/null +++ b/mason/tests/build.py @@ -0,0 +1,128 @@ +# 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 cliapp +import json +import logging +import morphlib +import os +import subprocess +import time +import urlparse + +import mason + + +class Build(object): + + """A single build instance.""" + + def __init__(self, name, controller, logfile): + self.system_name = name + self.controller = controller + self.log_path = logfile + self.logfile = open(logfile, 'w+') + #TODO: use distbuild not local build + self.command = [ + 'morph', 'build', self.system_name] + + def start(self): + self.process = subprocess.Popen(self.command, stdout=self.logfile, stderr=self.logfile) + + def completed(self): + return (self.process.poll() is not None) + + def close_log(self): + self.logfile.close() + + +class Runner(mason.runners.JobRunner): + + """Test that the built system will deploy and run + + This handles running the build-deploy-build test, which + is used to ensure that Baserock can build Baserock. + """ + + log = logging.getLogger("mason.tests.build.Runner") + + def __init__(self, worker_server, plugin_config, job_name): + super(Runner, self).__init__(worker_server, plugin_config, job_name) + + self.total_steps = 4 + + def run_job(self): + self.log.debug('Got job: %s', self.job_arguments) + + self.log.info('Step 1: Creating a workspace') + self._create_workspace() + + self.log.info('Step 2: Prepare build log directory') + self._prepare_build_log_dir() + + self.log.info('Step 3: Building the systems') + try: + self._build_systems() + except Exception as e: + self._remove_workspace() + raise e + + self.log.info('Step 4: Clean up') + self._clean_up() + + @staticmethod + def _parse_controllers(conf): + return dict(item.split(':', 1) for item in conf['controllers']) + + def _prepare_builds(self, conf): + cluster = self.morph_helper.load_morphology(conf['cluster-morphology']) + systems = set(self.morph_helper.iterate_systems(cluster['systems'])) + controllers = self._parse_controllers(conf) + builds = [] + for system_name in systems: + system = self.morph_helper.load_morphology(system_name) + print 'loaded %s' % system_name + if system['arch'] in controllers: + logfile = os.path.join(self.logdir, '%s.log' % system['name']) + builds.append(Build(system_name, controllers[system['arch']], logfile)) + print 'prepared builds' + return builds + + @mason.util.job_step + def _prepare_build_log_dir(self): + self.logdir = '/var/www/logs/%s-%s/build' % \ + (self.project, self.commit[:7]) + if not os.path.exists(self.logdir): + os.makedirs(self.logdir) + + @mason.util.job_step + def _build_systems(self): + builds = self._prepare_builds(self.plugin_config['config']) + os.chdir(self.defs_checkout) + for build in builds: + build.start() + # TODO: Don't force serialisation when we change to distbuild. + while not build.completed(): + time.sleep(1) + + fail = False + for build in builds: + build.close_log() + if build.process.returncode != 0: + fail = True + logging.error('Building failed for %s. Log is at %s.' % + (build.system_name, build.log_path)) + if fail: + raise cliapp.AppException('Building of systems failed.') |