2f5d6d7dcd
Config option 'repo' and 'repo_from' are used in several phases, merge them with one option 'repo'. 'append' in schema is used for appending the values from deprecated options to 'repo', so it won't break on any existing config files that have the old options of 'repo_from' and 'source_repo_from' (which is an alias of 'repo_from'). And 'repo' schema is updated to support repo dict as the value or an item in the values, a repo dict is just a dict contains repo options, 'baseurl' is required in the dict, like: {"baseurl": "http://example.com/url/to/repo"} or: {"baseurl": "Serer"} currently this is used in ostree phase to support extra repo options like: {"baseurl": "Server", "exclude": "systemd-container"} Signed-off-by: Qixiang Wan <qwan@redhat.com>
165 lines
7.1 KiB
Python
165 lines
7.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
from kobo.threads import ThreadPool, WorkerThread
|
|
import shutil
|
|
from productmd import images
|
|
import pipes
|
|
from kobo import shortcuts
|
|
|
|
from .base import ConfigGuardedPhase, PhaseLoggerMixin
|
|
from .. import util
|
|
from ..util import get_volid, get_repo_urls
|
|
from ..wrappers import kojiwrapper, iso, lorax, scm
|
|
|
|
|
|
class OstreeInstallerPhase(PhaseLoggerMixin, ConfigGuardedPhase):
|
|
name = 'ostree_installer'
|
|
|
|
def __init__(self, compose):
|
|
super(OstreeInstallerPhase, self).__init__(compose)
|
|
self.pool = ThreadPool(logger=self.logger)
|
|
|
|
def run(self):
|
|
for variant in self.compose.get_variants():
|
|
for arch in variant.arches:
|
|
for conf in util.get_arch_variant_data(self.compose.conf, self.name, arch, variant):
|
|
self.pool.add(OstreeInstallerThread(self.pool))
|
|
self.pool.queue_put((self.compose, variant, arch, conf))
|
|
|
|
self.pool.start()
|
|
|
|
|
|
class OstreeInstallerThread(WorkerThread):
|
|
def process(self, item, num):
|
|
compose, variant, arch, config = item
|
|
self.num = num
|
|
failable_arches = config.get('failable', [])
|
|
self.can_fail = util.can_arch_fail(failable_arches, arch)
|
|
with util.failable(compose, self.can_fail, variant, arch, 'ostree-installer',
|
|
logger=self.pool._logger):
|
|
self.worker(compose, variant, arch, config)
|
|
|
|
def worker(self, compose, variant, arch, config):
|
|
msg = 'Ostree phase for variant %s, arch %s' % (variant.uid, arch)
|
|
self.pool.log_info('[BEGIN] %s' % msg)
|
|
self.logdir = compose.paths.log.topdir('%s/%s/ostree_installer-%s' % (arch, variant, self.num))
|
|
|
|
repos = get_repo_urls(compose, shortcuts.force_list(config['repo']), arch=arch)
|
|
repos = [url.replace('$arch', arch) for url in repos]
|
|
output_dir = os.path.join(compose.paths.work.topdir(arch), variant.uid, 'ostree_installer')
|
|
util.makedirs(os.path.dirname(output_dir))
|
|
|
|
self.template_dir = os.path.join(compose.paths.work.topdir(arch), variant.uid, 'lorax_templates')
|
|
self._clone_templates(config.get('template_repo'), config.get('template_branch'))
|
|
disc_type = compose.conf['disc_types'].get('ostree', 'ostree')
|
|
|
|
volid = get_volid(compose, arch, variant, disc_type=disc_type)
|
|
task_id = self._run_ostree_cmd(compose, variant, arch, config, repos, output_dir, volid)
|
|
|
|
filename = compose.get_image_name(arch, variant, disc_type=disc_type)
|
|
self._copy_image(compose, variant, arch, filename, output_dir)
|
|
self._add_to_manifest(compose, variant, arch, filename)
|
|
self.pool.log_info('[DONE ] %s, (task id: %s)' % (msg, task_id))
|
|
|
|
def _clone_templates(self, url, branch='master'):
|
|
if not url:
|
|
self.template_dir = None
|
|
return
|
|
scm.get_dir_from_scm({'scm': 'git', 'repo': url, 'branch': branch, 'dir': '.'},
|
|
self.template_dir, logger=self.pool._logger)
|
|
|
|
def _get_release(self, compose, config):
|
|
if 'release' in config and config['release'] is None:
|
|
return compose.image_release
|
|
return config.get('release', None)
|
|
|
|
def _copy_image(self, compose, variant, arch, filename, output_dir):
|
|
iso_path = compose.paths.compose.iso_path(arch, variant, filename)
|
|
os_path = compose.paths.compose.os_tree(arch, variant)
|
|
boot_iso = os.path.join(output_dir, 'images', 'boot.iso')
|
|
|
|
shortcuts.run('cp -av %s/* %s/' %
|
|
(pipes.quote(output_dir), pipes.quote(os_path)))
|
|
try:
|
|
os.link(boot_iso, iso_path)
|
|
except OSError:
|
|
shutil.copy2(boot_iso, iso_path)
|
|
|
|
def _add_to_manifest(self, compose, variant, arch, filename):
|
|
full_iso_path = compose.paths.compose.iso_path(arch, variant, filename)
|
|
iso_path = compose.paths.compose.iso_path(arch, variant, filename, relative=True)
|
|
implant_md5 = iso.get_implanted_md5(full_iso_path)
|
|
|
|
img = images.Image(compose.im)
|
|
img.path = iso_path
|
|
img.mtime = util.get_mtime(full_iso_path)
|
|
img.size = util.get_file_size(full_iso_path)
|
|
img.arch = arch
|
|
img.type = "dvd-ostree"
|
|
img.format = "iso"
|
|
img.disc_number = 1
|
|
img.disc_count = 1
|
|
img.bootable = True
|
|
img.subvariant = variant.name
|
|
img.implant_md5 = implant_md5
|
|
setattr(img, 'can_fail', self.can_fail)
|
|
setattr(img, 'deliverable', 'ostree-installer')
|
|
try:
|
|
img.volume_id = iso.get_volume_id(full_iso_path)
|
|
except RuntimeError:
|
|
pass
|
|
compose.im.add(variant.uid, arch, img)
|
|
|
|
def _get_templates(self, config, key):
|
|
"""Retrieve all templates from configuration and make sure the paths
|
|
are absolute. Raises RuntimeError if template repo is needed but not
|
|
configured.
|
|
"""
|
|
templates = []
|
|
for template in config.get(key, []):
|
|
if template[0] != '/':
|
|
if not self.template_dir:
|
|
raise RuntimeError('Relative path to template without setting template_repo.')
|
|
template = os.path.join(self.template_dir, template)
|
|
templates.append(template)
|
|
return templates
|
|
|
|
def _run_ostree_cmd(self, compose, variant, arch, config, source_repo, output_dir, volid):
|
|
lorax_wrapper = lorax.LoraxWrapper()
|
|
cmd = lorax_wrapper.get_lorax_cmd(
|
|
compose.conf['release_name'],
|
|
compose.conf["release_version"],
|
|
self._get_release(compose, config),
|
|
repo_baseurl=source_repo,
|
|
output_dir=output_dir,
|
|
variant=variant.uid,
|
|
nomacboot=True,
|
|
volid=volid,
|
|
buildinstallpackages=config.get('installpkgs'),
|
|
add_template=self._get_templates(config, 'add_template'),
|
|
add_arch_template=self._get_templates(config, 'add_arch_template'),
|
|
add_template_var=config.get('add_template_var'),
|
|
add_arch_template_var=config.get('add_arch_template_var'),
|
|
rootfs_size=config.get('rootfs_size'),
|
|
is_final=compose.supported,
|
|
log_dir=self.logdir,
|
|
)
|
|
|
|
runroot_channel = compose.conf.get("runroot_channel")
|
|
runroot_tag = compose.conf["runroot_tag"]
|
|
|
|
packages = ['pungi', 'lorax', 'ostree']
|
|
log_file = os.path.join(self.logdir, 'runroot.log')
|
|
koji = kojiwrapper.KojiWrapper(compose.conf["koji_profile"])
|
|
koji_cmd = koji.get_runroot_cmd(runroot_tag, arch, cmd,
|
|
channel=runroot_channel,
|
|
use_shell=True, task_id=True,
|
|
packages=packages, mounts=[compose.topdir],
|
|
weight=compose.conf['runroot_weights'].get('ostree_installer'))
|
|
output = koji.run_runroot_cmd(koji_cmd, log_file=log_file)
|
|
if output["retcode"] != 0:
|
|
raise RuntimeError("Runroot task failed: %s. See %s for more details."
|
|
% (output["task_id"], log_file))
|
|
return output['task_id']
|