Phases createiso, liveimages, image_build, ostree_installer and osbs are done in parallel, logs from these phases are mixed and and it's not obvious which log message belongs to which phase. This change adds phase name in log message for these phases. The new mixin 'PhaseLoggerMixin' is added to extend a Pungi phase with a logging logger which copy handlers from compose's logger but with formatter changed. Fixes: #58 Signed-off-by: Qixiang Wan <qwan@redhat.com>
126 lines
4.8 KiB
Python
126 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import json
|
|
import os
|
|
from kobo.threads import ThreadPool, WorkerThread
|
|
|
|
from .base import ConfigGuardedPhase, PhaseLoggerMixin
|
|
from .. import util
|
|
from ..wrappers import kojiwrapper
|
|
from ..paths import translate_path
|
|
|
|
|
|
class OSBSPhase(PhaseLoggerMixin, ConfigGuardedPhase):
|
|
name = 'osbs'
|
|
|
|
def __init__(self, compose):
|
|
super(OSBSPhase, self).__init__(compose)
|
|
self.pool = ThreadPool(logger=self.logger)
|
|
self.pool.metadata = {}
|
|
|
|
def run(self):
|
|
for variant in self.compose.get_variants():
|
|
for conf in util.get_variant_data(self.compose.conf, self.name, variant):
|
|
self.pool.add(OSBSThread(self.pool))
|
|
self.pool.queue_put((self.compose, variant, conf))
|
|
|
|
self.pool.start()
|
|
|
|
def dump_metadata(self):
|
|
"""Create a file with image metadata if the phase actually ran."""
|
|
if self._skipped:
|
|
return
|
|
with open(self.compose.paths.compose.metadata('osbs.json'), 'w') as f:
|
|
json.dump(self.pool.metadata, f, indent=4, sort_keys=True,
|
|
separators=(',', ': '))
|
|
|
|
|
|
class OSBSThread(WorkerThread):
|
|
def process(self, item, num):
|
|
compose, variant, config = item
|
|
self.num = num
|
|
with util.failable(compose, bool(config.pop('failable', None)), variant, '*', 'osbs',
|
|
logger=self.pool._logger):
|
|
self.worker(compose, variant, config)
|
|
|
|
def worker(self, compose, variant, config):
|
|
msg = 'OSBS phase for variant %s' % variant.uid
|
|
self.pool.log_info('[BEGIN] %s' % msg)
|
|
koji = kojiwrapper.KojiWrapper(compose.conf['koji_profile'])
|
|
koji.login()
|
|
|
|
# Start task
|
|
try:
|
|
source = util.resolve_git_url(config.pop('url'))
|
|
target = config.pop('target')
|
|
except KeyError as exc:
|
|
raise RuntimeError('OSBS: missing config key %s for %s'
|
|
% (exc, variant.uid))
|
|
priority = config.pop('priority', None)
|
|
|
|
config['yum_repourls'] = [self._get_repo(compose, variant)]
|
|
|
|
task_id = koji.koji_proxy.buildContainer(source, target, config,
|
|
priority=priority)
|
|
|
|
# Wait for it to finish and capture the output into log file (even
|
|
# though there is not much there).
|
|
log_dir = os.path.join(compose.paths.log.topdir(), 'osbs')
|
|
util.makedirs(log_dir)
|
|
log_file = os.path.join(log_dir, '%s-%s-watch-task.log'
|
|
% (variant.uid, self.num))
|
|
if koji.watch_task(task_id, log_file) != 0:
|
|
raise RuntimeError('OSBS: task %s failed: see %s for details'
|
|
% (task_id, log_file))
|
|
|
|
# Only real builds get the metadata.
|
|
if not config.get('scratch', False):
|
|
self._add_metadata(koji.koji_proxy, variant, task_id)
|
|
|
|
self.pool.log_info('[DONE ] %s' % msg)
|
|
|
|
def _add_metadata(self, koji_proxy, variant, task_id):
|
|
# Create metadata
|
|
result = koji_proxy.getTaskResult(task_id)
|
|
build_id = int(result['koji_builds'][0])
|
|
buildinfo = koji_proxy.getBuild(build_id)
|
|
archives = koji_proxy.listArchives(build_id)
|
|
|
|
metadata = {
|
|
'name': buildinfo['name'],
|
|
'version': buildinfo['version'],
|
|
'release': buildinfo['release'],
|
|
'creation_time': buildinfo['creation_time'],
|
|
}
|
|
for archive in archives:
|
|
data = {
|
|
'filename': archive['filename'],
|
|
'size': archive['size'],
|
|
'checksum': archive['checksum'],
|
|
}
|
|
data.update(archive['extra'])
|
|
data.update(metadata)
|
|
arch = archive['extra']['image']['arch']
|
|
self.pool.log_debug('Created Docker base image %s-%s-%s.%s' % (
|
|
metadata['name'], metadata['version'], metadata['release'], arch))
|
|
self.pool.metadata.setdefault(
|
|
variant.uid, {}).setdefault(arch, []).append(data)
|
|
|
|
def _get_repo(self, compose, variant):
|
|
"""
|
|
Write a .repo file pointing to current variant and return URL to the
|
|
file.
|
|
"""
|
|
os_tree = compose.paths.compose.os_tree('$basearch', variant,
|
|
create_dir=False)
|
|
repo_file = os.path.join(compose.paths.work.tmp_dir(None, variant),
|
|
'compose-rpms-%s.repo' % self.num)
|
|
|
|
with open(repo_file, 'w') as f:
|
|
f.write('[%s]\n' % compose.compose_id)
|
|
f.write('name=Compose %s (RPMs)\n' % compose.compose_id)
|
|
f.write('baseurl=%s\n' % translate_path(compose, os_tree))
|
|
f.write('enabled=1\n')
|
|
f.write('gpgcheck=0\n')
|
|
|
|
return translate_path(compose, repo_file)
|