[live-images] Don't tweak kickstarts

Instead of downloading the kickstart file in Pungi and modifying it,
just pass it to Koji.

Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2016-02-17 14:35:28 +01:00
parent 454363fba8
commit bf5196af4a
5 changed files with 55 additions and 89 deletions

View File

@ -638,7 +638,8 @@ Live Images Settings
list should be tuples ``(variant_uid_regex, {arch|*: config})``. The config list should be tuples ``(variant_uid_regex, {arch|*: config})``. The config
should be a dict with these keys: should be a dict with these keys:
* ``kickstart`` (*str|dict*) * ``kickstart`` (*str*)
* ``ksurl`` (*str*) [optional] -- where to get the kickstart from
* ``name`` (*str*) * ``name`` (*str*)
* ``version`` (*str*) * ``version`` (*str*)
* ``additional_repos`` (*list*) -- external repos specified by URL * ``additional_repos`` (*list*) -- external repos specified by URL

View File

@ -17,20 +17,17 @@
import os import os
import sys import sys
import copy
import time import time
import pipes import pipes
import shutil import shutil
import tempfile
from kobo.threads import ThreadPool, WorkerThread from kobo.threads import ThreadPool, WorkerThread
from kobo.shortcuts import run from kobo.shortcuts import run
from pungi.wrappers.kojiwrapper import KojiWrapper from pungi.wrappers.kojiwrapper import KojiWrapper
from pungi.wrappers.iso import IsoWrapper from pungi.wrappers.iso import IsoWrapper
from pungi.wrappers.scm import get_file_from_scm
from pungi.phases.base import PhaseBase from pungi.phases.base import PhaseBase
from pungi.util import get_arch_variant_data from pungi.util import get_arch_variant_data, resolve_git_url
from pungi.paths import translate_path from pungi.paths import translate_path
@ -86,11 +83,10 @@ class LiveImagesPhase(PhaseBase):
for variant in self.compose.variants.values(): for variant in self.compose.variants.values():
for arch in variant.arches + ["src"]: for arch in variant.arches + ["src"]:
ks_in = get_ks_in(self.compose, arch, variant) data = get_arch_variant_data(self.compose.conf, "live_images", arch, variant)
if not ks_in: if not data:
continue continue
data = data[0]
ks_file = tweak_ks(self.compose, arch, variant, ks_in)
iso_dir = self.compose.paths.compose.iso_dir(arch, variant, symlink_to=symlink_isos_to) iso_dir = self.compose.paths.compose.iso_dir(arch, variant, symlink_to=symlink_isos_to)
if not iso_dir: if not iso_dir:
@ -102,32 +98,36 @@ class LiveImagesPhase(PhaseBase):
"iso_path": None, "iso_path": None,
"wrapped_rpms_path": iso_dir, "wrapped_rpms_path": iso_dir,
"build_arch": arch, "build_arch": arch,
"ks_file": ks_file, "ks_file": data['kickstart'],
"ksurl": None,
"specfile": None, "specfile": None,
"scratch": False, "scratch": False,
"label": "", # currently not used "label": "", # currently not used
} }
if 'ksurl' in data:
cmd['ksurl'] = resolve_git_url(data['ksurl'])
cmd["repos"] = [translate_path( cmd["repos"] = [translate_path(
self.compose, self.compose.paths.compose.repository(arch, variant, create_dir=False))] self.compose, self.compose.paths.compose.repository(arch, variant, create_dir=False))]
# additional repos # additional repos
data = get_arch_variant_data(self.compose.conf, "live_images", arch, variant) cmd["repos"].extend(data.get("additional_repos", []))
cmd["repos"].extend(data[0].get("additional_repos", [])) cmd['repos'].extend(self._get_extra_repos(arch, variant, data.get('repos_from', [])))
cmd['repos'].extend(self._get_extra_repos(arch, variant, data[0].get('repos_from', [])))
# Explicit name and version # Explicit name and version
cmd["name"] = data[0].get("name", None) cmd["name"] = data.get("name", None)
cmd["version"] = data[0].get("version", None) cmd["version"] = data.get("version", None)
cmd['type'] = data[0].get('type', 'live') cmd['type'] = data.get('type', 'live')
# Specfile (for images wrapped in rpm) # Specfile (for images wrapped in rpm)
cmd["specfile"] = data[0].get("specfile", None) cmd["specfile"] = data.get("specfile", None)
# Scratch (only taken in consideration if specfile specified) # Scratch (only taken in consideration if specfile specified)
# For images wrapped in rpm is scratch disabled by default # For images wrapped in rpm is scratch disabled by default
# For other images is scratch always on # For other images is scratch always on
cmd["scratch"] = data[0].get("scratch", False) cmd["scratch"] = data.get("scratch", False)
format = "%(compose_id)s-%(variant)s-%(arch)s-%(disc_type)s%(disc_num)s%(suffix)s" format = "%(compose_id)s-%(variant)s-%(arch)s-%(disc_type)s%(disc_num)s%(suffix)s"
# Custom name (prefix) # Custom name (prefix)
@ -204,7 +204,8 @@ class CreateLiveImageThread(WorkerThread):
image_type=cmd['type'], image_type=cmd['type'],
wait=True, wait=True,
archive=archive, archive=archive,
specfile=cmd["specfile"]) specfile=cmd["specfile"],
ksurl=cmd['ksurl'])
# avoid race conditions? # avoid race conditions?
# Kerberos authentication failed: Permission denied in replay cache code (-1765328215) # Kerberos authentication failed: Permission denied in replay cache code (-1765328215)
@ -239,47 +240,3 @@ class CreateLiveImageThread(WorkerThread):
dir, filename = os.path.split(iso_path) dir, filename = os.path.split(iso_path)
iso = IsoWrapper() iso = IsoWrapper()
run("cd %s && %s" % (pipes.quote(dir), iso.get_manifest_cmd(filename))) run("cd %s && %s" % (pipes.quote(dir), iso.get_manifest_cmd(filename)))
def get_ks_in(compose, arch, variant):
data = get_arch_variant_data(compose.conf, "live_images", arch, variant)
if not data:
return
scm_dict = data[0]["kickstart"]
if isinstance(scm_dict, dict):
file_name = os.path.basename(os.path.basename(scm_dict["file"]))
if scm_dict["scm"] == "file":
scm_dict["file"] = os.path.join(compose.config_dir, os.path.basename(scm_dict["file"]))
else:
file_name = os.path.basename(os.path.basename(scm_dict))
scm_dict = os.path.join(compose.config_dir, os.path.basename(scm_dict))
tmp_dir = tempfile.mkdtemp(prefix="ks_in_")
get_file_from_scm(scm_dict, tmp_dir, logger=compose._logger)
ks_in = os.path.join(compose.paths.work.topdir(arch), "liveimage-%s.%s.ks.in" % (variant.uid, arch))
shutil.copy2(os.path.join(tmp_dir, file_name), ks_in)
shutil.rmtree(tmp_dir)
return ks_in
def tweak_ks(compose, arch, variant, ks_in):
if variant.environments:
# get groups from default environment (with lowest display_order)
envs = copy.deepcopy(variant.environments)
envs.sort(lambda x, y: cmp(x["display_order"], y["display_order"]))
env = envs[0]
groups = sorted(env["groups"])
else:
# no environments -> get default groups
groups = []
for i in variant.groups:
if i["default"]:
groups.append(i["name"])
groups.sort()
ks_file = os.path.join(compose.paths.work.topdir(arch), "liveimage-%s.%s.ks" % (variant.uid, arch))
contents = open(ks_in, "r").read()
contents = contents.replace("__GROUPS__", "\n".join(["@%s" % i for i in groups]))
open(ks_file, "w").write(contents)
return ks_file

