[buildinstall] Hardlink boot isos

Instead of creating a symlink, try to hardlink the image, and copy it if
hardlinking fails.

Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2016-02-26 10:31:43 +01:00
parent ab30fe0cef
commit 636ac79186
3 changed files with 85 additions and 9 deletions

View File

@ -24,11 +24,12 @@ import shutil
import re
from kobo.threads import ThreadPool, WorkerThread
from kobo.shortcuts import run, relative_path
from kobo.shortcuts import run
from productmd.images import Image
from pungi.arch import get_valid_arches
from pungi.util import get_buildroot_rpms, get_volid, get_arch_variant_data
from pungi.util import get_file_size, get_mtime
from pungi.wrappers.lorax import LoraxWrapper
from pungi.wrappers.kojiwrapper import KojiWrapper
from pungi.wrappers.iso import IsoWrapper
@ -72,6 +73,11 @@ class BuildinstallPhase(PhaseBase):
"expected_types": [str],
"optional": True,
},
{
"name": "buildinstall_symlink",
"expected_types": [bool],
"optional": True,
},
)
def __init__(self, compose):
@ -332,9 +338,11 @@ def symlink_boot_iso(compose, arch, variant):
return
compose.log_info("[BEGIN] %s" % msg)
# can't make a hardlink - possible cross-device link due to 'symlink_to' argument
symlink_target = relative_path(boot_iso_path, new_boot_iso_path)
os.symlink(symlink_target, new_boot_iso_path)
# Try to hardlink, and copy if that fails
try:
os.link(boot_iso_path, new_boot_iso_path)
except OSError:
shutil.copy2(boot_iso_path, new_boot_iso_path)
iso = IsoWrapper()
implant_md5 = iso.get_implanted_md5(new_boot_iso_path)
@ -345,10 +353,9 @@ def symlink_boot_iso(compose, arch, variant):
run(iso.get_manifest_cmd(iso_name), workdir=iso_dir)
img = Image(compose.im)
img.implant_md5 = iso.get_implanted_md5(new_boot_iso_path)
img.path = new_boot_iso_relative_path
img.mtime = int(os.stat(new_boot_iso_path).st_mtime)
img.size = os.path.getsize(new_boot_iso_path)
img.mtime = get_mtime(new_boot_iso_path)
img.size = get_file_size(new_boot_iso_path)
img.arch = arch
img.type = "boot"
img.format = "iso"

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import mock
import os
import unittest
import tempfile
import shutil
@ -43,6 +44,7 @@ class DummyCompose(object):
'Everything': mock.Mock(uid='Everything', arches=['x86_64', 'amd64'],
type='variant', is_empty=False),
}
self.log_info = mock.Mock()
self.log_error = mock.Mock()
self.log_debug = mock.Mock()
self.get_image_name = mock.Mock(return_value='image-name')
@ -61,3 +63,14 @@ class DummyCompose(object):
for variant in self.variants.itervalues():
result |= set(variant.arches)
return result
def touch(path):
"""Helper utility that creates an dummy file in given location. Directories
will be created."""
try:
os.makedirs(os.path.dirname(path))
except OSError:
pass
with open(path, 'w') as f:
f.write(path + '\n')

View File

@ -10,8 +10,8 @@ import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from pungi.phases.buildinstall import BuildinstallPhase, BuildinstallThread
from tests.helpers import DummyCompose, PungiTestCase
from pungi.phases.buildinstall import BuildinstallPhase, BuildinstallThread, symlink_boot_iso
from tests.helpers import DummyCompose, PungiTestCase, touch
class BuildInstallCompose(DummyCompose):
@ -534,5 +534,61 @@ class BuildinstallThreadTestCase(PungiTestCase):
])
class TestSymlinkIso(PungiTestCase):
def setUp(self):
super(TestSymlinkIso, self).setUp()
self.compose = BuildInstallCompose(self.topdir, {})
os_tree = self.compose.paths.compose.os_tree('x86_64', self.compose.variants['Server'])
self.boot_iso_path = os.path.join(os_tree, "images", "boot.iso")
touch(self.boot_iso_path)
@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(self, run, IsoWrapperCls, get_file_size, get_mtime, ImageCls):
self.compose.conf = {'buildinstall_symlink': False}
IsoWrapper = IsoWrapperCls.return_value
get_file_size.return_value = 1024
get_mtime.return_value = 13579
symlink_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='boot', 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__":
unittest.main()