# 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): """This thread 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.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') self._build_systems() self.log.info('Step 4: Clean up') self._clean_up() 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]) def _parse_controllers(self, conf): print 'parsing controllers' controllers = {} for arch, addr in (item.split(':') for item in conf['controllers']): controllers[arch] = addr return 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 _create_workspace(self): 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'] url = urlparse.urlparse(self.zuul_url) self.defs_checkout = os.path.join(self.workspace, self.commit, url.hostname, '8080', self.project) self._do_git_config() cliapp.runcmd(['morph', 'init', self.workspace]) repo = 'http://%s:8080/%s' % (url.hostname, self.project) cliapp.runcmd(['morph', 'checkout', repo, self.commit], cwd=self.workspace) self.morph_helper = mason.util.MorphologyHelper(self.defs_checkout) @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() while not all(build.completed() for build in builds): 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.') @mason.util.job_step def _clean_up(self): os.chdir('/root') #TODO: don't do this in production self._do_git_config(name='Adam Coldrick', email='adam.coldrick@codethink.co.uk') cliapp.runcmd(['rm', '-rf', self.workspace])