Merge #206 Add option to customize disc type

This commit is contained in:
Dennis Gilmore 2016-03-08 13:40:43 +00:00
commit 0e7ea91d9d
6 changed files with 155 additions and 34 deletions

View File

@ -202,18 +202,18 @@ Options
------- -------
There a couple common format specifiers available for both the options: There a couple common format specifiers available for both the options:
* compose_id * ``compose_id``
* release_short * ``release_short``
* version * ``version``
* date * ``date``
* respin * ``respin``
* type * ``type``
* type_suffix * ``type_suffix``
* label * ``label``
* label_major_version * ``label_major_version``
* variant * ``variant``
* arch * ``arch``
* disc_type * ``disc_type``
**image_name_format** [optional] **image_name_format** [optional]
(*str*) -- Python's format string to serve as template for image names (*str*) -- Python's format string to serve as template for image names
@ -222,15 +222,15 @@ There a couple common format specifiers available for both the options:
means ``createiso``, ``live_images`` and ``buildinstall``. means ``createiso``, ``live_images`` and ``buildinstall``.
Available extra keys are: Available extra keys are:
* disc_num * ``disc_num``
* suffix * ``suffix``
**image_volid_formats** [optional] **image_volid_formats** [optional]
(*list*) -- A list of format strings for generating volume id. (*list*) -- A list of format strings for generating volume id.
The extra available keys are: The extra available keys are:
* base_product_short * ``base_product_short``
* base_product_version * ``base_product_version``
**image_volid_layered_product_formats** [optional] **image_volid_layered_product_formats** [optional]
(*list*) -- A list of format strings for generating volume id for layered (*list*) -- A list of format strings for generating volume id for layered
@ -239,6 +239,16 @@ There a couple common format specifiers available for both the options:
**volume_id_substitutions** [optional] **volume_id_substitutions** [optional]
(*dict*) -- A mapping of string replacements to shorten the volume id. (*dict*) -- A mapping of string replacements to shorten the volume id.
**disc_types** [optional]
(*dict*) -- A mapping for customizing ``disc_type`` used in image names.
Available keys are:
* ``boot`` -- for ``boot.iso`` images created in *buildinstall* phase
* ``live`` -- for images created by *live_images* phase
* ``dvd`` -- for images created by *createiso* phase
Default values are the same as the keys.
Example Example
------- -------
:: ::
@ -259,6 +269,12 @@ Example
'TC': 'T', 'TC': 'T',
} }
disc_types = {
'boot': 'netinst',
'live': 'Live',
'dvd': 'DVD',
}
Signing Signing
======= =======

View File

