Installing the same image to different storage disks on the same machine creates device conflicts with unexpected side effects. This commit adds a validation based on the PTUUID of the disk image to check if another device on the system has the same ID and if yes, does not allow to install the image again including a message which device takes the same identifier. This references bsc#1228741
451 lines
17 KiB
Python
451 lines
17 KiB
Python
from unittest.mock import (
|
|
MagicMock, patch, call, mock_open, ANY, Mock
|
|
)
|
|
from pytest import raises
|
|
import unittest.mock as mock
|
|
import kiwi.builder.install
|
|
|
|
from collections import namedtuple
|
|
|
|
from kiwi.bootloader.config.grub2 import BootLoaderConfigGrub2
|
|
from kiwi.defaults import Defaults
|
|
from kiwi.builder.install import InstallImageBuilder
|
|
from kiwi.exceptions import KiwiInstallBootImageError
|
|
|
|
|
|
class TestInstallImageBuilder:
|
|
def setup(self):
|
|
Defaults.set_platform_name('x86_64')
|
|
boot_names_type = namedtuple(
|
|
'boot_names_type', ['kernel_name', 'initrd_name']
|
|
)
|
|
self.setup = mock.Mock()
|
|
kiwi.builder.install.SystemSetup = mock.Mock(
|
|
return_value=self.setup
|
|
)
|
|
self.firmware = mock.Mock()
|
|
self.firmware.efi_mode = mock.Mock(
|
|
return_value='uefi'
|
|
)
|
|
kiwi.builder.install.FirmWare = mock.Mock(
|
|
return_value=self.firmware
|
|
)
|
|
self.mbrid = mock.Mock()
|
|
self.mbrid.get_id = mock.Mock(
|
|
return_value='0xffffffff'
|
|
)
|
|
kiwi.builder.install.SystemIdentifier = mock.Mock(
|
|
return_value=self.mbrid
|
|
)
|
|
kiwi.builder.install.Path = mock.Mock()
|
|
|
|
create_boot_loader_config_mock = mock.Mock(return_value=MagicMock())
|
|
create_boot_loader_config_mock.return_value.__enter__.return_value = mock.Mock()
|
|
kiwi.builder.install.create_boot_loader_config = create_boot_loader_config_mock
|
|
|
|
self.checksum = mock.Mock()
|
|
kiwi.builder.install.Checksum = mock.Mock(
|
|
return_value=self.checksum
|
|
)
|
|
self.kernel = mock.Mock()
|
|
self.kernel.get_kernel = mock.Mock()
|
|
self.kernel.get_xen_hypervisor = mock.Mock()
|
|
self.kernel.copy_kernel = mock.Mock()
|
|
self.kernel.copy_xen_hypervisor = mock.Mock()
|
|
kiwi.builder.install.Kernel = mock.Mock(
|
|
return_value=self.kernel
|
|
)
|
|
self.xml_state = mock.Mock()
|
|
self.xml_state.get_initrd_system = mock.Mock(
|
|
return_value='kiwi'
|
|
)
|
|
self.xml_state.xml_data.get_name = mock.Mock(
|
|
return_value='result-image'
|
|
)
|
|
self.xml_state.get_image_version = mock.Mock(
|
|
return_value='1.2.3'
|
|
)
|
|
self.xml_state.build_type.get_kernelcmdline = mock.Mock(
|
|
return_value='custom_kernel_options'
|
|
)
|
|
self.xml_state.get_oemconfig_oem_multipath_scan = mock.Mock(
|
|
return_value=False
|
|
)
|
|
self.xml_state.get_installmedia_initrd_modules = mock.Mock(
|
|
return_value=['module1', 'module2']
|
|
)
|
|
self.boot_image_task = mock.Mock()
|
|
self.boot_image_task.boot_root_directory = 'initrd_dir'
|
|
self.boot_image_task.initrd_filename = 'initrd'
|
|
self.boot_image_task.get_boot_names = mock.Mock(
|
|
return_value=boot_names_type(
|
|
kernel_name='kernel_name',
|
|
initrd_name='initrd-kernel_version'
|
|
)
|
|
)
|
|
|
|
self.install_image = InstallImageBuilder(
|
|
self.xml_state, 'root_dir', 'target_dir', self.boot_image_task
|
|
)
|
|
|
|
def setup_method(self, cls):
|
|
self.setup()
|
|
|
|
@patch('kiwi.builder.install.BootImage')
|
|
def test_init_dracut_based(self, mock_boot_image):
|
|
InstallImageBuilder(
|
|
self.xml_state, 'root_dir', 'target_dir', None
|
|
)
|
|
mock_boot_image.new.assert_called_once_with(
|
|
ANY, 'target_dir', 'root_dir'
|
|
)
|
|
|
|
def test_setup_ix86(self):
|
|
Defaults.set_platform_name('i686')
|
|
xml_state = mock.Mock()
|
|
xml_state.xml_data.get_name = mock.Mock(
|
|
return_value='result-image'
|
|
)
|
|
xml_state.get_image_version = mock.Mock(
|
|
return_value='1.2.3'
|
|
)
|
|
xml_state.build_type.get_kernelcmdline = mock.Mock(
|
|
return_value='custom_kernel_options'
|
|
)
|
|
xml_state.get_build_type_oemconfig_section = mock.Mock(
|
|
return_value=None
|
|
)
|
|
install_image = InstallImageBuilder(
|
|
xml_state, 'root_dir', 'target_dir', mock.Mock()
|
|
)
|
|
assert install_image.arch == 'ix86'
|
|
|
|
@patch('kiwi.builder.install.FileSystemIsoFs')
|
|
@patch('kiwi.builder.install.FileSystemSquashFs')
|
|
@patch('kiwi.builder.install.DeviceProvider')
|
|
@patch('kiwi.builder.install.create_boot_loader_config')
|
|
@patch('kiwi.builder.install.IsoToolsBase.setup_media_loader_directory')
|
|
@patch('kiwi.builder.install.shutil.copy')
|
|
@patch('kiwi.builder.install.Temporary')
|
|
@patch('kiwi.builder.install.Command.run')
|
|
@patch('kiwi.builder.install.Defaults.get_grub_boot_directory_name')
|
|
@patch('kiwi.builder.install.BlockID.get_ptuuid')
|
|
def test_create_install_iso(
|
|
self, mock_get_ptuuid, mock_grub_dir, mock_command, mock_Temporary,
|
|
mock_copy, mock_setup_media_loader_directory,
|
|
mock_create_boot_loader_config, mock_DeviceProvider,
|
|
mock_FileSystemSquashFs, mock_FileSystemIsoFs
|
|
):
|
|
mock_get_ptuuid.return_value = 'some_PTUUID'
|
|
|
|
temp_squashfs = Mock()
|
|
temp_squashfs.new_dir.return_value.name = 'temp-squashfs'
|
|
|
|
temp_media_dir = Mock()
|
|
temp_media_dir.new_dir.return_value.name = 'temp_media_dir'
|
|
|
|
temp_esp_file = Mock()
|
|
temp_esp_file.new_file.return_value.name = 'temp_esp'
|
|
|
|
tmp_names = [temp_esp_file, temp_squashfs, temp_media_dir]
|
|
|
|
iso_image = mock_FileSystemIsoFs.return_value.__enter__.return_value
|
|
iso_image.create_on_file.return_value = 42
|
|
|
|
def side_effect(prefix, path):
|
|
return tmp_names.pop()
|
|
|
|
bootloader_config = mock.MagicMock(spec=BootLoaderConfigGrub2)
|
|
mock_create_boot_loader_config.return_value.__enter__.return_value = bootloader_config
|
|
mock_Temporary.side_effect = side_effect
|
|
|
|
self.firmware.bios_mode.return_value = False
|
|
|
|
m_open = mock_open()
|
|
with patch('builtins.open', m_open, create=True):
|
|
self.install_image.create_install_iso()
|
|
|
|
self.setup.import_cdroot_files.assert_called_once_with('temp_media_dir')
|
|
|
|
self.checksum.sha256.assert_called_once_with(
|
|
'temp-squashfs/result-image.sha256'
|
|
)
|
|
mock_copy.assert_called_once_with(
|
|
'root_dir/boot/initrd-kernel_version',
|
|
'temp_media_dir/initrd.system_image'
|
|
)
|
|
assert m_open.call_args_list == [
|
|
call('temp_media_dir/config.isoclient', 'w'),
|
|
call('initrd_dir/config.vmxsystem', 'w')
|
|
]
|
|
assert m_open.return_value.write.call_args_list == [
|
|
call('IMAGE="result-image.raw"\n'),
|
|
call('IMAGE="result-image.raw"\n')
|
|
]
|
|
kiwi.builder.install.FileSystemSquashFs.assert_called_once_with(
|
|
custom_args={'compression': mock.ANY},
|
|
device_provider=mock_DeviceProvider.return_value,
|
|
root_dir='temp-squashfs'
|
|
)
|
|
squashed_image = mock_FileSystemSquashFs \
|
|
.return_value.__enter__.return_value
|
|
squashed_image.create_on_file.assert_called_once_with(
|
|
'target_dir/result-image.raw.squashfs'
|
|
)
|
|
mock_create_boot_loader_config.assert_called_once_with(
|
|
name='grub2', xml_state=self.xml_state, root_dir='root_dir',
|
|
boot_dir='temp_media_dir', custom_args={
|
|
'grub_directory_name': mock_grub_dir.return_value,
|
|
'grub_load_command': 'configfile'
|
|
}
|
|
)
|
|
bootloader_config.setup_install_boot_images.assert_called_once_with(
|
|
lookup_path='initrd_dir', mbrid=self.mbrid
|
|
)
|
|
mock_setup_media_loader_directory.assert_called_once_with(
|
|
'initrd_dir', 'temp_media_dir',
|
|
bootloader_config.get_boot_theme.return_value
|
|
)
|
|
bootloader_config.write_meta_data.assert_called_once_with()
|
|
bootloader_config.setup_install_image_config.assert_called_once_with(
|
|
mbrid=self.mbrid
|
|
)
|
|
bootloader_config.write.assert_called_once_with()
|
|
bootloader_config._create_embedded_fat_efi_image.assert_called_once_with(
|
|
'temp_esp'
|
|
)
|
|
self.boot_image_task.create_initrd.assert_called_once_with(
|
|
self.mbrid, 'initrd_kiwi_install', install_initrd=True
|
|
)
|
|
self.boot_image_task.cleanup.assert_called_once_with()
|
|
self.kernel.copy_kernel.assert_called_once_with(
|
|
'temp_media_dir/boot/x86_64/loader', '/linux'
|
|
)
|
|
self.kernel.copy_xen_hypervisor.assert_called_once_with(
|
|
'temp_media_dir/boot/x86_64/loader', '/xen.gz'
|
|
)
|
|
assert mock_command.call_args_list == [
|
|
call([
|
|
'cp', '-l',
|
|
'target_dir/result-image.x86_64-1.2.3.raw',
|
|
'temp-squashfs/result-image.raw'
|
|
]),
|
|
call([
|
|
'mv', 'target_dir/result-image.raw.squashfs', 'temp_media_dir'
|
|
]),
|
|
call([
|
|
'mv', 'initrd', 'temp_media_dir/boot/x86_64/loader/initrd'
|
|
])
|
|
]
|
|
iso_image.create_on_file.assert_called_once_with(
|
|
'target_dir/result-image.x86_64-1.2.3.install.iso'
|
|
)
|
|
|
|
tmp_names = [temp_esp_file, temp_squashfs, temp_media_dir]
|
|
self.install_image.initrd_system = 'dracut'
|
|
|
|
m_open.reset_mock()
|
|
with patch('builtins.open', m_open, create=True):
|
|
self.install_image.create_install_iso()
|
|
|
|
self.boot_image_task.include_module.assert_any_call('kiwi-dump')
|
|
self.boot_image_task.include_module.assert_any_call('kiwi-dump-reboot')
|
|
assert self.boot_image_task.omit_module.call_args_list == [
|
|
call('multipath'), call('module1'), call('module2')
|
|
]
|
|
self.boot_image_task.set_static_modules.assert_called_once_with(
|
|
['module1', 'module2']
|
|
)
|
|
|
|
assert self.boot_image_task.include_file.call_args_list == [
|
|
call('/config.bootoptions'),
|
|
call('/system_identifier')
|
|
]
|
|
assert m_open.call_args_list == [
|
|
call('temp_media_dir/config.isoclient', 'w'),
|
|
call('initrd_dir/system_identifier', 'w')
|
|
]
|
|
assert m_open.return_value.write.call_args_list == [
|
|
call('IMAGE="result-image.raw"\n'),
|
|
call('some_PTUUID')
|
|
]
|
|
|
|
@patch('kiwi.builder.disk.create_boot_loader_config')
|
|
@patch('kiwi.builder.install.IsoToolsBase.setup_media_loader_directory')
|
|
@patch('kiwi.builder.install.Temporary')
|
|
@patch('kiwi.builder.install.Command.run')
|
|
def test_create_install_iso_no_kernel_found(
|
|
self, mock_command, mock_Temporary, mock_setup_media_loader_directory,
|
|
mock_create_boot_loader_config
|
|
):
|
|
self.firmware.bios_mode.return_value = False
|
|
self.kernel.get_kernel.return_value = False
|
|
with patch('builtins.open'):
|
|
with raises(KiwiInstallBootImageError):
|
|
self.install_image.create_install_iso()
|
|
|
|
@patch('kiwi.builder.disk.create_boot_loader_config')
|
|
@patch('kiwi.builder.install.IsoToolsBase.setup_media_loader_directory')
|
|
@patch('kiwi.builder.install.Temporary')
|
|
@patch('kiwi.builder.install.Command.run')
|
|
def test_create_install_iso_no_hypervisor_found(
|
|
self, mock_command, mock_Temporary, mock_setup_media_loader_directory,
|
|
mock_create_boot_loader_config
|
|
):
|
|
self.firmware.bios_mode.return_value = False
|
|
self.kernel.get_xen_hypervisor.return_value = False
|
|
with patch('builtins.open'):
|
|
with raises(KiwiInstallBootImageError):
|
|
self.install_image.create_install_iso()
|
|
|
|
@patch('kiwi.builder.install.Temporary')
|
|
@patch('kiwi.builder.install.Command.run')
|
|
@patch('kiwi.builder.install.Checksum')
|
|
@patch('kiwi.builder.install.Compress')
|
|
def test_create_install_pxe_no_kernel_found(
|
|
self, mock_compress, mock_sha256, mock_command, mock_Temporary
|
|
):
|
|
self.firmware.bios_mode.return_value = False
|
|
mock_Temporary.return_value.new_dir.return_value.name = 'tmpdir'
|
|
self.kernel.get_kernel.return_value = False
|
|
with patch('builtins.open'):
|
|
with raises(KiwiInstallBootImageError):
|
|
self.install_image.create_install_pxe_archive()
|
|
|
|
@patch('kiwi.builder.install.Temporary')
|
|
@patch('kiwi.builder.install.Command.run')
|
|
@patch('kiwi.builder.install.Checksum')
|
|
@patch('kiwi.builder.install.Compress')
|
|
@patch('kiwi.builder.install.os.symlink')
|
|
def test_create_install_pxe_no_hypervisor_found(
|
|
self, mock_symlink, mock_compress, mock_sha256, mock_command,
|
|
mock_Temporary
|
|
):
|
|
self.firmware.bios_mode.return_value = False
|
|
mock_Temporary.return_value.new_dir.return_value.name = 'tmpdir'
|
|
self.kernel.get_xen_hypervisor.return_value = False
|
|
with patch('builtins.open'):
|
|
with raises(KiwiInstallBootImageError):
|
|
self.install_image.create_install_pxe_archive()
|
|
|
|
@patch('kiwi.builder.install.Temporary')
|
|
@patch('kiwi.builder.install.Command.run')
|
|
@patch('kiwi.builder.install.ArchiveTar')
|
|
@patch('kiwi.builder.install.Checksum')
|
|
@patch('kiwi.builder.install.Compress')
|
|
@patch('kiwi.builder.install.shutil.copy')
|
|
@patch('kiwi.builder.install.os.symlink')
|
|
@patch('kiwi.builder.install.os.chmod')
|
|
def test_create_install_pxe_archive(
|
|
self, mock_chmod, mock_symlink, mock_copy, mock_compress,
|
|
mock_sha256, mock_archive, mock_command, mock_Temporary
|
|
):
|
|
mock_Temporary.return_value.new_dir.return_value.name = 'tmpdir'
|
|
|
|
archive = mock.Mock()
|
|
mock_archive.return_value = archive
|
|
|
|
checksum = mock.Mock()
|
|
mock_sha256.return_value = checksum
|
|
|
|
compress = mock.Mock()
|
|
src = 'target_dir/result-image.x86_64-1.2.3.raw'
|
|
compress.xz.return_value = src
|
|
mock_compress.return_value = compress
|
|
|
|
m_open = mock_open()
|
|
with patch('builtins.open', m_open, create=True):
|
|
self.install_image.create_install_pxe_archive()
|
|
|
|
mock_compress.assert_called_once_with(
|
|
keep_source_on_compress=True, source_filename=src
|
|
)
|
|
compress.xz.assert_called_once_with(None)
|
|
assert mock_command.call_args_list[0] == call(
|
|
['mv', src, 'tmpdir/result-image.x86_64-1.2.3.xz']
|
|
)
|
|
mock_sha256.assert_called_once_with(
|
|
'target_dir/result-image.x86_64-1.2.3.raw'
|
|
)
|
|
checksum.sha256.assert_called_once_with(
|
|
'tmpdir/result-image.x86_64-1.2.3.sha256'
|
|
)
|
|
assert m_open.call_args_list == [
|
|
call('initrd_dir/config.vmxsystem', 'w'),
|
|
call('tmpdir/result-image.x86_64-1.2.3.append', 'w')
|
|
]
|
|
assert m_open.return_value.write.call_args_list == [
|
|
call('IMAGE="result-image.raw"\n'),
|
|
call('pxe=1 custom_kernel_options\n')
|
|
]
|
|
self.kernel.copy_kernel.assert_called_once_with(
|
|
'tmpdir', 'pxeboot.result-image.x86_64-1.2.3.kernel'
|
|
)
|
|
mock_symlink.assert_called_once_with(
|
|
'pxeboot.result-image.x86_64-1.2.3.kernel',
|
|
'tmpdir/result-image.x86_64-1.2.3.kernel'
|
|
)
|
|
self.kernel.copy_xen_hypervisor.assert_called_once_with(
|
|
'tmpdir', '/pxeboot.result-image.x86_64-1.2.3.xen.gz'
|
|
)
|
|
self.boot_image_task.create_initrd.assert_called_once_with(
|
|
self.mbrid, 'initrd_kiwi_install', install_initrd=True
|
|
)
|
|
self.boot_image_task.cleanup.assert_called_once_with()
|
|
assert mock_command.call_args_list[1] == call(
|
|
[
|
|
'mv', 'initrd',
|
|
'tmpdir/pxeboot.result-image.x86_64-1.2.3.initrd'
|
|
]
|
|
)
|
|
mock_chmod.assert_called_once_with(
|
|
'tmpdir/pxeboot.result-image.x86_64-1.2.3.initrd', 420
|
|
)
|
|
mock_archive.assert_called_once_with(
|
|
'target_dir/result-image.x86_64-1.2.3.install.tar'
|
|
)
|
|
archive.create.assert_called_once_with('tmpdir')
|
|
|
|
mock_chmod.reset_mock()
|
|
mock_copy.reset_mock()
|
|
self.install_image.initrd_system = 'dracut'
|
|
m_open.reset_mock()
|
|
with patch('builtins.open', m_open, create=True):
|
|
self.install_image.create_install_pxe_archive()
|
|
|
|
assert mock_copy.call_args_list == [
|
|
call(
|
|
'root_dir/boot/initrd-kernel_version',
|
|
'tmpdir/result-image.x86_64-1.2.3.initrd'
|
|
),
|
|
call(
|
|
'root_dir/config.bootoptions',
|
|
'tmpdir/result-image.x86_64-1.2.3.config.bootoptions'
|
|
)
|
|
]
|
|
assert mock_chmod.call_args_list == [
|
|
call('tmpdir/result-image.x86_64-1.2.3.initrd', 420),
|
|
call('tmpdir/pxeboot.result-image.x86_64-1.2.3.initrd', 420)
|
|
]
|
|
assert m_open.call_args_list == [
|
|
call('tmpdir/result-image.x86_64-1.2.3.append', 'w'),
|
|
]
|
|
assert m_open.return_value.write.call_args_list == [
|
|
call(
|
|
' '.join([
|
|
'rd.kiwi.install.pxe',
|
|
'rd.kiwi.install.image=http://example.com/image.xz',
|
|
'custom_kernel_options\n'
|
|
])
|
|
)
|
|
]
|
|
|
|
self.boot_image_task.include_module.assert_any_call('kiwi-dump')
|
|
self.boot_image_task.include_module.assert_any_call('kiwi-dump-reboot')
|
|
assert self.boot_image_task.omit_module.call_args_list == [
|
|
call('multipath'), call('module1'), call('module2')
|
|
]
|
|
self.boot_image_task.set_static_modules.assert_called_once_with(
|
|
['module1', 'module2']
|
|
)
|