View File

@ -162,7 +162,7 @@ class KojiWrapper(object):
return cmd return cmd
def get_create_image_cmd(self, name, version, target, arch, ks_file, repos, image_type="live", image_format=None, release=None, wait=True, archive=False, specfile=None): def get_create_image_cmd(self, name, version, target, arch, ks_file, repos, image_type="live", image_format=None, release=None, wait=True, archive=False, specfile=None, ksurl=None):
# Usage: koji spin-livecd [options] <name> <version> <target> <arch> <kickstart-file> # Usage: koji spin-livecd [options] <name> <version> <target> <arch> <kickstart-file>
# Usage: koji spin-appliance [options] <name> <version> <target> <arch> <kickstart-file> # Usage: koji spin-appliance [options] <name> <version> <target> <arch> <kickstart-file>
# Examples: # Examples:
@ -194,6 +194,9 @@ class KojiWrapper(object):
if specfile: if specfile:
cmd.append("--specfile=%s" % specfile) cmd.append("--specfile=%s" % specfile)
if ksurl:
cmd.append("--ksurl=%s" % ksurl)
if isinstance(repos, list): if isinstance(repos, list):
for repo in repos: for repo in repos:
cmd.append("--repo=%s" % repo) cmd.append("--repo=%s" % repo)

View File

