diff --git a/doc/configuration.rst b/doc/configuration.rst index 2c700e74..feeadeea 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -646,6 +646,9 @@ Live Images Settings * ``specfile`` (*str*) -- for images wrapped in RPM * ``scratch`` (*bool*) -- only RPM-wrapped images can use scratch builds, but by default this is turned off + * ``type`` (*str*) -- what kind of task to start in Koji. Defaults to + ``live`` meaning ``koji spin-livecd`` will be used. Alternative option + is ``appliance`` corresponding to ``koji spin-appliance``. Live Media Settings =================== diff --git a/pungi/phases/live_images.py b/pungi/phases/live_images.py index ab96ab76..8f64acef 100644 --- a/pungi/phases/live_images.py +++ b/pungi/phases/live_images.py @@ -119,6 +119,8 @@ class LiveImagesPhase(PhaseBase): cmd["name"] = data[0].get("name", None) cmd["version"] = data[0].get("version", None) + cmd['type'] = data[0].get('type', 'live') + # Specfile (for images wrapped in rpm) cmd["specfile"] = data[0].get("specfile", None) @@ -195,7 +197,14 @@ class CreateLiveImageThread(WorkerThread): # Non scratch build are allowed only for rpm wrapped images archive = True target = compose.conf.get("live_target", "rhel-7.0-candidate") # compatability for hardcoded target - koji_cmd = koji_wrapper.get_create_image_cmd(name, version, target, cmd["build_arch"], cmd["ks_file"], cmd["repos"], image_type="live", wait=True, archive=archive, specfile=cmd["specfile"]) + koji_cmd = koji_wrapper.get_create_image_cmd(name, version, target, + cmd["build_arch"], + cmd["ks_file"], + cmd["repos"], + image_type=cmd['type'], + wait=True, + archive=archive, + specfile=cmd["specfile"]) # avoid race conditions? # Kerberos authentication failed: Permission denied in replay cache code (-1765328215) diff --git a/tests/test_liveimagesphase.py b/tests/test_liveimagesphase.py index ead447c1..0392ab8d 100755 --- a/tests/test_liveimagesphase.py +++ b/tests/test_liveimagesphase.py @@ -63,7 +63,7 @@ class TestLiveImagesPhase(unittest.TestCase): @mock.patch('pungi.phases.live_images.ThreadPool') @mock.patch('pungi.phases.live_images.get_ks_in') @mock.patch('pungi.phases.live_images.tweak_ks') - def test_image_build(self, tweak_ks, get_ks_in, ThreadPool): + def test_live_image_build(self, tweak_ks, get_ks_in, ThreadPool): compose = _DummyCompose({ 'live_images': [ ('^Client$', { @@ -99,7 +99,53 @@ class TestLiveImagesPhase(unittest.TestCase): 'name': None, 'iso_path': '/iso_dir/amd64/Client/image-name', 'version': None, - 'specfile': None}, + 'specfile': None, + 'type': 'live'}, + compose.variants['Client'], + 'amd64'))]) + + @mock.patch('pungi.phases.live_images.ThreadPool') + @mock.patch('pungi.phases.live_images.get_ks_in') + @mock.patch('pungi.phases.live_images.tweak_ks') + def test_spin_appliance(self, tweak_ks, get_ks_in, ThreadPool): + compose = _DummyCompose({ + 'live_images': [ + ('^Client$', { + 'amd64': { + 'additional_repos': ['http://example.com/repo/'], + 'repos_from': ['Everything'], + 'type': 'appliance', + } + }) + ], + }) + + 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.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': '/path/to/ks_file', + 'build_arch': 'amd64', + 'wrapped_rpms_path': '/iso_dir/amd64/Client', + 'scratch': False, + 'repos': ['/repo/amd64/Client', + 'http://example.com/repo/', + '/repo/amd64/Everything'], + 'label': '', + 'name': None, + 'iso_path': '/iso_dir/amd64/Client/image-name', + 'version': None, + 'specfile': None, + 'type': 'appliance'}, compose.variants['Client'], 'amd64'))]) @@ -124,7 +170,8 @@ class TestCreateLiveImageThread(unittest.TestCase): 'name': None, 'iso_path': '/iso_dir/amd64/Client/image-name', 'version': None, - 'specfile': None + 'specfile': None, + 'type': 'live', } koji_wrapper = KojiWrapper.return_value @@ -151,6 +198,73 @@ class TestCreateLiveImageThread(unittest.TestCase): 'isoinfo -R -f -i image-name | grep -v \'/TRANS.TBL$\' | sort >> image-name.manifest' ]) self.assertEqual(run.mock_calls, [mock.call(write_manifest_cmd)]) + self.assertEqual(koji_wrapper.get_create_image_cmd.mock_calls, + [mock.call('Test', '20151203.0.t', 'rhel-7.0-candidate', + 'amd64', '/path/to/ks_file', + ['/repo/amd64/Client', + 'http://example.com/repo/', + '/repo/amd64/Everything'], + image_type='live', + archive=False, + specfile=None, + wait=True)]) + + @mock.patch('shutil.copy2') + @mock.patch('pungi.phases.live_images.run') + @mock.patch('pungi.phases.live_images.KojiWrapper') + def test_process_applicance(self, KojiWrapper, run, copy2): + compose = _DummyCompose({'koji_profile': 'koji'}) + pool = mock.Mock() + cmd = { + 'ks_file': '/path/to/ks_file', + 'build_arch': 'amd64', + 'wrapped_rpms_path': '/iso_dir/amd64/Client', + 'scratch': False, + 'repos': ['/repo/amd64/Client', + 'http://example.com/repo/', + '/repo/amd64/Everything'], + 'label': '', + 'name': None, + 'iso_path': '/iso_dir/amd64/Client/image-name', + 'version': None, + 'specfile': None, + 'type': 'appliance', + } + + koji_wrapper = KojiWrapper.return_value + koji_wrapper.get_create_image_cmd.return_value = 'koji spin-livecd ...' + koji_wrapper.run_blocking_cmd.return_value = { + 'retcode': 0, + 'output': 'some output', + 'task_id': 123 + } + koji_wrapper.get_image_path.return_value = ['/path/to/image'] + + t = CreateLiveImageThread(pool) + with mock.patch('time.sleep'): + t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1) + + self.assertEqual(koji_wrapper.run_blocking_cmd.mock_calls, + [mock.call('koji spin-livecd ...', log_file='/a/b/log/log_file')]) + self.assertEqual(koji_wrapper.get_image_path.mock_calls, [mock.call(123)]) + self.assertEqual(copy2.mock_calls, + [mock.call('/path/to/image', '/iso_dir/amd64/Client/image-name')]) + + write_manifest_cmd = ' && '.join([ + 'cd /iso_dir/amd64/Client', + 'isoinfo -R -f -i image-name | grep -v \'/TRANS.TBL$\' | sort >> image-name.manifest' + ]) + self.assertEqual(run.mock_calls, [mock.call(write_manifest_cmd)]) + self.assertEqual(koji_wrapper.get_create_image_cmd.mock_calls, + [mock.call('Test', '20151203.0.t', 'rhel-7.0-candidate', + 'amd64', '/path/to/ks_file', + ['/repo/amd64/Client', + 'http://example.com/repo/', + '/repo/amd64/Everything'], + image_type='appliance', + archive=False, + specfile=None, + wait=True)]) @mock.patch('shutil.copy2') @mock.patch('pungi.phases.live_images.run')