[live-media] Add global settings

These can be overriden for a particular image, but in general case they
can simplify the config.

Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2016-03-03 12:57:46 +01:00
parent 595845e104
commit 86bb816417
3 changed files with 167 additions and 7 deletions

View File

@ -758,6 +758,29 @@ Live Media Settings
* ``title`` (*str*) * ``title`` (*str*)
* ``install_tree_from`` (*str*) -- variant to take install tree from * ``install_tree_from`` (*str*) -- variant to take install tree from
If many of your media use the same value for one of ``ksurl``, ``release``,
``target`` or ``version``, consider using these options to set the value in one
place and have all media inherit it.
**live_media_ksurl**
(*str*) -- Provides a fallback for media that do not specify ``ksurl`` in
the ``live_media`` block.
**live_media_release**
(*str*) -- Provides a fallback for media that do not specify ``release`` in
the ``live_media`` block. Please note that if you set this, there is no way
to unset it for a particular media. This is important if you want the
release generated by Koji.
**live_media_target**
(*str*) -- Provides a fallback for media that do not specify ``target`` in
the ``live_media`` block.
**live_media_version**
(*str*) -- Provides a fallback for media that do not specify ``version`` in
the ``live_media`` block.
Image Build Settings Image Build Settings
==================== ====================

View File

@ -17,9 +17,33 @@ class LiveMediaPhase(PhaseBase):
"""class for wrapping up koji spin-livemedia""" """class for wrapping up koji spin-livemedia"""
name = 'live_media' name = 'live_media'
config_options = (
{
"name": "live_media",
"expected_types": [dict],
"optional": True,
},
{
"name": "live_media_ksurl",
"expected_types": [str],
"optional": True,
},
{
"name": "live_media_target",
"expected_types": [str],
"optional": True,
},
{
"name": "live_media_release",
"expected_types": [str],
"optional": True,
}
)
def __init__(self, compose): def __init__(self, compose):
super(LiveMediaPhase, self).__init__(compose) super(LiveMediaPhase, self).__init__(compose)
self.pool = ThreadPool(logger=self.compose._logger) self.pool = ThreadPool(logger=self.compose._logger)
self._global_ksurl = None
def skip(self): def skip(self):
if super(LiveMediaPhase, self).skip(): if super(LiveMediaPhase, self).skip():
@ -61,10 +85,13 @@ class LiveMediaPhase(PhaseBase):
return sorted(arches) return sorted(arches)
def _get_release(self, image_conf): def _get_release(self, image_conf):
"""If release is set explicitly to None, replace it with date and respin.""" """If release is set explicitly to None, replace it with date and respin.
if 'release' in image_conf and image_conf['release'] is None: Uses both image configuration and global config.
return '%s.%s' % (self.compose.compose_date, self.compose.compose_respin) """
return image_conf.get('release', None) for key, conf in [('release', image_conf), ('live_media_release', self.compose.conf)]:
if key in conf and conf[key] is None:
return '%s.%s' % (self.compose.compose_date, self.compose.compose_respin)
return image_conf.get('release', self.compose.conf.get('live_media_release'))
def _get_install_tree(self, image_conf, variant): def _get_install_tree(self, image_conf, variant):
if 'install_tree_from' in image_conf: if 'install_tree_from' in image_conf:
@ -80,16 +107,33 @@ class LiveMediaPhase(PhaseBase):
self.compose.paths.compose.os_tree('$basearch', variant, create_dir=False) self.compose.paths.compose.os_tree('$basearch', variant, create_dir=False)
) )
@property
def global_ksurl(self):
"""Get globally configure kickstart URL. It will only be resolved once."""
if not self._global_ksurl:
ksurl = self.compose.conf.get('live_media_ksurl')
self._global_ksurl = resolve_git_url(ksurl)
return self._global_ksurl
def _get_ksurl(self, image_conf):
"""Get ksurl from `image_conf`. If not present, fall back to global one."""
if 'ksurl' in image_conf:
return resolve_git_url(image_conf['ksurl'])
return self.global_ksurl
def _get_config(self, image_conf, opt):
return image_conf.get(opt, self.compose.conf.get('live_media_' + opt))
def run(self): def run(self):
for variant in self.compose.get_variants(): for variant in self.compose.get_variants():
arches = set([x for x in variant.arches if x != 'src']) arches = set([x for x in variant.arches if x != 'src'])
for image_conf in get_variant_data(self.compose.conf, self.name, variant): for image_conf in get_variant_data(self.compose.conf, self.name, variant):
config = { config = {
'target': image_conf['target'], 'target': self._get_config(image_conf, 'target'),
'arches': self._get_arches(image_conf, arches), 'arches': self._get_arches(image_conf, arches),
'ksfile': image_conf['kickstart'], 'ksfile': image_conf['kickstart'],
'ksurl': resolve_git_url(image_conf['ksurl']), 'ksurl': self._get_ksurl(image_conf),
'ksversion': image_conf.get('ksversion'), 'ksversion': image_conf.get('ksversion'),
'scratch': image_conf.get('scratch', False), 'scratch': image_conf.get('scratch', False),
'release': self._get_release(image_conf), 'release': self._get_release(image_conf),
@ -98,7 +142,7 @@ class LiveMediaPhase(PhaseBase):
'title': image_conf.get('title'), 'title': image_conf.get('title'),
'repo': self._get_repos(image_conf, variant), 'repo': self._get_repos(image_conf, variant),
'install_tree': self._get_install_tree(image_conf, variant), 'install_tree': self._get_install_tree(image_conf, variant),
'version': image_conf['version'], 'version': self._get_config(image_conf, 'version'),
} }
self.pool.add(LiveMediaThread(self.pool)) self.pool.add(LiveMediaThread(self.pool))
self.pool.queue_put((self.compose, variant, config)) self.pool.queue_put((self.compose, variant, config))