@ -297,12 +297,13 @@ class LiveImageKojiWrapperTest(KojiWrapperBaseTestCase):
def test_get_create_image_cmd_full(self): def test_get_create_image_cmd_full(self):
cmd = self.koji.get_create_image_cmd('my_name', '1.0', 'f24-candidate', cmd = self.koji.get_create_image_cmd('my_name', '1.0', 'f24-candidate',
'x86_64', '/path/to/ks', ['/repo/1', '/repo/2'], 'x86_64', '/path/to/ks', ['/repo/1', '/repo/2'],
release='1', wait=False, archive=True, specfile='foo.spec') release='1', wait=False, archive=True, specfile='foo.spec',
ksurl='https://git.example.com/')
self.assertEqual(cmd[0:2], ['koji', 'spin-livecd']) self.assertEqual(cmd[0:2], ['koji', 'spin-livecd'])
self.assertItemsEqual(cmd[2:8], self.assertEqual(cmd[-5:], ['my_name', '1.0', 'f24-candidate', 'x86_64', '/path/to/ks'])
self.assertItemsEqual(cmd[2:-5],
['--noprogress', '--nowait', '--repo=/repo/1', '--repo=/repo/2', ['--noprogress', '--nowait', '--repo=/repo/1', '--repo=/repo/2',
'--release=1', '--specfile=foo.spec']) '--release=1', '--specfile=foo.spec', '--ksurl=https://git.example.com/'])
self.assertEqual(cmd[8:], ['my_name', '1.0', 'f24-candidate', 'x86_64', '/path/to/ks'])
def test_spin_livecd_with_format(self): def test_spin_livecd_with_format(self):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):

View File

