The support for delta_root allows to build a delta container image from a given base container. Due to the refactoring of the kiwi code base using context managers no explicit deletion of instances happens anymore. This uncovered a weakness of the delta root code at the level of the overlay mount. At the time of the umount there are still active temporary mount handlers which keeps the mountpoint busy. In order to fix this properly also the PackageManager factory is now a context manager and the Repository factory received a cleanup method which is called when the PackageManager goes out of scope. This refactoring also fixes the busy state when building deltas
405 lines
16 KiB
Python
405 lines
16 KiB
Python
import logging
|
|
import sys
|
|
import os
|
|
from pytest import fixture
|
|
from unittest.mock import (
|
|
patch, call, Mock, MagicMock
|
|
)
|
|
|
|
import kiwi
|
|
|
|
from ..test_helper import argv_kiwi_tests
|
|
|
|
from kiwi.exceptions import KiwiCommandError
|
|
|
|
from kiwi.tasks.system_prepare import SystemPrepareTask
|
|
|
|
|
|
class TestSystemPrepareTask:
|
|
@fixture(autouse=True)
|
|
def inject_fixtures(self, caplog):
|
|
self._caplog = caplog
|
|
|
|
def setup(self):
|
|
sys.argv = [
|
|
sys.argv[0], '--profile', 'vmxFlavour', 'system', 'prepare',
|
|
'--description', '../data/description',
|
|
'--root', '../data/root-dir'
|
|
]
|
|
|
|
self.abs_root_dir = os.path.abspath('../data/root-dir')
|
|
|
|
self.command = Mock()
|
|
kiwi.tasks.system_prepare.Command = self.command
|
|
|
|
kiwi.tasks.system_prepare.Privileges = Mock()
|
|
|
|
self.runtime_checker = Mock()
|
|
kiwi.tasks.base.RuntimeChecker = Mock(
|
|
return_value=self.runtime_checker
|
|
)
|
|
|
|
self.setup = Mock()
|
|
kiwi.tasks.system_prepare.SystemSetup = Mock(
|
|
return_value=self.setup
|
|
)
|
|
|
|
self.profile = Mock()
|
|
self.profile.dot_profile = dict()
|
|
kiwi.tasks.system_prepare.Profile = Mock(
|
|
return_value=self.profile
|
|
)
|
|
|
|
kiwi.tasks.system_prepare.Help = Mock(
|
|
return_value=Mock()
|
|
)
|
|
self.task = SystemPrepareTask()
|
|
self.task.runtime_config = MagicMock()
|
|
|
|
def setup_method(self, cls):
|
|
self.setup()
|
|
|
|
def teardown(self):
|
|
sys.argv = argv_kiwi_tests
|
|
|
|
def teardown_method(self, cls):
|
|
self.teardown()
|
|
|
|
def _init_command_args(self):
|
|
self.task.command_args = {}
|
|
self.task.command_args['help'] = False
|
|
self.task.command_args['prepare'] = False
|
|
self.task.command_args['--description'] = '../data/description'
|
|
self.task.command_args['--root'] = '../data/root-dir'
|
|
self.task.command_args['--allow-existing-root'] = False
|
|
self.task.command_args['--set-repo'] = None
|
|
self.task.command_args['--set-repo-credentials'] = None
|
|
self.task.command_args['--add-repo'] = []
|
|
self.task.command_args['--add-repo-credentials'] = []
|
|
self.task.command_args['--add-package'] = []
|
|
self.task.command_args['--add-bootstrap-package'] = []
|
|
self.task.command_args['--delete-package'] = []
|
|
self.task.command_args['--ignore-repos'] = False
|
|
self.task.command_args['--ignore-repos-used-for-build'] = False
|
|
self.task.command_args['--clear-cache'] = False
|
|
self.task.command_args['--set-container-derived-from'] = None
|
|
self.task.command_args['--set-container-tag'] = None
|
|
self.task.command_args['--add-container-label'] = []
|
|
self.task.command_args['--signing-key'] = []
|
|
|
|
@patch('kiwi.xml_state.XMLState.get_repositories_signing_keys')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare(self, mock_SystemPrepare, mock_keys):
|
|
manager = MagicMock()
|
|
system_prepare = Mock()
|
|
system_prepare.setup_repositories = Mock(
|
|
return_value=manager
|
|
)
|
|
mock_SystemPrepare.return_value.__enter__.return_value = system_prepare
|
|
mock_keys.return_value = ['some_key', 'some_other_key']
|
|
self._init_command_args()
|
|
self.task.command_args['prepare'] = True
|
|
self.task.command_args['--clear-cache'] = True
|
|
self.task.process()
|
|
self.runtime_checker.\
|
|
check_boot_description_exists.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_initrd_selection_required.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_consistent_kernel_in_boot_and_system_image.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_container_tool_chain_installed.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_volume_setup_defines_multiple_fullsize_volumes.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_volume_setup_has_no_root_definition.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_volume_label_used_with_lvm.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_swap_name_used_with_lvm.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_xen_uniquely_setup_as_server_or_guest.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_target_directory_not_in_shared_cache.assert_called_once_with(
|
|
self.abs_root_dir
|
|
)
|
|
self.runtime_checker.\
|
|
check_mediacheck_installed.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_dracut_module_for_live_iso_in_package_list.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_repositories_configured.assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_dracut_module_for_disk_overlay_in_package_list.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_dracut_module_for_disk_oem_in_package_list.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_dracut_module_for_oem_install_in_package_list.\
|
|
assert_called_once_with()
|
|
self.runtime_checker.\
|
|
check_efi_mode_for_disk_overlay_correctly_setup.\
|
|
assert_called_once_with()
|
|
system_prepare.setup_repositories.assert_called_once_with(
|
|
True, ['some_key', 'some_other_key'], None
|
|
)
|
|
system_prepare.install_bootstrap.assert_called_once_with(
|
|
manager.__enter__.return_value, []
|
|
)
|
|
system_prepare.install_system.assert_called_once_with(
|
|
manager.__enter__.return_value
|
|
)
|
|
self.profile.create.assert_called_once_with(
|
|
self.abs_root_dir + '/.profile'
|
|
)
|
|
self.setup.import_description.assert_called_once_with()
|
|
self.setup.import_overlay_files.assert_called_once_with()
|
|
self.setup.import_repositories_marked_as_imageinclude.\
|
|
assert_called_once_with()
|
|
self.setup.call_post_bootstrap_script.assert_called_once_with()
|
|
self.setup.call_config_script.assert_called_once_with()
|
|
self.setup.import_image_identifier.assert_called_once_with()
|
|
self.setup.setup_groups.assert_called_once_with()
|
|
self.setup.setup_users.assert_called_once_with()
|
|
self.setup.setup_keyboard_map.assert_called_once_with()
|
|
self.setup.setup_locale.assert_called_once_with()
|
|
self.setup.setup_plymouth_splash.assert_called_once_with()
|
|
self.setup.setup_timezone.assert_called_once_with()
|
|
self.setup.setup_permissions.assert_called_once_with()
|
|
self.setup.setup_selinux_file_contexts.assert_called_once_with()
|
|
|
|
system_prepare.pinch_system.assert_has_calls(
|
|
[call(force=False), call(force=True)]
|
|
)
|
|
assert system_prepare.clean_package_manager_leftovers.called
|
|
|
|
@patch('kiwi.xml_state.XMLState.get_package_manager')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_run_debootstrap_only_once(
|
|
self, mock_SystemPrepare, mock_get_package_manager
|
|
):
|
|
manager = MagicMock()
|
|
system_prepare = Mock()
|
|
system_prepare.setup_repositories = Mock(
|
|
return_value=manager
|
|
)
|
|
mock_SystemPrepare.return_value.__enter__.return_value = system_prepare
|
|
self._init_command_args()
|
|
mock_get_package_manager.return_value = 'apt'
|
|
self.task.command_args['--allow-existing-root'] = True
|
|
|
|
# debootstrap must be called if chroot with apt-get failed
|
|
self.command.run.side_effect = KiwiCommandError('error')
|
|
self.task.process()
|
|
assert system_prepare.install_bootstrap.called
|
|
|
|
# debootstrap must not be called if chroot looks good
|
|
self.command.run.side_effect = None
|
|
system_prepare.install_bootstrap.reset_mock()
|
|
with self._caplog.at_level(logging.WARNING):
|
|
self.task.process()
|
|
assert not system_prepare.install_bootstrap.called
|
|
|
|
@patch('kiwi.xml_state.XMLState.get_repositories_signing_keys')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_add_package(
|
|
self, mock_SystemPrepare, mock_keys
|
|
):
|
|
manager = MagicMock()
|
|
system_prepare = Mock()
|
|
system_prepare.setup_repositories = Mock(
|
|
return_value=manager
|
|
)
|
|
mock_SystemPrepare.return_value.__enter__.return_value = system_prepare
|
|
mock_keys.return_value = ['some_key', 'some_other_key']
|
|
self._init_command_args()
|
|
self.task.command_args['--add-package'] = ['vim']
|
|
self.task.process()
|
|
system_prepare.setup_repositories.assert_called_once_with(
|
|
False, ['some_key', 'some_other_key'], None
|
|
)
|
|
system_prepare.install_packages.assert_called_once_with(
|
|
manager.__enter__.return_value, ['vim']
|
|
)
|
|
|
|
@patch('kiwi.xml_state.XMLState.get_repositories_signing_keys')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_delete_package(
|
|
self, mock_SystemPrepare, mock_keys
|
|
):
|
|
manager = MagicMock()
|
|
system_prepare = Mock()
|
|
system_prepare.setup_repositories = Mock(
|
|
return_value=manager
|
|
)
|
|
mock_SystemPrepare.return_value.__enter__.return_value = system_prepare
|
|
mock_keys.return_value = ['some_key', 'some_other_key']
|
|
self._init_command_args()
|
|
self.task.command_args['--delete-package'] = ['vim']
|
|
self.task.process()
|
|
system_prepare.setup_repositories.assert_called_once_with(
|
|
False, ['some_key', 'some_other_key'], None
|
|
)
|
|
system_prepare.delete_packages.assert_called_once_with(
|
|
manager.__enter__.return_value, ['vim']
|
|
)
|
|
|
|
@patch('kiwi.xml_state.XMLState.set_container_config_tag')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_set_container_tag(
|
|
self, mock_SystemPrepare, mock_set_container_tag
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--set-container-tag'] = 'new_tag'
|
|
self.task.process()
|
|
mock_set_container_tag.assert_called_once_with(
|
|
'new_tag'
|
|
)
|
|
|
|
@patch('kiwi.xml_state.XMLState.add_container_config_label')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_add_container_label(
|
|
self, mock_SystemPrepare, mock_add_container_label
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--add-container-label'] = ['newLabel=value']
|
|
self.task.process()
|
|
mock_add_container_label.assert_called_once_with(
|
|
'newLabel', 'value'
|
|
)
|
|
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_add_container_label_invalid_format(
|
|
self, mock_SystemPrepare
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--add-container-label'] = ['newLabel:value']
|
|
with self._caplog.at_level(logging.WARNING):
|
|
self.task.process()
|
|
|
|
@patch('kiwi.xml_state.XMLState.set_derived_from_image_uri')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_set_derived_from_uri(
|
|
self, mock_SystemPrepare, mock_set_derived_from_uri
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--set-container-derived-from'] = 'file:///new'
|
|
self.task.process()
|
|
mock_set_derived_from_uri.assert_called_once_with(
|
|
'file:///new'
|
|
)
|
|
|
|
@patch('kiwi.xml_state.XMLState.set_repository')
|
|
@patch('os.path.isfile')
|
|
@patch('os.unlink')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_set_repo(
|
|
self, mock_SystemPrepare, mock_os_unlink,
|
|
mock_os_path_is_file, mock_set_repo
|
|
):
|
|
mock_os_path_is_file.return_value = False
|
|
self._init_command_args()
|
|
self.task.command_args['--set-repo'] = 'http://example.com,yast2,alias'
|
|
self.task.process()
|
|
mock_set_repo.assert_called_once_with(
|
|
'http://example.com', 'yast2', 'alias',
|
|
None, None, None, [], None, None, None
|
|
)
|
|
self.task.command_args['--set-repo-credentials'] = 'user:pass'
|
|
mock_set_repo.reset_mock()
|
|
self.task.process()
|
|
mock_set_repo.assert_called_once_with(
|
|
'http://user:pass@example.com', 'yast2', 'alias',
|
|
None, None, None, [], None, None, None
|
|
)
|
|
self.task.command_args['--set-repo-credentials'] = '../data/credentials'
|
|
mock_os_path_is_file.return_value = True
|
|
mock_set_repo.reset_mock()
|
|
self.task.process()
|
|
mock_set_repo.assert_called_once_with(
|
|
'http://user:pass@example.com', 'yast2', 'alias',
|
|
None, None, None, [], None, None, None
|
|
)
|
|
mock_os_unlink.assert_called_once_with('../data/credentials')
|
|
|
|
@patch('kiwi.xml_state.XMLState.add_repository')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_add_repo(
|
|
self, mock_SystemPrepare, mock_add_repo
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--add-repo'] = [
|
|
'http://example1.com,yast2,alias,99,true',
|
|
'http://example2.com,yast2,alias,99,false,true',
|
|
'http://example3.com,yast2,alias,99,false,true'
|
|
]
|
|
self.task.process()
|
|
assert mock_add_repo.call_args_list == [
|
|
call(
|
|
'http://example1.com', 'yast2', 'alias', '99',
|
|
True, None, [], None, None, None
|
|
),
|
|
call(
|
|
'http://example2.com', 'yast2', 'alias', '99',
|
|
False, True, [], None, None, None
|
|
),
|
|
call(
|
|
'http://example3.com', 'yast2', 'alias', '99',
|
|
False, True, [], None, None, None
|
|
)
|
|
]
|
|
self.task.command_args['--add-repo-credentials'] = [
|
|
'user1:pass1',
|
|
'user2:pass2'
|
|
]
|
|
mock_add_repo.reset_mock()
|
|
self.task.process()
|
|
assert mock_add_repo.call_args_list == [
|
|
call(
|
|
'http://user1:pass1@example1.com', 'yast2', 'alias', '99',
|
|
True, None, [], None, None, None
|
|
),
|
|
call(
|
|
'http://user2:pass2@example2.com', 'yast2', 'alias', '99',
|
|
False, True, [], None, None, None
|
|
),
|
|
call(
|
|
'http://example3.com', 'yast2', 'alias', '99',
|
|
False, True, [], None, None, None
|
|
)
|
|
]
|
|
|
|
def test_process_system_prepare_help(self):
|
|
self._init_command_args()
|
|
self.task.command_args['help'] = True
|
|
self.task.command_args['prepare'] = True
|
|
self.task.process()
|
|
self.task.manual.show.assert_called_once_with(
|
|
'kiwi::system::prepare'
|
|
)
|
|
|
|
@patch('kiwi.xml_state.XMLState.delete_repository_sections')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_delete_repos(
|
|
self, mock_SystemPrepare, mock_delete_repos
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--ignore-repos'] = True
|
|
self.task.process()
|
|
mock_delete_repos.assert_called_once_with()
|
|
|
|
@patch('kiwi.xml_state.XMLState.delete_repository_sections_used_for_build')
|
|
@patch('kiwi.tasks.system_prepare.SystemPrepare')
|
|
def test_process_system_prepare_delete_repos_used_for_build(
|
|
self, mock_SystemPrepare, mock_delete_repos
|
|
):
|
|
self._init_command_args()
|
|
self.task.command_args['--ignore-repos-used-for-build'] = True
|
|
self.task.process()
|
|
mock_delete_repos.assert_called_once_with()
|