View File

@ -54,6 +54,99 @@ class TestLiveMediaPhase(PungiTestCase):
'version': 'Rawhide', 'version': 'Rawhide',
}))]) }))])
@mock.patch('pungi.phases.livemedia_phase.resolve_git_url')
@mock.patch('pungi.phases.livemedia_phase.ThreadPool')
def test_live_media_with_global_opts(self, ThreadPool, resolve_git_url):
compose = DummyCompose(self.topdir, {
'live_media_ksurl': 'git://example.com/repo.git#HEAD',
'live_media_target': 'f24',
'live_media_release': 'RRR',
'live_media_version': 'Rawhide',
'live_media': {
'^Server$': [
{
'kickstart': 'file.ks',
'name': 'Fedora Server Live',
},
{
'kickstart': 'different.ks',
'name': 'Fedora Server Live',
},
{
'kickstart': 'yet-another.ks',
'name': 'Fedora Server Live',
'ksurl': 'git://different.com/repo.git',
'target': 'f25',
'release': 'XXX',
'version': '25',
}
]
},
'koji_profile': 'koji',
})
resolve_git_url.return_value = 'git://example.com/repo.git#BEEFCAFE'
phase = LiveMediaPhase(compose)
phase.run()
self.assertTrue(phase.pool.add.called)
self.assertItemsEqual(resolve_git_url.mock_calls,
[mock.call('git://example.com/repo.git#HEAD'),
mock.call('git://different.com/repo.git')])
self.assertEqual(phase.pool.queue_put.call_args_list,
[mock.call((compose,
compose.variants['Server'],
{
'arches': ['amd64', 'x86_64'],
'ksfile': 'file.ks',
'ksurl': 'git://example.com/repo.git#BEEFCAFE',
'ksversion': None,
'name': 'Fedora Server Live',
'release': 'RRR',
'repo': [self.topdir + '/compose/Server/$basearch/os'],
'scratch': False,
'skip_tag': None,
'target': 'f24',
'title': None,
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
})),
mock.call((compose,
compose.variants['Server'],
{
'arches': ['amd64', 'x86_64'],
'ksfile': 'different.ks',
'ksurl': 'git://example.com/repo.git#BEEFCAFE',
'ksversion': None,
'name': 'Fedora Server Live',
'release': 'RRR',
'repo': [self.topdir + '/compose/Server/$basearch/os'],
'scratch': False,
'skip_tag': None,
'target': 'f24',
'title': None,
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
})),
mock.call((compose,
compose.variants['Server'],
{
'arches': ['amd64', 'x86_64'],
'ksfile': 'yet-another.ks',
'ksurl': 'git://example.com/repo.git#BEEFCAFE',
'ksversion': None,
'name': 'Fedora Server Live',
'release': 'XXX',
'repo': [self.topdir + '/compose/Server/$basearch/os'],
'scratch': False,
'skip_tag': None,
'target': 'f25',
'title': None,
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': '25',
}))])
@mock.patch('pungi.phases.livemedia_phase.ThreadPool') @mock.patch('pungi.phases.livemedia_phase.ThreadPool')
def test_live_media_non_existing_install_tree(self, ThreadPool): def test_live_media_non_existing_install_tree(self, ThreadPool):
compose = DummyCompose(self.topdir, { compose = DummyCompose(self.topdir, {