@ -189,7 +189,7 @@ class BuildinstallPhase(PhaseBase):
label = "" label = ""
volid = get_volid(self.compose, arch, variant, escape_spaces=False, disc_type="dvd") volid = get_volid(self.compose, arch, variant, escape_spaces=False, disc_type="dvd")
tweak_buildinstall(buildinstall_dir, os_tree, arch, variant.uid, label, volid, kickstart_file) tweak_buildinstall(buildinstall_dir, os_tree, arch, variant.uid, label, volid, kickstart_file)
symlink_boot_iso(self.compose, arch, variant) link_boot_iso(self.compose, arch, variant)
def get_kickstart_file(compose): def get_kickstart_file(compose):
@ -312,10 +312,12 @@ def tweak_buildinstall(src, dst, arch, variant, label, volid, kickstart_file=Non
shutil.rmtree(tmp_dir) shutil.rmtree(tmp_dir)
def symlink_boot_iso(compose, arch, variant): def link_boot_iso(compose, arch, variant):
if arch == "src": if arch == "src":
return return
disc_type = compose.conf.get('disc_types', {}).get('boot', 'boot')
symlink_isos_to = compose.conf.get("symlink_isos_to", None) symlink_isos_to = compose.conf.get("symlink_isos_to", None)
os_tree = compose.paths.compose.os_tree(arch, variant) os_tree = compose.paths.compose.os_tree(arch, variant)
# TODO: find in treeinfo? # TODO: find in treeinfo?
@ -323,8 +325,8 @@ def symlink_boot_iso(compose, arch, variant):
if not os.path.isfile(boot_iso_path): if not os.path.isfile(boot_iso_path):
return return
msg = "Symlinking boot.iso (arch: %s, variant: %s)" % (arch, variant) msg = "Linking boot.iso (arch: %s, variant: %s)" % (arch, variant)
filename = compose.get_image_name(arch, variant, disc_type="boot", filename = compose.get_image_name(arch, variant, disc_type=disc_type,
disc_num=None, suffix=".iso") disc_num=None, suffix=".iso")
new_boot_iso_path = compose.paths.compose.iso_path(arch, variant, filename, new_boot_iso_path = compose.paths.compose.iso_path(arch, variant, filename,
symlink_to=symlink_isos_to) symlink_to=symlink_isos_to)

View File

@ -54,6 +54,7 @@ class CreateisoPhase(PhaseBase):
def run(self): def run(self):
iso = IsoWrapper(logger=self.compose._logger) iso = IsoWrapper(logger=self.compose._logger)
symlink_isos_to = self.compose.conf.get("symlink_isos_to", None) symlink_isos_to = self.compose.conf.get("symlink_isos_to", None)
disc_type = self.compose.conf.get('disc_types', {}).get('dvd', 'dvd')
deliverables = [] deliverables = []
commands = [] commands = []
@ -64,7 +65,7 @@ class CreateisoPhase(PhaseBase):
self.compose.log_info("Skipping createiso for %s.%s due to config option" % (variant, arch)) self.compose.log_info("Skipping createiso for %s.%s due to config option" % (variant, arch))
continue continue
volid = get_volid(self.compose, arch, variant, disc_type='dvd') volid = get_volid(self.compose, arch, variant, disc_type=disc_type)
os_tree = self.compose.paths.compose.os_tree(arch, variant) os_tree = self.compose.paths.compose.os_tree(arch, variant)
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)
@ -90,9 +91,8 @@ class CreateisoPhase(PhaseBase):
for disc_num, iso_data in enumerate(split_iso_data): for disc_num, iso_data in enumerate(split_iso_data):
disc_num += 1 disc_num += 1
# XXX: hardcoded disc_type
filename = self.compose.get_image_name(arch, variant, filename = self.compose.get_image_name(arch, variant,
disc_type="dvd", disc_type=disc_type,
disc_num=disc_num) disc_num=disc_num)
iso_path = self.compose.paths.compose.iso_path(arch, iso_path = self.compose.paths.compose.iso_path(arch,
variant, variant,

View File

@ -178,6 +178,8 @@ class LiveImagesPhase(PhaseBase):
if self.compose.conf.get('live_images_no_rename', False): if self.compose.conf.get('live_images_no_rename', False):
return None return None
disc_type = self.compose.conf.get('disc_types', {}).get('live', 'live')
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)
if name: if name:
@ -186,8 +188,8 @@ class LiveImagesPhase(PhaseBase):
custom_iso_name += "-%s" % version custom_iso_name += "-%s" % version
format = custom_iso_name + "-%(variant)s-%(arch)s-%(disc_type)s%(disc_num)s%(suffix)s" format = custom_iso_name + "-%(variant)s-%(arch)s-%(disc_type)s%(disc_num)s%(suffix)s"
# XXX: hardcoded disc_type and disc_num # XXX: hardcoded disc_num
return self.compose.get_image_name(arch, variant, disc_type="live", return self.compose.get_image_name(arch, variant, disc_type=disc_type,
disc_num=None, format=format) disc_num=None, format=format)
def stop(self, *args, **kwargs): def stop(self, *args, **kwargs):

View File

@ -10,7 +10,7 @@ import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from pungi.phases.buildinstall import BuildinstallPhase, BuildinstallThread, symlink_boot_iso from pungi.phases.buildinstall import BuildinstallPhase, BuildinstallThread, link_boot_iso
from tests.helpers import DummyCompose, PungiTestCase, touch from tests.helpers import DummyCompose, PungiTestCase, touch
@ -312,14 +312,14 @@ class TestBuildinstallPhase(PungiTestCase):
class TestCopyFiles(PungiTestCase): class TestCopyFiles(PungiTestCase):
@mock.patch('pungi.phases.buildinstall.symlink_boot_iso') @mock.patch('pungi.phases.buildinstall.link_boot_iso')
@mock.patch('pungi.phases.buildinstall.tweak_buildinstall') @mock.patch('pungi.phases.buildinstall.tweak_buildinstall')
@mock.patch('pungi.phases.buildinstall.get_volid') @mock.patch('pungi.phases.buildinstall.get_volid')
@mock.patch('os.listdir') @mock.patch('os.listdir')
@mock.patch('os.path.isdir') @mock.patch('os.path.isdir')
@mock.patch('pungi.phases.buildinstall.get_kickstart_file') @mock.patch('pungi.phases.buildinstall.get_kickstart_file')
def test_copy_files_buildinstall(self, get_kickstart_file, isdir, listdir, def test_copy_files_buildinstall(self, get_kickstart_file, isdir, listdir,
get_volid, tweak_buildinstall, symlink_boot_iso): get_volid, tweak_buildinstall, link_boot_iso):
compose = BuildInstallCompose(self.topdir, { compose = BuildInstallCompose(self.topdir, {
'buildinstall_method': 'buildinstall' 'buildinstall_method': 'buildinstall'
}) })
@ -349,19 +349,19 @@ class TestCopyFiles(PungiTestCase):
self.topdir + '/compose/Client/amd64/os', self.topdir + '/compose/Client/amd64/os',
'amd64', 'Client', '', 'Client.amd64', 'kickstart')]) 'amd64', 'Client', '', 'Client.amd64', 'kickstart')])
self.assertItemsEqual( self.assertItemsEqual(
symlink_boot_iso.mock_calls, link_boot_iso.mock_calls,
[mock.call(compose, 'x86_64', compose.variants['Server']), [mock.call(compose, 'x86_64', compose.variants['Server']),
mock.call(compose, 'amd64', compose.variants['Client']), mock.call(compose, 'amd64', compose.variants['Client']),
mock.call(compose, 'amd64', compose.variants['Server'])]) mock.call(compose, 'amd64', compose.variants['Server'])])
@mock.patch('pungi.phases.buildinstall.symlink_boot_iso') @mock.patch('pungi.phases.buildinstall.link_boot_iso')
@mock.patch('pungi.phases.buildinstall.tweak_buildinstall') @mock.patch('pungi.phases.buildinstall.tweak_buildinstall')
@mock.patch('pungi.phases.buildinstall.get_volid') @mock.patch('pungi.phases.buildinstall.get_volid')
@mock.patch('os.listdir') @mock.patch('os.listdir')
@mock.patch('os.path.isdir') @mock.patch('os.path.isdir')
@mock.patch('pungi.phases.buildinstall.get_kickstart_file') @mock.patch('pungi.phases.buildinstall.get_kickstart_file')
def test_copy_files_lorax(self, get_kickstart_file, isdir, listdir, def test_copy_files_lorax(self, get_kickstart_file, isdir, listdir,
get_volid, tweak_buildinstall, symlink_boot_iso): get_volid, tweak_buildinstall, link_boot_iso):
compose = BuildInstallCompose(self.topdir, { compose = BuildInstallCompose(self.topdir, {
'buildinstall_method': 'lorax' 'buildinstall_method': 'lorax'
}) })
@ -391,7 +391,7 @@ class TestCopyFiles(PungiTestCase):
self.topdir + '/compose/Client/amd64/os', self.topdir + '/compose/Client/amd64/os',
'amd64', 'Client', '', 'Client.amd64', 'kickstart')]) 'amd64', 'Client', '', 'Client.amd64', 'kickstart')])
self.assertItemsEqual( self.assertItemsEqual(
symlink_boot_iso.mock_calls, link_boot_iso.mock_calls,
[mock.call(compose, 'x86_64', compose.variants['Server']), [mock.call(compose, 'x86_64', compose.variants['Server']),
mock.call(compose, 'amd64', compose.variants['Client']), mock.call(compose, 'amd64', compose.variants['Client']),
mock.call(compose, 'amd64', compose.variants['Server'])]) mock.call(compose, 'amd64', compose.variants['Server'])])
@ -576,7 +576,7 @@ class TestSymlinkIso(PungiTestCase):
get_file_size.return_value = 1024 get_file_size.return_value = 1024
get_mtime.return_value = 13579 get_mtime.return_value = 13579
symlink_boot_iso(self.compose, 'x86_64', self.compose.variants['Server']) link_boot_iso(self.compose, 'x86_64', self.compose.variants['Server'])
tgt = self.topdir + '/compose/Server/x86_64/iso/image-name' tgt = self.topdir + '/compose/Server/x86_64/iso/image-name'
self.assertTrue(os.path.isfile(tgt)) self.assertTrue(os.path.isfile(tgt))
@ -611,6 +611,55 @@ class TestSymlinkIso(PungiTestCase):
self.assertEqual(self.compose.im.add.mock_calls, self.assertEqual(self.compose.im.add.mock_calls,
[mock.call('Server', 'x86_64', image)]) [mock.call('Server', 'x86_64', image)])
@mock.patch('pungi.phases.buildinstall.Image')
@mock.patch('pungi.phases.buildinstall.get_mtime')
@mock.patch('pungi.phases.buildinstall.get_file_size')
@mock.patch('pungi.phases.buildinstall.IsoWrapper')
@mock.patch('pungi.phases.buildinstall.run')
def test_hardlink_with_custom_type(self, run, IsoWrapperCls, get_file_size, get_mtime, ImageCls):
self.compose.conf = {
'buildinstall_symlink': False,
'disc_types': {'boot': 'netinst'},
}
IsoWrapper = IsoWrapperCls.return_value
get_file_size.return_value = 1024
get_mtime.return_value = 13579
link_boot_iso(self.compose, 'x86_64', self.compose.variants['Server'])
tgt = self.topdir + '/compose/Server/x86_64/iso/image-name'
self.assertTrue(os.path.isfile(tgt))
self.assertEqual(os.stat(tgt).st_ino,
os.stat(self.topdir + '/compose/Server/x86_64/os/images/boot.iso').st_ino)
self.assertItemsEqual(
self.compose.get_image_name.mock_calls,
[mock.call('x86_64', self.compose.variants['Server'],
disc_type='netinst', disc_num=None, suffix='.iso')])
self.assertItemsEqual(IsoWrapper.get_implanted_md5.mock_calls,
[mock.call(tgt)])
self.assertItemsEqual(IsoWrapper.get_manifest_cmd.mock_calls,
[mock.call('image-name')])
self.assertItemsEqual(IsoWrapper.get_volume_id.mock_calls,
[mock.call(tgt)])
self.assertItemsEqual(run.mock_calls,
[mock.call(IsoWrapper.get_manifest_cmd.return_value,
workdir=self.topdir + '/compose/Server/x86_64/iso')])
image = ImageCls.return_value
self.assertEqual(image.path, 'Server/x86_64/iso/image-name')
self.assertEqual(image.mtime, 13579)
self.assertEqual(image.size, 1024)
self.assertEqual(image.arch, 'x86_64')
self.assertEqual(image.type, "boot")
self.assertEqual(image.format, "iso")
self.assertEqual(image.disc_number, 1)
self.assertEqual(image.disc_count, 1)
self.assertEqual(image.bootable, True)
self.assertEqual(image.implant_md5, IsoWrapper.get_implanted_md5.return_value)
self.assertEqual(self.compose.im.add.mock_calls,
[mock.call('Server', 'x86_64', image)])
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -58,6 +58,10 @@ class TestLiveImagesPhase(PungiTestCase):
'ksurl': None}, 'ksurl': None},
compose.variants['Client'], compose.variants['Client'],
'amd64'))]) 'amd64'))])
self.assertItemsEqual(
compose.get_image_name.mock_calls,
[mock.call('amd64', compose.variants['Client'], disc_num=None, disc_type='live',
format='%(compose_id)s-%(variant)s-%(arch)s-%(disc_type)s%(disc_num)s%(suffix)s')])
@mock.patch('pungi.phases.live_images.ThreadPool') @mock.patch('pungi.phases.live_images.ThreadPool')
def test_live_image_build_single_repo_from(self, ThreadPool): def test_live_image_build_single_repo_from(self, ThreadPool):
@ -260,6 +264,54 @@ class TestLiveImagesPhase(PungiTestCase):
self.assertEqual(resolve_git_url.mock_calls, self.assertEqual(resolve_git_url.mock_calls,
[mock.call('https://git.example.com/kickstarts.git?#HEAD')]) [mock.call('https://git.example.com/kickstarts.git?#HEAD')])
@mock.patch('pungi.phases.live_images.ThreadPool')
def test_live_image_build_custom_type(self, ThreadPool):
compose = DummyCompose(self.topdir, {
'disc_types': {'live': 'Live'},
'live_images': [
('^Client$', {
'amd64': {
'kickstart': 'test.ks',
'additional_repos': ['http://example.com/repo/'],
'repo_from': ['Everything'],
'release': None,
}
})
],
})
phase = LiveImagesPhase(compose)
phase.run()
# assert at least one thread was started
self.assertTrue(phase.pool.add.called)
self.maxDiff = None
self.assertItemsEqual(phase.pool.queue_put.mock_calls,
[mock.call((compose,
{'ks_file': 'test.ks',
'build_arch': 'amd64',
'dest_dir': self.topdir + '/compose/Client/amd64/iso',
'scratch': False,
'repos': [self.topdir + '/compose/Client/amd64/os',
'http://example.com/repo/',
self.topdir + '/compose/Everything/amd64/os'],
'label': '',
'name': None,
'filename': 'image-name',
'version': None,
'specfile': None,
'sign': False,
'type': 'live',
'release': '20151203.0',
'ksurl': None},
compose.variants['Client'],
'amd64'))])
self.assertItemsEqual(
compose.get_image_name.mock_calls,
[mock.call('amd64', compose.variants['Client'], disc_num=None, disc_type='Live',
format='%(compose_id)s-%(variant)s-%(arch)s-%(disc_type)s%(disc_num)s%(suffix)s')])
class TestCreateLiveImageThread(PungiTestCase): class TestCreateLiveImageThread(PungiTestCase):