[live-images] Add images to manifest

The type is either "live" or "appliance", the format is set based on
filename extension.

Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2016-02-22 11:19:11 +01:00
parent f80c97e3ec
commit 7734ddf57e
2 changed files with 111 additions and 34 deletions

View File

@ -23,6 +23,7 @@ import shutil
from kobo.threads import ThreadPool, WorkerThread
from kobo.shortcuts import run, save_to_file
from productmd.images import Image
from pungi.wrappers.kojiwrapper import KojiWrapper
from pungi.wrappers.iso import IsoWrapper
@ -269,15 +270,40 @@ class CreateLiveImageThread(WorkerThread):
shutil.copy2(rpm_path, cmd["dest_dir"])
self._write_manifest(destination)
self._add_to_images(compose, variant, arch, cmd['type'], self._get_format(image_path), destination)
self.pool.log_info("[DONE ] %s" % msg)
def _add_to_images(self, compose, variant, arch, type, format, path):
"""Adds the image to images.json"""
img = Image(compose.im)
img.type = type
img.format = format
img.path = os.path.relpath(path, compose.paths.compose.topdir())
img.mtime = int(os.stat(path).st_mtime)
img.size = os.path.getsize(path)
img.arch = arch
img.disc_number = 1 # We don't expect multiple disks
img.disc_count = 1
img.bootable = True
compose.im.add(variant=variant.uid, arch=arch, image=img)
def _is_image(self, path):
for ext in ('.iso', '.raw.xz'):
if path.endswith(ext):
return True
return False
def _get_format(self, path):
"""Extract all extensions from the path."""
exts = []
while True:
path, ext = os.path.splitext(path)
if not ext:
break
exts.append(ext.lstrip('.'))
return '.'.join(reversed(exts))
def _write_manifest(self, iso_path):
"""Generate manifest for ISO at given path.

View File

@ -22,24 +22,20 @@ class _DummyCompose(object):
self.conf = config
self.paths = mock.Mock(
compose=mock.Mock(
topdir=mock.Mock(return_value='/top'),
repository=mock.Mock(
side_effect=lambda arch, variant, create_dir=False: os.path.join('/repo', arch, variant.uid)
),
iso_dir=mock.Mock(
side_effect=lambda arch, variant, symlink_to: os.path.join(
'/iso_dir', arch, variant.uid
'/top/iso_dir', arch, variant.uid
)
),
image_dir=mock.Mock(
side_effect=lambda variant, symlink_to: os.path.join(
'/image_dir/%(arch)s', variant.uid
'/top/image_dir/%(arch)s', variant.uid
)
),
iso_path=mock.Mock(
side_effect=lambda arch, variant, filename, symlink_to: os.path.join(
'/iso_dir', arch, variant.uid, filename
)
)
),
log=mock.Mock(
log_file=mock.Mock(return_value='/a/b/log/log_file')
@ -53,6 +49,7 @@ class _DummyCompose(object):
}
self.log_error = mock.Mock()
self.get_image_name = mock.Mock(return_value='image-name')
self.im = mock.Mock()
def get_arches(self):
return ['x86_64', 'amd64']
@ -93,7 +90,7 @@ class TestLiveImagesPhase(unittest.TestCase):
[mock.call((compose,
{'ks_file': 'test.ks',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -137,7 +134,7 @@ class TestLiveImagesPhase(unittest.TestCase):
[mock.call((compose,
{'ks_file': 'test.ks',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -183,7 +180,7 @@ class TestLiveImagesPhase(unittest.TestCase):
[mock.call((compose,
{'ks_file': 'test.ks',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -202,7 +199,7 @@ class TestLiveImagesPhase(unittest.TestCase):
mock.call((compose,
{'ks_file': 'another.ks',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -249,7 +246,7 @@ class TestLiveImagesPhase(unittest.TestCase):
[mock.call((compose,
{'ks_file': 'test.ks',
'build_arch': 'amd64',
'dest_dir': '/image_dir/amd64/Client',
'dest_dir': '/top/image_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -271,16 +268,17 @@ class TestLiveImagesPhase(unittest.TestCase):
class TestCreateLiveImageThread(unittest.TestCase):
@mock.patch('pungi.phases.live_images.Image')
@mock.patch('shutil.copy2')
@mock.patch('pungi.phases.live_images.run')
@mock.patch('pungi.phases.live_images.KojiWrapper')
def test_process(self, KojiWrapper, run, copy2):
def test_process(self, KojiWrapper, run, copy2, Image):
compose = _DummyCompose({'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
'ks_file': '/path/to/ks_file',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -305,17 +303,21 @@ class TestCreateLiveImageThread(unittest.TestCase):
koji_wrapper.get_image_path.return_value = ['/path/to/image.iso']
t = CreateLiveImageThread(pool)
with mock.patch('time.sleep'):
t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1)
with mock.patch('os.stat') as stat:
with mock.patch('os.path.getsize') as getsize:
with mock.patch('time.sleep'):
getsize.return_value = 1024
stat.return_value.st_mtime = 13579
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', '/iso_dir/amd64/Client/image-name')])
[mock.call('/path/to/image.iso', '/top/iso_dir/amd64/Client/image-name')])
write_manifest_cmd = ' && '.join([
'cd /iso_dir/amd64/Client',
'cd /top/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)])
@ -331,17 +333,29 @@ class TestCreateLiveImageThread(unittest.TestCase):
wait=True,
release=None,
ksurl='https://git.example.com/kickstarts.git?#CAFEBABE')])
self.assertEqual(Image.return_value.type, 'live')
self.assertEqual(Image.return_value.format, 'iso')
self.assertEqual(Image.return_value.path, 'iso_dir/amd64/Client/image-name')
self.assertEqual(Image.return_value.size, 1024)
self.assertEqual(Image.return_value.mtime, 13579)
self.assertEqual(Image.return_value.arch, 'amd64')
self.assertEqual(Image.return_value.disc_number, 1)
self.assertEqual(Image.return_value.disc_count, 1)
self.assertTrue(Image.return_value.bootable)
self.assertEqual(compose.im.add.mock_calls,
[mock.call(variant='Client', arch='amd64', image=Image.return_value)])
@mock.patch('pungi.phases.live_images.Image')
@mock.patch('shutil.copy2')
@mock.patch('pungi.phases.live_images.run')
@mock.patch('pungi.phases.live_images.KojiWrapper')
def test_process_no_rename(self, KojiWrapper, run, copy2):
def test_process_no_rename(self, KojiWrapper, run, copy2, Image):
compose = _DummyCompose({'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
'ks_file': '/path/to/ks_file',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -366,17 +380,25 @@ class TestCreateLiveImageThread(unittest.TestCase):
koji_wrapper.get_image_path.return_value = ['/path/to/image.iso']
t = CreateLiveImageThread(pool)
with mock.patch('time.sleep'):
t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1)
with mock.patch('os.stat') as stat:
with mock.patch('os.path.getsize') as getsize:
getsize.return_value = 1024
getsize.return_value = 1024
getsize.return_value = 1024
getsize.return_value = 1024
with mock.patch('time.sleep'):
getsize.return_value = 1024
stat.return_value.st_mtime = 13579
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', '/iso_dir/amd64/Client/image.iso')])
[mock.call('/path/to/image.iso', '/top/iso_dir/amd64/Client/image.iso')])
write_manifest_cmd = ' && '.join([
'cd /iso_dir/amd64/Client',
'cd /top/iso_dir/amd64/Client',
'isoinfo -R -f -i image.iso | grep -v \'/TRANS.TBL$\' | sort >> image.iso.manifest'
])
self.assertEqual(run.mock_calls, [mock.call(write_manifest_cmd)])
@ -393,16 +415,29 @@ class TestCreateLiveImageThread(unittest.TestCase):
release=None,
ksurl='https://git.example.com/kickstarts.git?#CAFEBABE')])
self.assertEqual(Image.return_value.type, 'live')
self.assertEqual(Image.return_value.format, 'iso')
self.assertEqual(Image.return_value.path, 'iso_dir/amd64/Client/image.iso')
self.assertEqual(Image.return_value.size, 1024)
self.assertEqual(Image.return_value.mtime, 13579)
self.assertEqual(Image.return_value.arch, 'amd64')
self.assertEqual(Image.return_value.disc_number, 1)
self.assertEqual(Image.return_value.disc_count, 1)
self.assertTrue(Image.return_value.bootable)
self.assertEqual(compose.im.add.mock_calls,
[mock.call(variant='Client', arch='amd64', image=Image.return_value)])
@mock.patch('pungi.phases.live_images.Image')
@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):
def test_process_applicance(self, KojiWrapper, run, copy2, Image):
compose = _DummyCompose({'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
'ks_file': '/path/to/ks_file',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -424,20 +459,24 @@ class TestCreateLiveImageThread(unittest.TestCase):
'output': 'some output',
'task_id': 123
}
koji_wrapper.get_image_path.return_value = ['/path/to/image.iso']
koji_wrapper.get_image_path.return_value = ['/path/to/image.raw.xz']
t = CreateLiveImageThread(pool)
with mock.patch('time.sleep'):
t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1)
with mock.patch('os.stat') as stat:
with mock.patch('os.path.getsize') as getsize:
with mock.patch('time.sleep'):
getsize.return_value = 1024
stat.return_value.st_mtime = 13579
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', '/iso_dir/amd64/Client/image-name')])
[mock.call('/path/to/image.raw.xz', '/top/iso_dir/amd64/Client/image-name')])
write_manifest_cmd = ' && '.join([
'cd /iso_dir/amd64/Client',
'cd /top/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)])
@ -454,6 +493,18 @@ class TestCreateLiveImageThread(unittest.TestCase):
release=None,
ksurl=None)])
self.assertEqual(Image.return_value.type, 'appliance')
self.assertEqual(Image.return_value.format, 'raw.xz')
self.assertEqual(Image.return_value.path, 'iso_dir/amd64/Client/image-name')
self.assertEqual(Image.return_value.size, 1024)
self.assertEqual(Image.return_value.mtime, 13579)
self.assertEqual(Image.return_value.arch, 'amd64')
self.assertEqual(Image.return_value.disc_number, 1)
self.assertEqual(Image.return_value.disc_count, 1)
self.assertTrue(Image.return_value.bootable)
self.assertEqual(compose.im.add.mock_calls,
[mock.call(variant='Client', arch='amd64', image=Image.return_value)])
@mock.patch('shutil.copy2')
@mock.patch('pungi.phases.live_images.run')
@mock.patch('pungi.phases.live_images.KojiWrapper')
@ -466,7 +517,7 @@ class TestCreateLiveImageThread(unittest.TestCase):
cmd = {
'ks_file': '/path/to/ks_file',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/iso_dir/amd64/Client',
'scratch': False,
'repos': ['/repo/amd64/Client',
'http://example.com/repo/',
@ -503,14 +554,14 @@ class TestCreateLiveImageThread(unittest.TestCase):
cmd = {
'ks_file': '/path/to/ks_file',
'build_arch': 'amd64',
'dest_dir': '/iso_dir/amd64/Client',
'dest_dir': '/top/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',
'filename': 'image-name',
'version': None,
'specfile': None,
'ksurl': None,