@ -61,13 +61,12 @@ class _DummyCompose(object):
class TestLiveImagesPhase(unittest.TestCase): class TestLiveImagesPhase(unittest.TestCase):
@mock.patch('pungi.phases.live_images.ThreadPool') @mock.patch('pungi.phases.live_images.ThreadPool')
@mock.patch('pungi.phases.live_images.get_ks_in') def test_live_image_build(self, ThreadPool):
@mock.patch('pungi.phases.live_images.tweak_ks')
def test_live_image_build(self, tweak_ks, get_ks_in, ThreadPool):
compose = _DummyCompose({ compose = _DummyCompose({
'live_images': [ 'live_images': [
('^Client$', { ('^Client$', {
'amd64': { 'amd64': {
'kickstart': 'test.ks',
'additional_repos': ['http://example.com/repo/'], 'additional_repos': ['http://example.com/repo/'],
'repos_from': ['Everything'], 'repos_from': ['Everything'],
} }
@ -75,10 +74,6 @@ class TestLiveImagesPhase(unittest.TestCase):
], ],
}) })
get_ks_in.side_effect = (lambda compose, arch, variant:
None if variant.uid != 'Client' or arch != 'amd64' else '/path/to/ks_in')
tweak_ks.return_value = '/path/to/ks_file'
phase = LiveImagesPhase(compose) phase = LiveImagesPhase(compose)
phase.run() phase.run()
@ -88,7 +83,7 @@ class TestLiveImagesPhase(unittest.TestCase):
self.maxDiff = None self.maxDiff = None
self.assertItemsEqual(phase.pool.queue_put.mock_calls, self.assertItemsEqual(phase.pool.queue_put.mock_calls,
[mock.call((compose, [mock.call((compose,
{'ks_file': '/path/to/ks_file', {'ks_file': 'test.ks',
'build_arch': 'amd64', 'build_arch': 'amd64',
'wrapped_rpms_path': '/iso_dir/amd64/Client', 'wrapped_rpms_path': '/iso_dir/amd64/Client',
'scratch': False, 'scratch': False,
@ -100,18 +95,20 @@ class TestLiveImagesPhase(unittest.TestCase):
'iso_path': '/iso_dir/amd64/Client/image-name', 'iso_path': '/iso_dir/amd64/Client/image-name',
'version': None, 'version': None,
'specfile': None, 'specfile': None,
'type': 'live'}, 'type': 'live',
'ksurl': None},
compose.variants['Client'], compose.variants['Client'],
'amd64'))]) 'amd64'))])
@mock.patch('pungi.phases.live_images.ThreadPool') @mock.patch('pungi.phases.live_images.ThreadPool')
@mock.patch('pungi.phases.live_images.get_ks_in') @mock.patch('pungi.phases.live_images.resolve_git_url')
@mock.patch('pungi.phases.live_images.tweak_ks') def test_spin_appliance(self, resolve_git_url, ThreadPool):
def test_spin_appliance(self, tweak_ks, get_ks_in, ThreadPool):
compose = _DummyCompose({ compose = _DummyCompose({
'live_images': [ 'live_images': [
('^Client$', { ('^Client$', {
'amd64': { 'amd64': {
'kickstart': 'test.ks',
'ksurl': 'https://git.example.com/kickstarts.git?#HEAD',
'additional_repos': ['http://example.com/repo/'], 'additional_repos': ['http://example.com/repo/'],
'repos_from': ['Everything'], 'repos_from': ['Everything'],
'type': 'appliance', 'type': 'appliance',
@ -120,9 +117,7 @@ class TestLiveImagesPhase(unittest.TestCase):
], ],
}) })
get_ks_in.side_effect = (lambda compose, arch, variant: resolve_git_url.return_value = 'https://git.example.com/kickstarts.git?#CAFEBABE'
None if variant.uid != 'Client' or arch != 'amd64' else '/path/to/ks_in')
tweak_ks.return_value = '/path/to/ks_file'
phase = LiveImagesPhase(compose) phase = LiveImagesPhase(compose)
@ -133,7 +128,7 @@ class TestLiveImagesPhase(unittest.TestCase):
self.maxDiff = None self.maxDiff = None
self.assertItemsEqual(phase.pool.queue_put.mock_calls, self.assertItemsEqual(phase.pool.queue_put.mock_calls,
[mock.call((compose, [mock.call((compose,
{'ks_file': '/path/to/ks_file', {'ks_file': 'test.ks',
'build_arch': 'amd64', 'build_arch': 'amd64',
'wrapped_rpms_path': '/iso_dir/amd64/Client', 'wrapped_rpms_path': '/iso_dir/amd64/Client',
'scratch': False, 'scratch': False,
@ -145,9 +140,12 @@ class TestLiveImagesPhase(unittest.TestCase):
'iso_path': '/iso_dir/amd64/Client/image-name', 'iso_path': '/iso_dir/amd64/Client/image-name',
'version': None, 'version': None,
'specfile': None, 'specfile': None,
'type': 'appliance'}, 'type': 'appliance',
'ksurl': 'https://git.example.com/kickstarts.git?#CAFEBABE'},
compose.variants['Client'], compose.variants['Client'],
'amd64'))]) 'amd64'))])
self.assertEqual(resolve_git_url.mock_calls,
[mock.call('https://git.example.com/kickstarts.git?#HEAD')])
class TestCreateLiveImageThread(unittest.TestCase): class TestCreateLiveImageThread(unittest.TestCase):
@ -172,6 +170,7 @@ class TestCreateLiveImageThread(unittest.TestCase):
'version': None, 'version': None,
'specfile': None, 'specfile': None,
'type': 'live', 'type': 'live',
'ksurl': 'https://git.example.com/kickstarts.git?#CAFEBABE',
} }
koji_wrapper = KojiWrapper.return_value koji_wrapper = KojiWrapper.return_value
@ -207,7 +206,8 @@ class TestCreateLiveImageThread(unittest.TestCase):
image_type='live', image_type='live',
archive=False, archive=False,
specfile=None, specfile=None,
wait=True)]) wait=True,
ksurl='https://git.example.com/kickstarts.git?#CAFEBABE')])
@mock.patch('shutil.copy2') @mock.patch('shutil.copy2')
@mock.patch('pungi.phases.live_images.run') @mock.patch('pungi.phases.live_images.run')
@ -229,6 +229,7 @@ class TestCreateLiveImageThread(unittest.TestCase):
'version': None, 'version': None,
'specfile': None, 'specfile': None,
'type': 'appliance', 'type': 'appliance',
'ksurl': None,
} }
koji_wrapper = KojiWrapper.return_value koji_wrapper = KojiWrapper.return_value
@ -264,7 +265,8 @@ class TestCreateLiveImageThread(unittest.TestCase):
image_type='appliance', image_type='appliance',
archive=False, archive=False,
specfile=None, specfile=None,
wait=True)]) wait=True,
ksurl=None)])
@mock.patch('shutil.copy2') @mock.patch('shutil.copy2')
@mock.patch('pungi.phases.live_images.run') @mock.patch('pungi.phases.live_images.run')
@ -287,7 +289,8 @@ class TestCreateLiveImageThread(unittest.TestCase):
'name': None, 'name': None,
'iso_path': '/iso_dir/amd64/Client/image-name', 'iso_path': '/iso_dir/amd64/Client/image-name',
'version': None, 'version': None,
'specfile': None 'specfile': None,
'ksurl': None,
} }
koji_wrapper = KojiWrapper.return_value koji_wrapper = KojiWrapper.return_value
@ -323,7 +326,8 @@ class TestCreateLiveImageThread(unittest.TestCase):
'name': None, 'name': None,
'iso_path': '/iso_dir/amd64/Client/image-name', 'iso_path': '/iso_dir/amd64/Client/image-name',
'version': None, 'version': None,
'specfile': None 'specfile': None,
'ksurl': None,
} }
def boom(*args, **kwargs): def boom(*args, **kwargs):