class TestSystemSetup(object): @patch('platform.machine') def setup(self, mock_machine): mock_machine.return_value = 'x86_64' self.context_manager_mock = mock.Mock() self.file_mock = mock.Mock() self.enter_mock = mock.Mock() self.exit_mock = mock.Mock() self.enter_mock.return_value = self.file_mock setattr(self.context_manager_mock, '__enter__', self.enter_mock) setattr(self.context_manager_mock, '__exit__', self.exit_mock) self.xml_state = mock.MagicMock() self.xml_state.get_package_manager = mock.Mock( return_value='zypper' ) self.xml_state.build_type.get_filesystem = mock.Mock( return_value='ext3' ) self.xml_state.xml_data.get_name = mock.Mock( return_value='some-image' ) self.xml_state.get_image_version = mock.Mock( return_value='1.2.3' ) self.xml_state.xml_data.description_dir = 'description_dir' self.setup = SystemSetup( self.xml_state, 'root_dir' ) description = XMLDescription( description='../data/example_config.xml', derived_from='derived/description' ) self.setup_with_real_xml = SystemSetup( XMLState(description.load()), 'root_dir' ) command_run = namedtuple( 'command', ['output', 'error', 'returncode'] ) self.run_result = command_run( output='password-hash\n', error='stderr', returncode=0 ) @patch('platform.machine') def test_setup_ix86(self, mock_machine): mock_machine.return_value = 'i686' setup = SystemSetup( mock.MagicMock(), 'root_dir' ) assert setup.arch == 'ix86' @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') def test_import_description(self, mock_path, mock_open, mock_command): mock_path.return_value = True self.setup_with_real_xml.import_description() assert mock_command.call_args_list == [ call(['mkdir', '-p', 'root_dir/image']), call(['cp', '../data/config.sh', 'root_dir/image/config.sh']), call([ 'cp', '../data/my_edit_boot_script', 'root_dir/image/edit_boot_config.sh' ]), call([ 'cp', '/absolute/path/to/my_edit_boot_install', 'root_dir/image/edit_boot_install.sh' ]), call(['cp', '../data/images.sh', 'root_dir/image/images.sh']), call([ 'cp', Defaults.project_file('config/functions.sh'), 'root_dir/.kconfig' ]), call(['cp', '/absolute/path/to/image.tgz', 'root_dir/image/']), call(['cp', '../data/bootstrap.tgz', 'root_dir/image/'])] @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') def test_import_description_archive_from_derived( self, mock_path, mock_open, mock_command ): path_return_values = [ True, False, True, True, True, True, True ] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect self.setup_with_real_xml.import_description() assert mock_command.call_args_list == [ call(['mkdir', '-p', 'root_dir/image']), call(['cp', '../data/config.sh', 'root_dir/image/config.sh']), call([ 'cp', '../data/my_edit_boot_script', 'root_dir/image/edit_boot_config.sh' ]), call([ 'cp', '/absolute/path/to/my_edit_boot_install', 'root_dir/image/edit_boot_install.sh' ]), call(['cp', '../data/images.sh', 'root_dir/image/images.sh']), call([ 'cp', Defaults.project_file('config/functions.sh'), 'root_dir/.kconfig' ]), call(['cp', '/absolute/path/to/image.tgz', 'root_dir/image/']), call([ 'cp', 'derived/description/bootstrap.tgz', 'root_dir/image/' ]) ] @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') @raises(KiwiImportDescriptionError) def test_import_description_configured_editboot_scripts_not_found( self, mock_path, mock_open, mock_command ): path_return_values = [False, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect self.setup_with_real_xml.import_description() @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') @raises(KiwiImportDescriptionError) def test_import_description_configured_archives_not_found( self, mock_path, mock_open, mock_command ): path_return_values = [False, False, True, True, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect self.setup_with_real_xml.import_description() @patch('kiwi.command.Command.run') def test_cleanup(self, mock_command): self.setup.cleanup() mock_command.assert_called_once_with( ['rm', '-r', '-f', '/.kconfig', '/image'] ) @patch_open def test_import_shell_environment(self, mock_open): mock_profile = mock.MagicMock() mock_profile.create = mock.Mock( return_value=['a'] ) mock_open.return_value = self.context_manager_mock self.setup.import_shell_environment(mock_profile) mock_profile.create.assert_called_once_with() mock_open.assert_called_once_with('root_dir/.profile', 'w') self.file_mock.write.assert_called_once_with('a\n') @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_copy_links( self, mock_os_path, mock_DataSync, mock_command ): data = mock.Mock() mock_DataSync.return_value = data mock_os_path.return_value = True self.setup.import_overlay_files( follow_links=True, preserve_owner_group=True ) mock_DataSync.assert_called_once_with( 'description_dir/root/', 'root_dir' ) data.sync_data.assert_called_once_with( options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--copy-links', '-o', '-g' ] ) @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_links( self, mock_os_path, mock_DataSync, mock_command ): data = mock.Mock() mock_DataSync.return_value = data mock_os_path.return_value = True self.setup.import_overlay_files( follow_links=False, preserve_owner_group=True ) mock_DataSync.assert_called_once_with( 'description_dir/root/', 'root_dir' ) data.sync_data.assert_called_once_with( options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--links', '-o', '-g' ] ) @patch('kiwi.system.setup.ArchiveTar') @patch('os.path.exists') def test_import_overlay_files_from_archive( self, mock_os_path, mock_archive ): archive = mock.Mock() mock_archive.return_value = archive exists_results = [True, False] def side_effect(arg): return exists_results.pop() mock_os_path.side_effect = side_effect self.setup.import_overlay_files() mock_archive.assert_called_once_with( 'description_dir/root.tar.gz' ) archive.extract.assert_called_once_with( 'root_dir' ) @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_keyboard_map(self, mock_path, mock_run, mock_shell): mock_path.return_value = True self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() mock_shell.assert_called_once_with( 'baseUpdateSysConfig', [ 'root_dir/etc/sysconfig/keyboard', 'KEYTABLE', '"keytable"' ] ) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_keyboard_map_with_systemd( self, mock_path, mock_run, mock_shell, mock_caps ): mock_caps.return_value = True mock_path.return_value = True self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/vconsole.conf']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--keymap=keytable' ]) ]) @patch('kiwi.logger.log.warning') @patch('os.path.exists') def test_setup_keyboard_skipped(self, mock_exists, mock_log_warn): mock_exists.return_value = False self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() assert mock_log_warn.called @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale(self, mock_path, mock_run, mock_shell): mock_path.return_value = True self.setup.preferences['locale'] = 'locale1,locale2' self.setup.setup_locale() mock_shell.assert_called_once_with( 'baseUpdateSysConfig', [ 'root_dir/etc/sysconfig/language', 'RC_LANG', 'locale1.UTF-8' ] ) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale_with_systemd( self, mock_path, mock_run, mock_shell, mock_caps ): mock_caps.return_valure = True mock_path.return_value = True self.setup.preferences['locale'] = 'locale1,locale2' self.setup.setup_locale() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/locale.conf']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--locale=locale1.UTF-8' ]) ]) @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale_POSIX(self, mock_path, mock_run, mock_shell): mock_path.return_value = True self.setup.preferences['locale'] = 'POSIX,locale2' self.setup.setup_locale() mock_shell.assert_called_once_with( 'baseUpdateSysConfig', [ 'root_dir/etc/sysconfig/language', 'RC_LANG', 'POSIX' ] ) @patch('kiwi.logger.log.warning') @patch('os.path.exists') def test_setup_locale_skipped(self, mock_exists, mock_log_warn): mock_exists.return_value = False self.setup.preferences['locale'] = 'locale1,locale2' self.setup.setup_locale() assert mock_log_warn.called @patch('kiwi.system.setup.Command.run') def test_setup_timezone(self, mock_command): self.setup.preferences['timezone'] = 'timezone' self.setup.setup_timezone() mock_command.assert_has_calls([ call([ 'chroot', 'root_dir', 'ln', '-s', '-f', '/usr/share/zoneinfo/timezone', '/etc/localtime' ]) ]) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Command.run') def test_setup_timezone_with_systemd(self, mock_command, mock_caps): mock_caps.return_value = True self.setup.preferences['timezone'] = 'timezone' self.setup.setup_timezone() mock_command.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/localtime']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--timezone=timezone' ]) ]) @patch('kiwi.system.setup.Users') def test_setup_groups(self, mock_users): users = mock.Mock() users.group_exists = mock.Mock( return_value=False ) mock_users.return_value = users self.setup_with_real_xml.setup_groups() calls = [ call('users'), call('kiwi'), call('admin') ] users.group_exists.assert_has_calls(calls) calls = [ call('users', []), call('kiwi', []), call('admin', []) ] users.group_add.assert_has_calls(calls) @patch('kiwi.system.setup.Users') @patch('kiwi.system.setup.Command.run') def test_setup_users_add(self, mock_command, mock_users): users = mock.Mock() users.user_exists = mock.Mock( return_value=False ) mock_users.return_value = users mock_command.return_value = self.run_result self.setup_with_real_xml.setup_users() calls = [ call('root'), call('tux'), call('kiwi') ] users.user_exists.assert_has_calls(calls) calls = [ call( 'root', [ '-p', 'password-hash', '-s', '/bin/bash', '-u', '815', '-c', 'Bob', '-m', '-d', '/root' ] ), call( 'tux', [ '-p', 'password-hash', '-g', 'users', '-m', '-d', '/home/tux' ] ), call( 'kiwi', [ '-p', 'password-hash', '-g', 'kiwi', '-G', 'admin,users', '-m', '-d', '/home/kiwi' ] ) ] users.user_add.assert_has_calls(calls) mock_command.assert_called_with( ['openssl', 'passwd', '-1', '-salt', 'xyz', 'mypwd'] ) @patch('kiwi.system.setup.Users') @patch('kiwi.system.setup.Command.run') def test_setup_users_modify(self, mock_command, mock_users): users = mock.Mock() users.user_exists = mock.Mock( return_value=True ) mock_users.return_value = users mock_command.return_value = self.run_result self.setup_with_real_xml.setup_users() calls = [ call('root'), call('tux'), call('kiwi') ] users.user_exists.assert_has_calls(calls) calls = [ call( 'root', [ '-p', 'password-hash', '-s', '/bin/bash', '-u', '815', '-c', 'Bob' ] ), call( 'tux', [ '-p', 'password-hash', '-g', 'users' ] ), call( 'kiwi', [ '-p', 'password-hash', '-g', 'kiwi', '-G', 'admin,users' ] ) ] users.user_modify.assert_has_calls(calls) @patch('kiwi.system.setup.Path.which') @patch('kiwi.system.setup.Command.run') def test_setup_plymouth_splash(self, mock_command, mock_which): mock_which.return_value = 'plymouth-set-default-theme' preferences = mock.Mock() preferences.get_bootsplash_theme = mock.Mock( return_value=['some-theme'] ) self.xml_state.get_preferences_sections = mock.Mock( return_value=[preferences] ) self.setup.setup_plymouth_splash() mock_which.assert_called_once_with( custom_env={'PATH': 'root_dir/usr/sbin'}, filename='plymouth-set-default-theme' ) mock_command.assert_called_once_with( ['chroot', 'root_dir', 'plymouth-set-default-theme', 'some-theme'] ) @patch_open @patch('os.path.exists') def test_import_image_identifier(self, mock_os_path, mock_open): self.xml_state.xml_data.get_id = mock.Mock( return_value='42' ) mock_os_path.return_value = True mock_open.return_value = self.context_manager_mock self.setup.import_image_identifier() mock_open.assert_called_once_with('root_dir/etc/ImageID', 'w') self.file_mock.write.assert_called_once_with('42\n') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') def test_call_config_script(self, mock_os_path, mock_watch, mock_command): result_type = namedtuple( 'result', ['stderr', 'returncode'] ) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result self.setup.call_config_script() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'bash', '/image/config.sh'] ) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') def test_call_image_script(self, mock_os_path, mock_watch, mock_command): result_type = namedtuple( 'result_type', ['stderr', 'returncode'] ) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result self.setup.call_image_script() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'bash', '/image/images.sh'] ) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.path.abspath') def test_call_edit_boot_config_script( self, mock_abspath, mock_exists, mock_watch, mock_command ): result_type = namedtuple( 'result_type', ['stderr', 'returncode'] ) mock_result = result_type(stderr='stderr', returncode=0) mock_exists.return_value = True mock_abspath.return_value = '/root_dir/image/edit_boot_config.sh' mock_watch.return_value = mock_result self.setup.call_edit_boot_config_script('ext4', 1) mock_abspath.assert_called_once_with( 'root_dir/image/edit_boot_config.sh' ) mock_command.assert_called_once_with([ 'bash', '-c', 'cd root_dir && bash --norc /root_dir/image/edit_boot_config.sh ext4 1' ]) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.path.abspath') def test_call_edit_boot_install_script( self, mock_abspath, mock_exists, mock_watch, mock_command ): result_type = namedtuple( 'result_type', ['stderr', 'returncode'] ) mock_result = result_type(stderr='stderr', returncode=0) mock_exists.return_value = True mock_abspath.return_value = '/root_dir/image/edit_boot_install.sh' mock_watch.return_value = mock_result self.setup.call_edit_boot_install_script( 'my_image.raw', '/dev/mapper/loop0p1' ) mock_abspath.assert_called_once_with( 'root_dir/image/edit_boot_install.sh' ) mock_command.assert_called_once_with([ 'bash', '-c', 'cd root_dir && bash --norc /root_dir/image/edit_boot_install.sh my_image.raw /dev/mapper/loop0p1' ]) @raises(KiwiScriptFailed) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') def test_call_image_script_raises( self, mock_os_path, mock_watch, mock_command ): result_type = namedtuple( 'result_type', ['stderr', 'returncode'] ) mock_result = result_type(stderr='stderr', returncode=1) mock_os_path.return_value = True mock_watch.return_value = mock_result self.setup.call_image_script() @raises(KiwiScriptFailed) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') def test_call_edit_boot_install_script_raises( self, mock_os_path, mock_watch, mock_command ): result_type = namedtuple( 'result_type', ['stderr', 'returncode'] ) mock_result = result_type(stderr='stderr', returncode=1) mock_os_path.return_value = True mock_watch.return_value = mock_result self.setup.call_edit_boot_install_script( 'my_image.raw', '/dev/mapper/loop0p1' ) @patch('kiwi.command.Command.run') def test_create_init_link_from_linuxrc(self, mock_command): self.setup.create_init_link_from_linuxrc() mock_command.assert_called_once_with( ['ln', 'root_dir/linuxrc', 'root_dir/init'] ) @patch('kiwi.command.Command.run') def test_create_recovery_archive_cleanup_only(self, mock_command): self.setup.oemconfig['recovery'] = False self.setup.create_recovery_archive() assert mock_command.call_args_list[0] == call( ['bash', '-c', 'rm -f root_dir/recovery.*'] ) @patch_open def test_create_fstab(self, mock_open): mock_open.return_value = self.context_manager_mock self.setup.create_fstab(['fstab_entry']) mock_open.assert_called_once_with( 'root_dir/etc/fstab', 'w' ) self.file_mock.write.assert_called_once_with('fstab_entry\n') @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.NamedTemporaryFile') @patch('kiwi.system.setup.ArchiveTar') @patch_open @patch('kiwi.system.setup.Compress') @patch('os.path.getsize') @patch('kiwi.system.setup.Path.wipe') def test_create_recovery_archive( self, mock_wipe, mock_getsize, mock_compress, mock_open, mock_archive, mock_temp, mock_command ): mock_open.return_value = self.context_manager_mock mock_getsize.return_value = 42 compress = mock.Mock() mock_compress.return_value = compress archive = mock.Mock() mock_archive.return_value = archive tmpdir = mock.Mock() tmpdir.name = 'tmpdir' mock_temp.return_value = tmpdir self.setup.oemconfig['recovery'] = True self.setup.oemconfig['recovery_inplace'] = True self.setup.create_recovery_archive() assert mock_command.call_args_list[0] == call( ['bash', '-c', 'rm -f root_dir/recovery.*'] ) mock_archive.assert_called_once_with( create_from_file_list=False, filename='tmpdir' ) archive.create.assert_called_once_with( exclude=['dev', 'proc', 'sys'], options=[ '--numeric-owner', '--hard-dereference', '--preserve-permissions' ], source_dir='root_dir' ) assert mock_command.call_args_list[1] == call( ['mv', 'tmpdir', 'root_dir/recovery.tar'] ) assert mock_open.call_args_list[0] == call( 'root_dir/recovery.tar.filesystem', 'w' ) assert self.file_mock.write.call_args_list[0] == call('ext3') assert mock_command.call_args_list[2] == call( ['bash', '-c', 'tar -tf root_dir/recovery.tar | wc -l'] ) assert mock_open.call_args_list[1] == call( 'root_dir/recovery.tar.files', 'w' ) assert mock_getsize.call_args_list[0] == call( 'root_dir/recovery.tar' ) assert self.file_mock.write.call_args_list[1] == call('1\n') assert mock_open.call_args_list[2] == call( 'root_dir/recovery.tar.size', 'w' ) assert self.file_mock.write.call_args_list[2] == call('42') mock_compress.assert_called_once_with( 'root_dir/recovery.tar' ) compress.gzip.assert_called_once_with() assert mock_getsize.call_args_list[1] == call( 'root_dir/recovery.tar.gz' ) assert mock_open.call_args_list[3] == call( 'root_dir/recovery.partition.size', 'w' ) assert self.file_mock.write.call_args_list[3] == call('300') mock_wipe.assert_called_once_with( 'root_dir/recovery.tar.gz' ) @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.Path.create') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_export_modprobe_setup( self, mock_exists, mock_DataSync, mock_path, mock_command ): data = mock.Mock() mock_DataSync.return_value = data mock_exists.return_value = True self.setup.export_modprobe_setup('target_root_dir') mock_path.assert_called_once_with('target_root_dir/etc') mock_DataSync.assert_called_once_with( 'root_dir/etc/modprobe.d', 'target_root_dir/etc/' ) data.sync_data.assert_called_once_with( options=['-z', '-a'] ) @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_list_rpm( self, mock_open, mock_command ): command = mock.Mock() command.output = 'packages_data' mock_command.return_value = command result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_has_calls([ call(['chroot', 'root_dir', 'rpm', '-E', '%_dbpath']), call([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|%{DISTURL}\\n', '--dbpath', 'packages_data' ]) ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w' ) @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_list_rpm_no_dbpath( self, mock_open, mock_command ): cmd = mock.Mock() cmd.output = 'packages_data' def dbpath_check_fails(command): if '%_dbpath' in command: raise KiwiCommandError() else: return cmd mock_command.side_effect = dbpath_check_fails result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_has_calls([ call(['chroot', 'root_dir', 'rpm', '-E', '%_dbpath']), call([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|%{DISTURL}\\n' ]) ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w' ) @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_list_dpkg( self, mock_open, mock_command ): command = mock.Mock() command.output = 'packages_data' mock_command.return_value = command self.xml_state.get_package_manager = mock.Mock( return_value='apt-get' ) result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'dpkg-query', '--admindir', 'root_dir/var/lib/dpkg', '-W', '-f', '${Package}|None|${Version}|None|${Architecture}|None\\n' ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w' ) @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_verification( self, mock_open, mock_command ): command = mock.Mock() command.output = 'verification_data' mock_command.return_value = command result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_has_calls([ call(['chroot', 'root_dir', 'rpm', '-E', '%_dbpath']), call(command=[ 'rpm', '--root', 'root_dir', '-Va', '--dbpath', 'verification_data' ], raise_on_error=False) ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w' ) @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_verification_no_dbpath( self, mock_open, mock_command ): cmd = mock.Mock() cmd.output = 'verification_data' def dbpath_check_fails(command, raise_on_error): if '%_dbpath' in command: raise KiwiCommandError() else: return cmd mock_command.side_effect = dbpath_check_fails result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_has_calls([ call(['chroot', 'root_dir', 'rpm', '-E', '%_dbpath']), call( command=['rpm', '--root', 'root_dir', '-Va'], raise_on_error=False ) ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w' ) @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_verification_dpkg( self, mock_open, mock_command ): command = mock.Mock() command.output = 'verification_data' mock_command.return_value = command self.xml_state.get_package_manager = mock.Mock( return_value='apt-get' ) result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with( command=[ 'dpkg', '--root', 'root_dir', '-V', '--verify-format', 'rpm' ], raise_on_error=False ) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w' ) @patch('kiwi.system.setup.Command.run') def test_set_selinux_file_contexts(self, mock_command): self.setup.set_selinux_file_contexts('security_context_file') mock_command.assert_called_once_with( [ 'chroot', 'root_dir', 'setfiles', 'security_context_file', '/', '-v' ] ) @patch('kiwi.system.setup.Repository') @patch('kiwi.system.setup.Uri') def test_import_repositories_marked_as_imageinclude( self, mock_uri, mock_repo ): uri = mock.Mock() mock_uri.return_value = uri uri.translate = mock.Mock( return_value="uri" ) uri.alias = mock.Mock( return_value="uri-alias" ) uri.credentials_file_name = mock.Mock( return_value='kiwiRepoCredentials' ) mock_uri.return_value = uri repo = mock.Mock() mock_repo.return_value = repo self.setup_with_real_xml.import_repositories_marked_as_imageinclude() assert repo.add_repo.call_args_list[0] == call( 'uri-alias', 'uri', 'rpm-md', None, None, None, None, None, 'kiwiRepoCredentials', None, None )
def process(self): # noqa: C901 """ Prepare and install a new system for chroot access """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() self.load_xml_description(self.command_args['--description']) abs_root_path = os.path.abspath(self.command_args['--root']) self.runtime_checker.check_efi_mode_for_disk_overlay_correctly_setup() self.runtime_checker.check_grub_efi_installed_for_efi_firmware() self.runtime_checker.check_boot_description_exists() self.runtime_checker.check_consistent_kernel_in_boot_and_system_image() self.runtime_checker.check_docker_tool_chain_installed() self.runtime_checker.check_volume_setup_has_no_root_definition() self.runtime_checker.check_xen_uniquely_setup_as_server_or_guest() self.runtime_checker.check_target_directory_not_in_shared_cache( abs_root_path) self.runtime_checker.check_mediacheck_only_for_x86_arch() self.runtime_checker.check_dracut_module_for_live_iso_in_package_list() self.runtime_checker.check_dracut_module_for_disk_overlay_in_package_list( ) self.runtime_checker.check_dracut_module_for_disk_oem_in_package_list() self.runtime_checker.check_dracut_module_for_oem_install_in_package_list( ) if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo'])) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository(*self.sextuple_token(add_repo)) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag']) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from']) self.runtime_checker.check_repositories_configured() self.runtime_checker.check_image_include_repos_publicly_resolvable() log.info('Preparing system') system = SystemPrepare(self.xml_state, abs_root_path, self.command_args['--allow-existing-root']) manager = system.setup_repositories(self.command_args['--clear-cache'], self.command_args['--signing-key']) system.install_bootstrap(manager) system.install_system(manager) if self.command_args['--add-package']: system.install_packages(manager, self.command_args['--add-package']) if self.command_args['--delete-package']: system.delete_packages(manager, self.command_args['--delete-package']) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) setup = SystemSetup(self.xml_state, abs_root_path) setup.import_shell_environment(profile) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # handle uninstall package requests, gracefully uninstall # with dependency cleanup system.pinch_system(force=False) # handle delete package requests, forced uninstall without # any dependency resolution system.pinch_system(force=True) # make sure system instance is cleaned up now del system
class TestSystemSetup: @patch('platform.machine') def setup(self, mock_machine): mock_machine.return_value = 'x86_64' self.context_manager_mock = mock.Mock() self.file_mock = mock.Mock() self.enter_mock = mock.Mock() self.exit_mock = mock.Mock() self.enter_mock.return_value = self.file_mock setattr(self.context_manager_mock, '__enter__', self.enter_mock) setattr(self.context_manager_mock, '__exit__', self.exit_mock) self.xml_state = mock.MagicMock() self.xml_state.get_package_manager = mock.Mock(return_value='zypper') self.xml_state.build_type.get_filesystem = mock.Mock( return_value='ext3') self.xml_state.xml_data.get_name = mock.Mock(return_value='some-image') self.xml_state.get_image_version = mock.Mock(return_value='1.2.3') self.xml_state.xml_data.description_dir = 'description_dir' self.setup = SystemSetup(self.xml_state, 'root_dir') description = XMLDescription(description='../data/example_config.xml', derived_from='derived/description') self.setup_with_real_xml = SystemSetup(XMLState(description.load()), 'root_dir') command_run = namedtuple('command', ['output', 'error', 'returncode']) self.run_result = command_run(output='password-hash\n', error='stderr', returncode=0) @patch('platform.machine') def test_setup_ix86(self, mock_machine): mock_machine.return_value = 'i686' setup = SystemSetup(mock.MagicMock(), 'root_dir') assert setup.arch == 'ix86' @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') @patch('kiwi.system.setup.glob.iglob') def test_import_description(self, mock_iglob, mock_path, mock_open, mock_command): mock_iglob.return_value = ['config-cdroot.tar.xz'] mock_path.return_value = True self.setup_with_real_xml.import_description() mock_iglob.assert_called_once_with('../data/config-cdroot.tar*') assert mock_command.call_args_list == [ call(['mkdir', '-p', 'root_dir/image']), call(['cp', '../data/config.sh', 'root_dir/image/config.sh']), call([ 'cp', '../data/my_edit_boot_script', 'root_dir/image/edit_boot_config.sh' ]), call([ 'cp', '/absolute/path/to/my_edit_boot_install', 'root_dir/image/edit_boot_install.sh' ]), call(['cp', '../data/images.sh', 'root_dir/image/images.sh']), call([ 'cp', Defaults.project_file('config/functions.sh'), 'root_dir/.kconfig' ]), call(['cp', '/absolute/path/to/image.tgz', 'root_dir/image/']), call(['cp', '../data/bootstrap.tgz', 'root_dir/image/']), call(['cp', 'config-cdroot.tar.xz', 'root_dir/image/']) ] @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') def test_import_description_archive_from_derived(self, mock_path, mock_open, mock_command): path_return_values = [True, False, True, True, True, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect self.setup_with_real_xml.import_description() assert mock_command.call_args_list == [ call(['mkdir', '-p', 'root_dir/image']), call(['cp', '../data/config.sh', 'root_dir/image/config.sh']), call([ 'cp', '../data/my_edit_boot_script', 'root_dir/image/edit_boot_config.sh' ]), call([ 'cp', '/absolute/path/to/my_edit_boot_install', 'root_dir/image/edit_boot_install.sh' ]), call(['cp', '../data/images.sh', 'root_dir/image/images.sh']), call([ 'cp', Defaults.project_file('config/functions.sh'), 'root_dir/.kconfig' ]), call(['cp', '/absolute/path/to/image.tgz', 'root_dir/image/']), call( ['cp', 'derived/description/bootstrap.tgz', 'root_dir/image/']) ] @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') @raises(KiwiImportDescriptionError) def test_import_description_configured_editboot_scripts_not_found( self, mock_path, mock_open, mock_command): path_return_values = [False, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect self.setup_with_real_xml.import_description() @patch('kiwi.command.Command.run') @patch_open @patch('os.path.exists') @raises(KiwiImportDescriptionError) def test_import_description_configured_archives_not_found( self, mock_path, mock_open, mock_command): path_return_values = [False, False, True, True, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect self.setup_with_real_xml.import_description() @patch('kiwi.command.Command.run') def test_cleanup(self, mock_command): self.setup.cleanup() mock_command.assert_called_once_with( ['rm', '-r', '-f', '/.kconfig', '/image']) @patch_open def test_import_shell_environment(self, mock_open): mock_profile = mock.MagicMock() mock_profile.create = mock.Mock(return_value=['a']) mock_open.return_value = self.context_manager_mock self.setup.import_shell_environment(mock_profile) mock_profile.create.assert_called_once_with() mock_open.assert_called_once_with('root_dir/.profile', 'w') self.file_mock.write.assert_called_once_with('a\n') @patch('kiwi.system.setup.ArchiveTar') @patch('kiwi.system.setup.glob.iglob') def test_import_cdroot_files(self, mock_iglob, mock_ArchiveTar): archive = mock.Mock() mock_ArchiveTar.return_value = archive mock_iglob.return_value = ['config-cdroot.tar.xz'] self.setup.import_cdroot_files('target_dir') mock_iglob.assert_called_once_with( 'description_dir/config-cdroot.tar*') mock_ArchiveTar.assert_called_once_with('config-cdroot.tar.xz') archive.extract.assert_called_once_with('target_dir') @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_copy_links(self, mock_os_path, mock_DataSync, mock_command): data = mock.Mock() mock_DataSync.return_value = data mock_os_path.return_value = True self.setup.import_overlay_files(follow_links=True, preserve_owner_group=True) mock_DataSync.assert_called_once_with('description_dir/root/', 'root_dir') data.sync_data.assert_called_once_with(options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--copy-links', '-o', '-g' ]) @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_links(self, mock_os_path, mock_DataSync, mock_command): data = mock.Mock() mock_DataSync.return_value = data mock_os_path.return_value = True self.setup.import_overlay_files(follow_links=False, preserve_owner_group=True) mock_DataSync.assert_called_once_with('description_dir/root/', 'root_dir') data.sync_data.assert_called_once_with(options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--links', '-o', '-g' ]) @patch('kiwi.system.setup.ArchiveTar') @patch('os.path.exists') def test_import_overlay_files_from_archive(self, mock_os_path, mock_archive): archive = mock.Mock() mock_archive.return_value = archive exists_results = [True, False] def side_effect(arg): return exists_results.pop() mock_os_path.side_effect = side_effect self.setup.import_overlay_files() mock_archive.assert_called_once_with('description_dir/root.tar.gz') archive.extract.assert_called_once_with('root_dir') @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_keyboard_map(self, mock_path, mock_run, mock_shell): mock_path.return_value = True self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() mock_shell.assert_called_once_with( 'baseUpdateSysConfig', ['root_dir/etc/sysconfig/keyboard', 'KEYTABLE', '"keytable"']) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_keyboard_map_with_systemd(self, mock_path, mock_run, mock_shell, mock_caps): mock_caps.return_value = True mock_path.return_value = True self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/vconsole.conf']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--keymap=keytable' ]) ]) @patch('kiwi.logger.log.warning') @patch('os.path.exists') def test_setup_keyboard_skipped(self, mock_exists, mock_log_warn): mock_exists.return_value = False self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() assert mock_log_warn.called @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale(self, mock_path, mock_run, mock_shell, mock_caps): mock_caps.return_valure = True mock_path.return_value = True self.setup.preferences['locale'] = 'locale1,locale2' self.setup.setup_locale() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/locale.conf']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--locale=locale1.UTF-8' ]) ]) mock_shell.assert_called_once_with( 'baseUpdateSysConfig', ['root_dir/etc/sysconfig/language', 'RC_LANG', 'locale1.UTF-8']) @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale_POSIX(self, mock_path, mock_run, mock_shell): mock_path.return_value = True self.setup.preferences['locale'] = 'POSIX,locale2' self.setup.setup_locale() mock_shell.assert_called_once_with( 'baseUpdateSysConfig', ['root_dir/etc/sysconfig/language', 'RC_LANG', 'POSIX']) @patch('kiwi.system.setup.Command.run') def test_setup_timezone(self, mock_command): self.setup.preferences['timezone'] = 'timezone' self.setup.setup_timezone() mock_command.assert_has_calls([ call([ 'chroot', 'root_dir', 'ln', '-s', '-f', '/usr/share/zoneinfo/timezone', '/etc/localtime' ]) ]) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Command.run') def test_setup_timezone_with_systemd(self, mock_command, mock_caps): mock_caps.return_value = True self.setup.preferences['timezone'] = 'timezone' self.setup.setup_timezone() mock_command.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/localtime']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--timezone=timezone' ]) ]) @patch('kiwi.system.setup.Users') def test_setup_groups(self, mock_users): users = mock.Mock() users.group_exists = mock.Mock(return_value=False) mock_users.return_value = users self.setup_with_real_xml.setup_groups() calls = [call('users'), call('kiwi'), call('admin')] users.group_exists.assert_has_calls(calls) calls = [call('users', []), call('kiwi', []), call('admin', [])] users.group_add.assert_has_calls(calls) @patch('kiwi.system.setup.Users') @patch('kiwi.system.setup.Command.run') def test_setup_users_add(self, mock_command, mock_users): users = mock.Mock() users.user_exists = mock.Mock(return_value=False) mock_users.return_value = users mock_command.return_value = self.run_result self.setup_with_real_xml.setup_users() calls = [call('root'), call('tux'), call('kiwi')] users.user_exists.assert_has_calls(calls) calls = [ call('root', [ '-p', 'password-hash', '-s', '/bin/bash', '-u', '815', '-c', 'Bob', '-m', '-d', '/root' ]), call('tux', [ '-p', 'password-hash', '-g', 'users', '-m', '-d', '/home/tux' ]), call('kiwi', [ '-p', 'password-hash', '-g', 'kiwi', '-G', 'admin,users', '-m', '-d', '/home/kiwi' ]) ] users.user_add.assert_has_calls(calls) mock_command.assert_called_with( ['openssl', 'passwd', '-1', '-salt', 'xyz', 'mypwd']) @patch('kiwi.system.setup.Users') @patch('kiwi.system.setup.Command.run') def test_setup_users_modify(self, mock_command, mock_users): users = mock.Mock() users.user_exists = mock.Mock(return_value=True) mock_users.return_value = users mock_command.return_value = self.run_result self.setup_with_real_xml.setup_users() calls = [call('root'), call('tux'), call('kiwi')] users.user_exists.assert_has_calls(calls) calls = [ call('root', [ '-p', 'password-hash', '-s', '/bin/bash', '-u', '815', '-c', 'Bob' ]), call('tux', ['-p', 'password-hash', '-g', 'users']), call('kiwi', ['-p', 'password-hash', '-g', 'kiwi', '-G', 'admin,users']) ] users.user_modify.assert_has_calls(calls) @patch('kiwi.system.setup.Path.which') @patch('kiwi.system.setup.Command.run') def test_setup_plymouth_splash(self, mock_command, mock_which): mock_which.return_value = 'plymouth-set-default-theme' preferences = mock.Mock() preferences.get_bootsplash_theme = mock.Mock( return_value=['some-theme']) self.xml_state.get_preferences_sections = mock.Mock( return_value=[preferences]) self.setup.setup_plymouth_splash() mock_which.assert_called_once_with( custom_env={'PATH': 'root_dir/usr/sbin'}, filename='plymouth-set-default-theme') mock_command.assert_called_once_with( ['chroot', 'root_dir', 'plymouth-set-default-theme', 'some-theme']) @patch_open @patch('os.path.exists') def test_import_image_identifier(self, mock_os_path, mock_open): self.xml_state.xml_data.get_id = mock.Mock(return_value='42') mock_os_path.return_value = True mock_open.return_value = self.context_manager_mock self.setup.import_image_identifier() mock_open.assert_called_once_with('root_dir/etc/ImageID', 'w') self.file_mock.write.assert_called_once_with('42\n') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') def test_call_non_excutable_config_script(self, mock_access, mock_stat, mock_os_path, mock_watch, mock_command): result_type = namedtuple('result', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False self.setup.call_config_script() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'bash', '/image/config.sh']) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') def test_call_excutable_config_script(self, mock_access, mock_stat, mock_os_path, mock_watch, mock_command): result_type = namedtuple('result', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result # pretend that the script is executable mock_access.return_value = True self.setup.call_config_script() mock_command.assert_called_once_with( ['chroot', 'root_dir', '/image/config.sh']) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') def test_call_image_script(self, mock_access, mock_stat, mock_os_path, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False self.setup.call_image_script() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'bash', '/image/images.sh']) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.path.abspath') def test_call_edit_boot_config_script(self, mock_abspath, mock_exists, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_exists.return_value = True mock_abspath.return_value = '/root_dir/image/edit_boot_config.sh' mock_watch.return_value = mock_result self.setup.call_edit_boot_config_script('ext4', 1) mock_abspath.assert_called_once_with( 'root_dir/image/edit_boot_config.sh') mock_command.assert_called_once_with([ 'bash', '-c', 'cd root_dir && bash --norc /root_dir/image/edit_boot_config.sh ' 'ext4 1' ]) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.path.abspath') def test_call_edit_boot_install_script(self, mock_abspath, mock_exists, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_exists.return_value = True mock_abspath.return_value = '/root_dir/image/edit_boot_install.sh' mock_watch.return_value = mock_result self.setup.call_edit_boot_install_script('my_image.raw', '/dev/mapper/loop0p1') mock_abspath.assert_called_once_with( 'root_dir/image/edit_boot_install.sh') mock_command.assert_called_once_with([ 'bash', '-c', 'cd root_dir && bash --norc /root_dir/image/edit_boot_install.sh ' 'my_image.raw /dev/mapper/loop0p1' ]) @raises(KiwiScriptFailed) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') def test_call_image_script_raises(self, mock_access, mock_stat, mock_os_path, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=1) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False self.setup.call_image_script() @raises(KiwiScriptFailed) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') def test_call_edit_boot_install_script_raises(self, mock_os_path, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=1) mock_os_path.return_value = True mock_watch.return_value = mock_result self.setup.call_edit_boot_install_script('my_image.raw', '/dev/mapper/loop0p1') @patch('kiwi.command.Command.run') def test_create_init_link_from_linuxrc(self, mock_command): self.setup.create_init_link_from_linuxrc() mock_command.assert_called_once_with( ['ln', 'root_dir/linuxrc', 'root_dir/init']) @patch('kiwi.command.Command.run') def test_create_recovery_archive_cleanup_only(self, mock_command): self.setup.oemconfig['recovery'] = False self.setup.create_recovery_archive() assert mock_command.call_args_list[0] == call( ['bash', '-c', 'rm -f root_dir/recovery.*']) @patch_open @patch('os.path.exists') @patch('kiwi.system.setup.Path.wipe') @patch('kiwi.command.Command.run') def test_create_fstab(self, mock_command, mock_wipe, mock_exists, mock_open): mock_exists.return_value = True mock_open.return_value = self.context_manager_mock self.file_mock.read.return_value = 'append_entry' self.setup.create_fstab(['fstab_entry']) assert mock_open.call_args_list == [ call('root_dir/etc/fstab', 'w'), call('root_dir/etc/fstab.append', 'r') ] assert self.file_mock.write.call_args_list == [ call('fstab_entry\n'), call('append_entry') ] assert mock_command.call_args_list == [ call(['patch', 'root_dir/etc/fstab', 'root_dir/etc/fstab.patch']), call(['chroot', 'root_dir', '/etc/fstab.script']) ] assert mock_wipe.call_args_list == [ call('root_dir/etc/fstab.append'), call('root_dir/etc/fstab.patch'), call('root_dir/etc/fstab.script') ] @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.NamedTemporaryFile') @patch('kiwi.system.setup.ArchiveTar') @patch_open @patch('kiwi.system.setup.Compress') @patch('os.path.getsize') @patch('kiwi.system.setup.Path.wipe') def test_create_recovery_archive(self, mock_wipe, mock_getsize, mock_compress, mock_open, mock_archive, mock_temp, mock_command): mock_open.return_value = self.context_manager_mock mock_getsize.return_value = 42 compress = mock.Mock() mock_compress.return_value = compress archive = mock.Mock() mock_archive.return_value = archive tmpdir = mock.Mock() tmpdir.name = 'tmpdir' mock_temp.return_value = tmpdir self.setup.oemconfig['recovery'] = True self.setup.oemconfig['recovery_inplace'] = True self.setup.create_recovery_archive() assert mock_command.call_args_list[0] == call( ['bash', '-c', 'rm -f root_dir/recovery.*']) mock_archive.assert_called_once_with(create_from_file_list=False, filename='tmpdir') archive.create.assert_called_once_with(exclude=['dev', 'proc', 'sys'], options=[ '--numeric-owner', '--hard-dereference', '--preserve-permissions' ], source_dir='root_dir') assert mock_command.call_args_list[1] == call( ['mv', 'tmpdir', 'root_dir/recovery.tar']) assert mock_open.call_args_list[0] == call( 'root_dir/recovery.tar.filesystem', 'w') assert self.file_mock.write.call_args_list[0] == call('ext3') assert mock_command.call_args_list[2] == call( ['bash', '-c', 'tar -tf root_dir/recovery.tar | wc -l']) assert mock_open.call_args_list[1] == call( 'root_dir/recovery.tar.files', 'w') assert mock_getsize.call_args_list[0] == call('root_dir/recovery.tar') assert self.file_mock.write.call_args_list[1] == call('1\n') assert mock_open.call_args_list[2] == call( 'root_dir/recovery.tar.size', 'w') assert self.file_mock.write.call_args_list[2] == call('42') mock_compress.assert_called_once_with('root_dir/recovery.tar') compress.gzip.assert_called_once_with() assert mock_getsize.call_args_list[1] == call( 'root_dir/recovery.tar.gz') assert mock_open.call_args_list[3] == call( 'root_dir/recovery.partition.size', 'w') assert self.file_mock.write.call_args_list[3] == call('300') mock_wipe.assert_called_once_with('root_dir/recovery.tar.gz') @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.Path.create') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_export_modprobe_setup(self, mock_exists, mock_DataSync, mock_path, mock_command): data = mock.Mock() mock_DataSync.return_value = data mock_exists.return_value = True self.setup.export_modprobe_setup('target_root_dir') mock_path.assert_called_once_with('target_root_dir/etc') mock_DataSync.assert_called_once_with('root_dir/etc/modprobe.d', 'target_root_dir/etc/') data.sync_data.assert_called_once_with(options=['-a']) @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.RpmDataBase') @patch('kiwi.system.setup.MountManager') @patch_open def test_export_package_list_rpm(self, mock_open, mock_MountManager, mock_RpmDataBase, mock_command): rpmdb = mock.Mock() rpmdb.rpmdb_image.expand_query.return_value = 'image_dbpath' rpmdb.rpmdb_host.expand_query.return_value = 'host_dbpath' rpmdb.has_rpm.return_value = True mock_RpmDataBase.return_value = rpmdb command = mock.Mock() command.output = 'packages_data' mock_command.return_value = command result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|' '%{DISTURL}|%{LICENSE}\\n', '--dbpath', 'image_dbpath' ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w') rpmdb.has_rpm.return_value = False mock_command.reset_mock() result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|' '%{DISTURL}|%{LICENSE}\\n', '--dbpath', 'host_dbpath' ]) @patch('kiwi.system.setup.os.path.exists') @patch_open def test_setup_machine_id(self, mock_open, mock_path_exists): mock_path_exists.return_value = True self.setup.setup_machine_id() mock_path_exists.return_value = False self.setup.setup_machine_id() mock_open.assert_called_once_with('root_dir/etc/machine-id', 'w') @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.Path.which') @patch('kiwi.logger.log.warning') def test_setup_permissions(self, mock_log_warn, mock_path_which, mock_command): mock_path_which.return_value = 'chkstat' self.setup.setup_permissions() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'chkstat', '--system', '--set']) mock_path_which.return_value = None self.setup.setup_permissions() mock_log_warn.assert_called_once() @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_list_dpkg(self, mock_open, mock_command): command = mock.Mock() command.output = 'packages_data' mock_command.return_value = command self.xml_state.get_package_manager = mock.Mock(return_value='apt-get') result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'dpkg-query', '--admindir', 'root_dir/var/lib/dpkg', '-W', '-f', '${Package}|None|${Version}|None|${Architecture}|None|None\\n' ]) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w') @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.RpmDataBase') @patch('kiwi.system.setup.MountManager') @patch_open def test_export_package_verification(self, mock_open, mock_MountManager, mock_RpmDataBase, mock_command): is_mounted_return = [True, False] def is_mounted(): return is_mounted_return.pop() shared_mount = mock.Mock() shared_mount.is_mounted.side_effect = is_mounted mock_MountManager.return_value = shared_mount rpmdb = mock.Mock() rpmdb.rpmdb_image.expand_query.return_value = 'image_dbpath' rpmdb.rpmdb_host.expand_query.return_value = 'host_dbpath' rpmdb.has_rpm.return_value = True mock_RpmDataBase.return_value = rpmdb command = mock.Mock() command.output = 'verification_data' mock_command.return_value = command result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with(command=[ 'rpm', '--root', 'root_dir', '-Va', '--dbpath', 'image_dbpath' ], raise_on_error=False) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w') mock_MountManager.assert_called_once_with(device='/dev', mountpoint='root_dir/dev') shared_mount.bind_mount.assert_called_once_with() shared_mount.umount_lazy.assert_called_once_with() rpmdb.has_rpm.return_value = False is_mounted_return = [True, False] mock_command.reset_mock() shared_mount.reset_mock() result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with(command=[ 'rpm', '--root', 'root_dir', '-Va', '--dbpath', 'host_dbpath' ], raise_on_error=False) shared_mount.bind_mount.assert_called_once_with() shared_mount.umount_lazy.assert_called_once_with() @patch('kiwi.system.setup.Command.run') @patch_open def test_export_package_verification_dpkg(self, mock_open, mock_command): command = mock.Mock() command.output = 'verification_data' mock_command.return_value = command self.xml_state.get_package_manager = mock.Mock(return_value='apt-get') result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with(command=[ 'dpkg', '--root', 'root_dir', '-V', '--verify-format', 'rpm' ], raise_on_error=False) mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w') @patch('kiwi.system.setup.Command.run') def test_set_selinux_file_contexts(self, mock_command): self.setup.set_selinux_file_contexts('security_context_file') mock_command.assert_called_once_with([ 'chroot', 'root_dir', 'setfiles', 'security_context_file', '/', '-v' ]) @patch('kiwi.system.setup.Repository') @patch('kiwi.system.setup.Uri') def test_import_repositories_marked_as_imageinclude( self, mock_uri, mock_repo): uri = mock.Mock() mock_uri.return_value = uri uri.translate = mock.Mock(return_value="uri") uri.alias = mock.Mock(return_value="uri-alias") uri.credentials_file_name = mock.Mock( return_value='kiwiRepoCredentials') mock_uri.return_value = uri repo = mock.Mock() mock_repo.return_value = repo self.setup_with_real_xml.import_repositories_marked_as_imageinclude() assert repo.add_repo.call_args_list[0] == call('uri-alias', 'uri', 'rpm-md', None, None, None, None, None, 'kiwiRepoCredentials', None, None)
def process(self): # noqa: C901 """ Prepare and install a new system for chroot access """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() self.load_xml_description(self.command_args['--description']) abs_root_path = os.path.abspath(self.command_args['--root']) prepare_checks = self.checks_before_command_args prepare_checks.update( {'check_target_directory_not_in_shared_cache': [abs_root_path]}) self.run_checks(prepare_checks) if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo'])) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository(*self.sextuple_token(add_repo)) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag']) if self.command_args['--add-container-label']: for add_label in self.command_args['--add-container-label']: try: (name, value) = add_label.split('=', 1) self.xml_state.add_container_config_label(name, value) except Exception: log.warning('Container label {0} ignored. Invalid format: ' 'expected labelname=value'.format(add_label)) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from']) self.run_checks(self.checks_after_command_args) log.info('Preparing system') system = SystemPrepare(self.xml_state, abs_root_path, self.command_args['--allow-existing-root']) manager = system.setup_repositories(self.command_args['--clear-cache'], self.command_args['--signing-key']) system.install_bootstrap(manager, self.command_args['--add-bootstrap-package']) system.install_system(manager) if self.command_args['--add-package']: system.install_packages(manager, self.command_args['--add-package']) if self.command_args['--delete-package']: system.delete_packages(manager, self.command_args['--delete-package']) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) setup = SystemSetup(self.xml_state, abs_root_path) setup.import_shell_environment(profile) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() setup.setup_permissions() # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # handle uninstall package requests, gracefully uninstall # with dependency cleanup system.pinch_system(force=False) # handle delete package requests, forced uninstall without # any dependency resolution system.pinch_system(force=True) # delete any custom rpm macros created Rpm(abs_root_path, Defaults.get_custom_rpm_image_macro_name()).wipe_config() # make sure system instance is cleaned up now del system
class TestSystemSetup: @fixture(autouse=True) def inject_fixtures(self, caplog): self._caplog = caplog @patch('kiwi.system.setup.RuntimeConfig') def setup(self, mock_RuntimeConfig): Defaults.set_platform_name('x86_64') self.runtime_config = Mock() self.runtime_config.get_package_changes = Mock(return_value=True) mock_RuntimeConfig.return_value = self.runtime_config self.xml_state = MagicMock() self.xml_state.get_package_manager = Mock(return_value='zypper') self.xml_state.build_type.get_filesystem = Mock(return_value='ext3') self.xml_state.xml_data.get_name = Mock(return_value='some-image') self.xml_state.get_image_version = Mock(return_value='1.2.3') self.xml_state.xml_data.description_dir = 'description_dir' self.setup = SystemSetup(self.xml_state, 'root_dir') description = XMLDescription(description='../data/example_config.xml', derived_from='derived/description') self.description_dir = os.path.dirname(description.description_origin) self.setup_with_real_xml = SystemSetup(XMLState(description.load()), 'root_dir') command_run = namedtuple('command', ['output', 'error', 'returncode']) self.run_result = command_run(output='password-hash\n', error='stderr', returncode=0) def teardown(self): sys.argv = argv_kiwi_tests def test_setup_ix86(self): Defaults.set_platform_name('i686') setup = SystemSetup(MagicMock(), 'root_dir') assert setup.arch == 'ix86' @patch('kiwi.command.Command.run') @patch('os.path.exists') @patch('kiwi.system.setup.glob.iglob') def test_import_description(self, mock_iglob, mock_path, mock_command): mock_iglob.return_value = ['config-cdroot.tar.xz'] mock_path.return_value = True with patch('builtins.open'): self.setup_with_real_xml.import_description() mock_iglob.assert_called_once_with('{0}/config-cdroot.tar*'.format( self.description_dir)) assert mock_command.call_args_list == [ call([ 'cp', '{0}/config.sh'.format(self.description_dir), 'root_dir/image/config.sh' ]), call([ 'cp', '{0}/disk.sh'.format(self.description_dir), 'root_dir/image/disk.sh' ]), call([ 'cp', '{0}/my_edit_boot_script'.format(self.description_dir), 'root_dir/image/edit_boot_config.sh' ]), call([ 'cp', '/absolute/path/to/my_edit_boot_install', 'root_dir/image/edit_boot_install.sh' ]), call([ 'cp', '{0}/images.sh'.format(self.description_dir), 'root_dir/image/images.sh' ]), call([ 'cp', '{0}/post_bootstrap.sh'.format(self.description_dir), 'root_dir/image/post_bootstrap.sh' ]), call([ 'cp', Defaults.project_file('config/functions.sh'), 'root_dir/.kconfig' ]), call(['cp', '/absolute/path/to/image.tgz', 'root_dir/image/']), call([ 'cp', '{0}/bootstrap.tgz'.format(self.description_dir), 'root_dir/image/' ]), call(['cp', 'config-cdroot.tar.xz', 'root_dir/image/']) ] @patch('kiwi.path.Path.create') @patch('kiwi.command.Command.run') @patch('os.path.exists') def test_import_description_archive_from_derived(self, mock_path, mock_command, mock_create): path_return_values = [ True, False, True, True, True, True, True, True, True ] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect with patch('builtins.open'): self.setup_with_real_xml.import_description() assert mock_command.call_args_list == [ call([ 'cp', '{0}/config.sh'.format(self.description_dir), 'root_dir/image/config.sh' ]), call([ 'cp', '{0}/disk.sh'.format(self.description_dir), 'root_dir/image/disk.sh' ]), call([ 'cp', '{0}/my_edit_boot_script'.format(self.description_dir), 'root_dir/image/edit_boot_config.sh' ]), call([ 'cp', '/absolute/path/to/my_edit_boot_install', 'root_dir/image/edit_boot_install.sh' ]), call([ 'cp', '{0}/images.sh'.format(self.description_dir), 'root_dir/image/images.sh' ]), call([ 'cp', '{0}/post_bootstrap.sh'.format(self.description_dir), 'root_dir/image/post_bootstrap.sh' ]), call([ 'cp', Defaults.project_file('config/functions.sh'), 'root_dir/.kconfig' ]), call(['cp', '/absolute/path/to/image.tgz', 'root_dir/image/']), call( ['cp', 'derived/description/bootstrap.tgz', 'root_dir/image/']) ] mock_create.assert_called_once_with('root_dir/image') @patch('kiwi.command.Command.run') @patch('os.path.exists') def test_import_description_configured_editboot_scripts_not_found( self, mock_path, mock_command): path_return_values = [False, True, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect with patch('builtins.open'): with raises(KiwiImportDescriptionError): self.setup_with_real_xml.import_description() @patch('kiwi.path.Path.create') @patch('kiwi.command.Command.run') @patch('os.path.exists') def test_import_description_configured_archives_not_found( self, mock_path, mock_command, mock_create): path_return_values = [False, False, True, True, True, True, True, True] def side_effect(arg): return path_return_values.pop() mock_path.side_effect = side_effect with patch('builtins.open'): with raises(KiwiImportDescriptionError): self.setup_with_real_xml.import_description() @patch('kiwi.command.Command.run') def test_cleanup(self, mock_command): self.setup.cleanup() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'rm', '-rf', '.kconfig', 'image']) @patch('kiwi.system.setup.ArchiveTar') @patch('kiwi.system.setup.glob.iglob') def test_import_cdroot_files(self, mock_iglob, mock_ArchiveTar): archive = Mock() mock_ArchiveTar.return_value = archive mock_iglob.return_value = ['config-cdroot.tar.xz'] self.setup.import_cdroot_files('target_dir') mock_iglob.assert_called_once_with( 'description_dir/config-cdroot.tar*') mock_ArchiveTar.assert_called_once_with('config-cdroot.tar.xz') archive.extract.assert_called_once_with('target_dir') @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_copy_links(self, mock_os_path, mock_DataSync, mock_command): data = Mock() mock_DataSync.return_value = data mock_os_path.return_value = True self.setup.import_overlay_files(follow_links=True, preserve_owner_group=True) mock_DataSync.assert_called_once_with('description_dir/root/', 'root_dir') data.sync_data.assert_called_once_with(options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--copy-links', '-o', '-g' ]) @patch('kiwi.command.Command.run') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_links(self, mock_os_path, mock_DataSync, mock_command): data = Mock() mock_DataSync.return_value = data mock_os_path.return_value = True self.setup.import_overlay_files(follow_links=False, preserve_owner_group=True) mock_DataSync.assert_called_once_with('description_dir/root/', 'root_dir') data.sync_data.assert_called_once_with(options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--links', '-o', '-g' ]) @patch('kiwi.system.setup.ArchiveTar') @patch('os.path.exists') def test_import_overlay_files_from_archive(self, mock_os_path, mock_archive): archive = Mock() mock_archive.return_value = archive exists_results = [True, False] def side_effect(arg): return exists_results.pop() mock_os_path.side_effect = side_effect self.setup.import_overlay_files() mock_archive.assert_called_once_with('description_dir/root.tar.gz') archive.extract.assert_called_once_with('root_dir') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_import_overlay_files_from_profile(self, mock_os_path, mock_DataSync): exists_results = [True, False, False] def side_effect(arg): return exists_results.pop() data = Mock() mock_DataSync.return_value = data mock_os_path.side_effect = side_effect self.xml_state.profiles = ['profile_root'] self.setup.import_overlay_files() mock_DataSync.assert_called_once_with('description_dir/profile_root/', 'root_dir') data.sync_data.assert_called_once_with(options=[ '-r', '-p', '-t', '-D', '-H', '-X', '-A', '--one-file-system', '--links' ]) @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_keyboard_map(self, mock_path, mock_run, mock_shell): mock_path.return_value = True self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() mock_shell.assert_called_once_with( 'baseUpdateSysConfig', ['root_dir/etc/sysconfig/keyboard', 'KEYTABLE', '"keytable"']) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Shell.run_common_function') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_keyboard_map_with_systemd(self, mock_path, mock_run, mock_shell, mock_caps): mock_caps.return_value = True mock_path.return_value = True self.setup.preferences['keytable'] = 'keytable' self.setup.setup_keyboard_map() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/vconsole.conf']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--keymap=keytable' ]) ]) @patch('os.path.exists') def test_setup_keyboard_skipped(self, mock_exists): mock_exists.return_value = False self.setup.preferences['keytable'] = 'keytable' with self._caplog.at_level(logging.WARNING): self.setup.setup_keyboard_map() @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale(self, mock_path, mock_run, mock_caps): mock_caps.return_valure = True mock_path.return_value = True self.setup.preferences['locale'] = 'locale1,locale2' self.setup.setup_locale() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/locale.conf']), call([ 'chroot', 'root_dir', 'systemd-firstboot', '--locale=locale1.UTF-8' ]) ]) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') def test_setup_locale_POSIX(self, mock_path, mock_run, mock_caps): mock_caps.return_valure = True mock_path.return_value = True self.setup.preferences['locale'] = 'POSIX,locale2' self.setup.setup_locale() mock_run.assert_has_calls([ call(['rm', '-r', '-f', 'root_dir/etc/locale.conf']), call(['chroot', 'root_dir', 'systemd-firstboot', '--locale=POSIX']) ]) @patch('kiwi.system.setup.Command.run') def test_setup_timezone(self, mock_command): self.setup.preferences['timezone'] = 'timezone' self.setup.setup_timezone() mock_command.assert_has_calls([ call([ 'chroot', 'root_dir', 'ln', '-s', '-f', '/usr/share/zoneinfo/timezone', '/etc/localtime' ]) ]) @patch('kiwi.system.setup.CommandCapabilities.has_option_in_help') @patch('kiwi.system.setup.Command.run') def test_setup_timezone_with_systemd(self, mock_command, mock_caps): mock_caps.return_value = True self.setup.preferences['timezone'] = 'timezone' self.setup.setup_timezone() mock_command.assert_has_calls([ call([ 'chroot', 'root_dir', 'systemd-firstboot', '--timezone=timezone' ]) ]) @patch('kiwi.system.setup.Users') def test_setup_groups(self, mock_users): users = Mock() users.group_exists = Mock(return_value=False) mock_users.return_value = users self.setup_with_real_xml.setup_groups() calls = [call('users'), call('kiwi'), call('admin')] users.group_exists.assert_has_calls(calls) calls = [call('users', []), call('kiwi', []), call('admin', [])] users.group_add.assert_has_calls(calls) @patch('kiwi.system.setup.Users') @patch('kiwi.system.setup.Command.run') def test_setup_users_add(self, mock_command, mock_users): users = Mock() users.user_exists = Mock(return_value=False) mock_users.return_value = users mock_command.return_value = self.run_result self.setup_with_real_xml.setup_users() calls = [call('root'), call('tux'), call('kiwi')] users.user_exists.assert_has_calls(calls) calls = [ call('root', [ '-p', 'password-hash', '-s', '/bin/bash', '-u', '815', '-c', 'Bob', '-m', '-d', '/root' ]), call('tux', [ '-p', 'password-hash', '-g', 'users', '-m', '-d', '/home/tux' ]), call('kiwi', [ '-p', 'password-hash', '-g', 'kiwi', '-G', 'admin,users', '-m' ]) ] users.user_add.assert_has_calls(calls) mock_command.assert_called_with( ['openssl', 'passwd', '-1', '-salt', 'xyz', 'mypwd']) @patch('kiwi.system.setup.Users') @patch('kiwi.system.setup.Command.run') def test_setup_users_modify(self, mock_command, mock_users): users = Mock() users.user_exists = Mock(return_value=True) mock_users.return_value = users mock_command.return_value = self.run_result self.setup_with_real_xml.setup_users() calls = [call('root'), call('tux'), call('kiwi')] users.user_exists.assert_has_calls(calls) calls = [ call('root', [ '-p', 'password-hash', '-s', '/bin/bash', '-u', '815', '-c', 'Bob' ]), call('tux', ['-p', 'password-hash', '-g', 'users']), call('kiwi', ['-p', 'password-hash', '-g', 'kiwi', '-G', 'admin,users']) ] users.user_modify.assert_has_calls(calls) @patch('kiwi.system.setup.Path.which') @patch('kiwi.system.setup.Command.run') def test_setup_plymouth_splash(self, mock_command, mock_which): mock_which.return_value = 'plymouth-set-default-theme' preferences = Mock() preferences.get_bootsplash_theme = Mock(return_value=['some-theme']) self.xml_state.get_preferences_sections = Mock( return_value=[preferences]) self.setup.setup_plymouth_splash() mock_which.assert_called_once_with( root_dir='root_dir', filename='plymouth-set-default-theme') mock_command.assert_called_once_with( ['chroot', 'root_dir', 'plymouth-set-default-theme', 'some-theme']) @patch('os.path.exists') def test_import_image_identifier(self, mock_os_path): self.xml_state.xml_data.get_id = Mock(return_value='42') mock_os_path.return_value = True m_open = mock_open() with patch('builtins.open', m_open, create=True): self.setup.import_image_identifier() m_open.assert_called_once_with('root_dir/etc/ImageID', 'w') m_open.return_value.write.assert_called_once_with('42\n') @patch('kiwi.system.setup.Profile') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') @patch('copy.deepcopy') def test_call_non_excutable_config_script(self, mock_copy_deepcopy, mock_access, mock_stat, mock_os_path, mock_watch, mock_command, mock_Profile): mock_copy_deepcopy.return_value = {} profile = Mock() mock_Profile.return_value = profile profile.get_settings.return_value = {} result_type = namedtuple('result', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False self.setup.call_config_script() mock_copy_deepcopy.assert_called_once_with(os.environ) mock_command.assert_called_once_with( ['chroot', 'root_dir', 'bash', 'image/config.sh'], {}) @patch('kiwi.system.setup.Profile') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') @patch('copy.deepcopy') def test_call_excutable_config_script(self, mock_copy_deepcopy, mock_access, mock_stat, mock_os_path, mock_watch, mock_command, mock_Profile): mock_copy_deepcopy.return_value = {} profile = Mock() mock_Profile.return_value = profile profile.get_settings.return_value = {} result_type = namedtuple('result', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result # pretend that the script is executable mock_access.return_value = True self.setup.call_config_script() mock_copy_deepcopy.assert_called_once_with(os.environ) mock_command.assert_called_once_with( ['chroot', 'root_dir', 'image/config.sh'], {}) @patch('kiwi.system.setup.Profile') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') @patch('copy.deepcopy') def test_call_excutable_post_bootstrap_script(self, mock_copy_deepcopy, mock_access, mock_stat, mock_os_path, mock_watch, mock_command, mock_Profile): mock_copy_deepcopy.return_value = {} profile = Mock() mock_Profile.return_value = profile profile.get_settings.return_value = {} result_type = namedtuple('result', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result # pretend that the script is executable mock_access.return_value = True self.setup.call_post_bootstrap_script() mock_copy_deepcopy.assert_called_once_with(os.environ) mock_command.assert_called_once_with( ['chroot', 'root_dir', 'image/post_bootstrap.sh'], {}) @patch('kiwi.system.setup.Defaults.is_buildservice_worker') @patch('kiwi.logger.Logger.getLogLevel') @patch('kiwi.system.setup.Profile') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') @patch('copy.deepcopy') def test_call_disk_script(self, mock_copy_deepcopy, mock_access, mock_stat, mock_os_path, mock_watch, mock_command, mock_Profile, mock_getLogLevel, mock_is_buildservice_worker): mock_is_buildservice_worker.return_value = False mock_getLogLevel.return_value = logging.DEBUG mock_copy_deepcopy.return_value = {} profile = Mock() mock_Profile.return_value = profile profile.get_settings.return_value = {} result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False self.setup.call_disk_script() mock_copy_deepcopy.assert_called_once_with(os.environ) mock_command.assert_called_once_with([ 'screen', '-t', '-X', 'chroot', 'root_dir', 'bash', 'image/disk.sh' ], {}) @patch('kiwi.system.setup.Profile') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') @patch('copy.deepcopy') def test_call_image_script(self, mock_copy_deepcopy, mock_access, mock_stat, mock_os_path, mock_watch, mock_command, mock_Profile): mock_copy_deepcopy.return_value = {} profile = Mock() mock_Profile.return_value = profile profile.get_settings.return_value = {} result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False self.setup.call_image_script() mock_copy_deepcopy.assert_called_once_with(os.environ) mock_command.assert_called_once_with( ['chroot', 'root_dir', 'bash', 'image/images.sh'], {}) @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.path.abspath') def test_call_edit_boot_config_script(self, mock_abspath, mock_exists, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_exists.return_value = True mock_abspath.return_value = '/root_dir/image/edit_boot_config.sh' mock_watch.return_value = mock_result self.setup.call_edit_boot_config_script('ext4', 1) mock_abspath.assert_called_once_with( 'root_dir/image/edit_boot_config.sh') mock_command.assert_called_once_with([ 'bash', '-c', 'cd root_dir && bash --norc /root_dir/image/edit_boot_config.sh ' 'ext4 1' ]) @patch('kiwi.system.setup.Defaults.is_buildservice_worker') @patch('kiwi.logger.Logger.getLogLevel') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.path.abspath') def test_call_edit_boot_install_script(self, mock_abspath, mock_exists, mock_watch, mock_command, mock_getLogLevel, mock_is_buildservice_worker): mock_is_buildservice_worker.return_value = False mock_getLogLevel.return_value = logging.DEBUG result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=0) mock_exists.return_value = True mock_abspath.return_value = '/root_dir/image/edit_boot_install.sh' mock_watch.return_value = mock_result self.setup.call_edit_boot_install_script('my_image.raw', '/dev/mapper/loop0p1') mock_abspath.assert_called_once_with( 'root_dir/image/edit_boot_install.sh') mock_command.assert_called_once_with([ 'screen', '-t', '-X', 'bash', '-c', 'cd root_dir && bash --norc ' '/root_dir/image/edit_boot_install.sh ' 'my_image.raw /dev/mapper/loop0p1' ]) @patch('kiwi.system.setup.Profile') @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') @patch('os.stat') @patch('os.access') def test_call_image_script_raises(self, mock_access, mock_stat, mock_os_path, mock_watch, mock_command, mock_Profile): profile = Mock() mock_Profile.return_value = profile profile.get_settings.return_value = {} result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=1) mock_os_path.return_value = True mock_watch.return_value = mock_result mock_access.return_value = False with raises(KiwiScriptFailed): self.setup.call_image_script() @patch('kiwi.command.Command.call') @patch('kiwi.command_process.CommandProcess.poll_and_watch') @patch('os.path.exists') def test_call_edit_boot_install_script_raises(self, mock_os_path, mock_watch, mock_command): result_type = namedtuple('result_type', ['stderr', 'returncode']) mock_result = result_type(stderr='stderr', returncode=1) mock_os_path.return_value = True mock_watch.return_value = mock_result with raises(KiwiScriptFailed): self.setup.call_edit_boot_install_script('my_image.raw', '/dev/mapper/loop0p1') @patch('kiwi.command.Command.run') def test_create_init_link_from_linuxrc(self, mock_command): self.setup.create_init_link_from_linuxrc() mock_command.assert_called_once_with( ['ln', 'root_dir/linuxrc', 'root_dir/init']) @patch('kiwi.command.Command.run') def test_create_recovery_archive_cleanup_only(self, mock_command): self.setup.oemconfig['recovery'] = False self.setup.create_recovery_archive() assert mock_command.call_args_list[0] == call( ['bash', '-c', 'rm -f root_dir/recovery.*']) @patch('os.path.exists') @patch('kiwi.system.setup.Path.wipe') @patch('kiwi.command.Command.run') def test_create_fstab(self, mock_command, mock_wipe, mock_exists): fstab = Mock() mock_exists.return_value = True m_open = mock_open(read_data='append_entry') with patch('builtins.open', m_open, create=True): self.setup.create_fstab(fstab) fstab.export.assert_called_once_with('root_dir/etc/fstab') assert m_open.call_args_list == [ call('root_dir/etc/fstab', 'a'), call('root_dir/etc/fstab.append', 'r') ] assert m_open.return_value.write.call_args_list == [ call('append_entry') ] assert mock_command.call_args_list == [ call(['patch', 'root_dir/etc/fstab', 'root_dir/etc/fstab.patch']), call(['chroot', 'root_dir', '/etc/fstab.script']) ] assert mock_wipe.call_args_list == [ call('root_dir/etc/fstab.append'), call('root_dir/etc/fstab.patch'), call('root_dir/etc/fstab.script') ] @patch('kiwi.command.Command.run') @patch('pathlib.Path.touch') @patch('kiwi.system.setup.ArchiveTar') @patch('kiwi.system.setup.Compress') @patch('os.path.getsize') @patch('kiwi.system.setup.Path.wipe') def test_create_recovery_archive(self, mock_wipe, mock_getsize, mock_compress, mock_archive, mock_pathlib_Path_touch, mock_command): mock_getsize.return_value = 42 compress = Mock() mock_compress.return_value = compress archive = Mock() mock_archive.return_value = archive self.setup.oemconfig['recovery'] = True self.setup.oemconfig['recovery_inplace'] = True m_open = mock_open() with patch('builtins.open', m_open, create=True): self.setup.create_recovery_archive() assert mock_command.call_args_list[0] == call( ['bash', '-c', 'rm -f root_dir/recovery.*']) mock_archive.assert_called_once_with(create_from_file_list=False, filename='root_dir/recovery.tar') archive.create.assert_called_once_with(exclude=['dev', 'proc', 'sys'], options=[ '--numeric-owner', '--hard-dereference', '--preserve-permissions' ], source_dir='root_dir') assert m_open.call_args_list[0] == call( 'root_dir/recovery.tar.filesystem', 'w') assert m_open.return_value.write.call_args_list[0] == call('ext3') assert mock_command.call_args_list[1] == call( ['bash', '-c', 'tar -tf root_dir/recovery.tar | wc -l']) assert m_open.call_args_list[1] == call('root_dir/recovery.tar.files', 'w') assert mock_getsize.call_args_list[0] == call('root_dir/recovery.tar') assert m_open.return_value.write.call_args_list[1] == call('1\n') assert m_open.call_args_list[2] == call('root_dir/recovery.tar.size', 'w') assert m_open.return_value.write.call_args_list[2] == call('42') mock_compress.assert_called_once_with('root_dir/recovery.tar') compress.gzip.assert_called_once_with() assert mock_getsize.call_args_list[1] == call( 'root_dir/recovery.tar.gz') assert m_open.call_args_list[3] == call( 'root_dir/recovery.partition.size', 'w') assert m_open.return_value.write.call_args_list[3] == call('300') mock_wipe.assert_called_once_with('root_dir/recovery.tar.gz') @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.Path.create') @patch('kiwi.system.setup.DataSync') @patch('os.path.exists') def test_export_modprobe_setup(self, mock_exists, mock_DataSync, mock_path, mock_command): data = Mock() mock_DataSync.return_value = data mock_exists.return_value = True self.setup.export_modprobe_setup('target_root_dir') mock_path.assert_called_once_with('target_root_dir/etc') mock_DataSync.assert_called_once_with('root_dir/etc/modprobe.d', 'target_root_dir/etc/') data.sync_data.assert_called_once_with(options=['-a']) @patch('kiwi.defaults.Defaults.get_default_packager_tool') def test_export_package_list_unknown_packager( self, mock_get_default_packager_tool): assert self.setup.export_package_list('target_dir') == '' @patch('kiwi.defaults.Defaults.get_default_packager_tool') def test_export_package_changes_unknown_packager( self, mock_get_default_packager_tool): assert self.setup.export_package_changes('target_dir') == '' @patch('kiwi.defaults.Defaults.get_default_packager_tool') def test_export_package_verification_unknown_packager( self, mock_get_default_packager_tool): assert self.setup.export_package_verification('target_dir') == '' @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.RpmDataBase') @patch('kiwi.system.setup.MountManager') def test_export_package_list_rpm(self, mock_MountManager, mock_RpmDataBase, mock_command): rpmdb = Mock() rpmdb.rpmdb_image.expand_query.return_value = 'image_dbpath' rpmdb.rpmdb_host.expand_query.return_value = 'host_dbpath' rpmdb.has_rpm.return_value = True mock_RpmDataBase.return_value = rpmdb command = Mock() command.output = 'packages_data' mock_command.return_value = command with patch('builtins.open') as m_open: result = self.setup.export_package_list('target_dir') m_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w', encoding='utf-8') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|' '%{DISTURL}|%{LICENSE}\\n', '--dbpath', 'image_dbpath' ]) rpmdb.has_rpm.return_value = False mock_command.reset_mock() with patch('builtins.open'): result = self.setup.export_package_list('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|' '%{DISTURL}|%{LICENSE}\\n', '--dbpath', 'host_dbpath' ]) @patch('kiwi.system.setup.os.path.exists') def test_setup_machine_id(self, mock_path_exists): mock_path_exists.return_value = True with patch('builtins.open') as m_open: self.setup.setup_machine_id() m_open.assert_called_once_with('root_dir/etc/machine-id', 'w') mock_path_exists.return_value = False self.setup.setup_machine_id() @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.Path.which') def test_setup_permissions(self, mock_path_which, mock_command): mock_path_which.return_value = 'chkstat' self.setup.setup_permissions() mock_command.assert_called_once_with( ['chroot', 'root_dir', 'chkstat', '--system', '--set']) mock_path_which.return_value = None with self._caplog.at_level(logging.WARNING): self.setup.setup_permissions() @patch('kiwi.system.setup.Command.run') def test_export_package_list_dpkg(self, mock_command): command = Mock() command.output = 'packages_data' mock_command.return_value = command self.xml_state.get_package_manager = Mock(return_value='apt') with patch('builtins.open') as m_open: result = self.setup.export_package_list('target_dir') m_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w', encoding='utf-8') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with([ 'dpkg-query', '--admindir', 'root_dir/var/lib/dpkg', '-W', '-f', '${Package}|None|${Version}|None|${Architecture}|None|None\\n' ]) @patch('kiwi.system.setup.Command.run') def test_export_package_list_pacman(self, mock_command): command = Mock() command.output = 'packages_data' mock_command.return_value = command self.xml_state.get_package_manager = Mock(return_value='pacman') with patch('builtins.open') as m_open: result = self.setup.export_package_list('target_dir') m_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.packages', 'w') assert result == 'target_dir/some-image.x86_64-1.2.3.packages' mock_command.assert_called_once_with( ['pacman', '--query', '--dbpath', 'root_dir/var/lib/pacman']) @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.RpmDataBase') @patch('kiwi.system.setup.MountManager') def test_export_package_changes_rpm(self, mock_MountManager, mock_RpmDataBase, mock_command): rpmdb = Mock() rpmdb.rpmdb_image.expand_query.return_value = 'image_dbpath' rpmdb.rpmdb_host.expand_query.return_value = 'host_dbpath' rpmdb.has_rpm.return_value = True mock_RpmDataBase.return_value = rpmdb command = Mock() command.output = 'package|\nchanges' mock_command.return_value = command with patch('builtins.open', create=True) as mock_open: mock_open.return_value = MagicMock(spec=io.IOBase) result = self.setup.export_package_changes('target_dir') mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.changes', 'w', encoding='utf-8') assert result == 'target_dir/some-image.x86_64-1.2.3.changes' mock_command.assert_called_once_with([ 'rpm', '--root', 'root_dir', '-qa', '--qf', '%{NAME}|\\n', '--changelog', '--dbpath', 'image_dbpath' ]) self.runtime_config.get_package_changes.assert_called_once_with() @patch('kiwi.system.setup.Command.run') @patch('os.path.exists') @patch('os.listdir') def test_export_package_changes_dpkg(self, mock_os_listdir, mock_os_path_exists, mock_command): command = Mock() command.output = 'changes' mock_command.return_value = command self.xml_state.get_package_manager = Mock(return_value='apt') mock_os_listdir.return_value = ['package_b', 'package_a'] mock_os_path_exists.return_value = True with patch('builtins.open', create=True) as mock_open: mock_open.return_value = MagicMock(spec=io.IOBase) result = self.setup.export_package_changes('target_dir') file_handle = mock_open.return_value.__enter__.return_value mock_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.changes', 'w', encoding='utf-8') assert result == 'target_dir/some-image.x86_64-1.2.3.changes' assert file_handle.write.call_args_list == [ call('package_a|\n'), call('changes\n'), call('package_b|\n'), call('changes\n') ] self.runtime_config.get_package_changes.assert_called_once_with() @patch('kiwi.system.setup.Command.run') @patch('kiwi.system.setup.RpmDataBase') @patch('kiwi.system.setup.MountManager') def test_export_package_verification(self, mock_MountManager, mock_RpmDataBase, mock_command): is_mounted_return = [True, False] def is_mounted(): return is_mounted_return.pop() shared_mount = Mock() shared_mount.is_mounted.side_effect = is_mounted mock_MountManager.return_value = shared_mount rpmdb = Mock() rpmdb.rpmdb_image.expand_query.return_value = 'image_dbpath' rpmdb.rpmdb_host.expand_query.return_value = 'host_dbpath' rpmdb.has_rpm.return_value = True mock_RpmDataBase.return_value = rpmdb command = Mock() command.output = 'verification_data' mock_command.return_value = command with patch('builtins.open') as m_open: result = self.setup.export_package_verification('target_dir') m_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w', encoding='utf-8') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with(command=[ 'rpm', '--root', 'root_dir', '-Va', '--dbpath', 'image_dbpath' ], raise_on_error=False) mock_MountManager.assert_called_once_with(device='/dev', mountpoint='root_dir/dev') shared_mount.bind_mount.assert_called_once_with() shared_mount.umount_lazy.assert_called_once_with() rpmdb.has_rpm.return_value = False is_mounted_return = [True, False] mock_command.reset_mock() shared_mount.reset_mock() with patch('builtins.open'): result = self.setup.export_package_verification('target_dir') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with(command=[ 'rpm', '--root', 'root_dir', '-Va', '--dbpath', 'host_dbpath' ], raise_on_error=False) shared_mount.bind_mount.assert_called_once_with() shared_mount.umount_lazy.assert_called_once_with() @patch('kiwi.system.setup.Command.run') def test_export_package_verification_dpkg(self, mock_command): command = Mock() command.output = 'verification_data' mock_command.return_value = command self.xml_state.get_package_manager = Mock(return_value='apt') with patch('builtins.open') as m_open: result = self.setup.export_package_verification('target_dir') m_open.assert_called_once_with( 'target_dir/some-image.x86_64-1.2.3.verified', 'w', encoding='utf-8') assert result == 'target_dir/some-image.x86_64-1.2.3.verified' mock_command.assert_called_once_with(command=[ 'dpkg', '--root', 'root_dir', '-V', '--verify-format', 'rpm' ], raise_on_error=False) @patch('kiwi.system.setup.Command.run') def test_set_selinux_file_contexts(self, mock_command): self.setup.set_selinux_file_contexts('security_context_file') mock_command.assert_called_once_with([ 'chroot', 'root_dir', 'setfiles', 'security_context_file', '/', '-v' ]) @patch('kiwi.system.setup.Repository.new') @patch('kiwi.system.setup.Uri') def test_import_repositories_marked_as_imageinclude( self, mock_uri, mock_repo): uri = Mock() mock_uri.return_value = uri uri.translate = Mock(return_value="uri") uri.alias = Mock(return_value="uri-alias") uri.credentials_file_name = Mock(return_value='kiwiRepoCredentials') mock_uri.return_value = uri repo = Mock() mock_repo.return_value = repo self.setup_with_real_xml.import_repositories_marked_as_imageinclude() assert repo.add_repo.call_args_list[0] == call( 'uri-alias', 'uri', 'rpm-md', None, None, None, None, None, 'kiwiRepoCredentials', None, None, None, False, '../data/script') @patch('os.path.exists') def test_script_exists(self, mock_path_exists): assert self.setup.script_exists('some-script') == \ mock_path_exists.return_value
def process(self): # noqa: C901 """ Build a system image from the specified description. The build command combines the prepare and create commands """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() abs_target_dir_path = os.path.abspath( self.command_args['--target-dir'] ) build_dir = os.sep.join([abs_target_dir_path, 'build']) image_root = os.sep.join([build_dir, 'image-root']) Path.create(build_dir) if not self.global_args['--logfile']: log.set_logfile( os.sep.join([abs_target_dir_path, 'build', 'image-root.log']) ) self.load_xml_description( self.command_args['--description'] ) build_checks = self.checks_before_command_args build_checks.update( { 'check_target_directory_not_in_shared_cache': [abs_target_dir_path] } ) self.run_checks(build_checks) if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo']) ) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository( *self.sextuple_token(add_repo) ) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag'] ) if self.command_args['--add-container-label']: for add_label in self.command_args['--add-container-label']: try: (name, value) = add_label.split('=', 1) self.xml_state.add_container_config_label(name, value) except Exception: log.warning( 'Container label {0} ignored. Invalid format: ' 'expected labelname=value'.format(add_label) ) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from'] ) self.run_checks(self.checks_after_command_args) log.info('Preparing new root system') system = SystemPrepare( self.xml_state, image_root, self.command_args['--allow-existing-root'] ) manager = system.setup_repositories( self.command_args['--clear-cache'], self.command_args['--signing-key'] ) system.install_bootstrap( manager, self.command_args['--add-bootstrap-package'] ) system.install_system( manager ) if self.command_args['--add-package']: system.install_packages( manager, self.command_args['--add-package'] ) if self.command_args['--delete-package']: system.delete_packages( manager, self.command_args['--delete-package'] ) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) profile.create( Defaults.get_profile_file(image_root) ) setup = SystemSetup( self.xml_state, image_root ) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() setup.setup_permissions() # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # handle uninstall package requests, gracefully uninstall # with dependency cleanup system.pinch_system(force=False) # handle delete package requests, forced uninstall without # any dependency resolution system.pinch_system(force=True) # delete any custom rpm macros created system.clean_package_manager_leftovers() # make sure system instance is cleaned up now del system setup.call_image_script() # make sure setup instance is cleaned up now del setup log.info('Creating system image') image_builder = ImageBuilder.new( self.xml_state, abs_target_dir_path, image_root, custom_args={ 'signing_keys': self.command_args['--signing-key'], 'xz_options': self.runtime_config.get_xz_options() } ) result = image_builder.create() result.print_results() result.dump( os.sep.join([abs_target_dir_path, 'kiwi.result']) )
def process(self): """ Build a system image from the specified description. The build command combines the prepare and create commands """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() abs_target_dir_path = os.path.abspath( self.command_args['--target-dir'] ) build_dir = os.sep.join([abs_target_dir_path, 'build']) image_root = os.sep.join([build_dir, 'image-root']) Path.create(build_dir) if not self.global_args['--logfile']: log.set_logfile( os.sep.join([abs_target_dir_path, 'build', 'image-root.log']) ) self.load_xml_description( self.command_args['--description'] ) self.runtime_checker.check_efi_mode_for_disk_overlay_correctly_setup() self.runtime_checker.check_consistent_kernel_in_boot_and_system_image() self.runtime_checker.check_docker_tool_chain_installed() self.runtime_checker.check_volume_setup_has_no_root_definition() self.runtime_checker.check_xen_uniquely_setup_as_server_or_guest() self.runtime_checker.check_target_directory_not_in_shared_cache( abs_target_dir_path ) self.runtime_checker.check_mediacheck_only_for_x86_arch() self.runtime_checker.check_dracut_module_for_live_iso_in_package_list() self.runtime_checker.check_dracut_module_for_disk_overlay_in_package_list() if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.quintuple_token(self.command_args['--set-repo']) ) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository( *self.quintuple_token(add_repo) ) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag'] ) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from'] ) self.runtime_checker.check_repositories_configured() self.runtime_checker.check_image_include_repos_publicly_resolvable() package_requests = False if self.command_args['--add-package']: package_requests = True if self.command_args['--delete-package']: package_requests = True log.info('Preparing new root system') system = SystemPrepare( self.xml_state, image_root, self.command_args['--allow-existing-root'] ) manager = system.setup_repositories( self.command_args['--clear-cache'], self.command_args['--signing-key'] ) system.install_bootstrap(manager) system.install_system( manager ) if package_requests: if self.command_args['--add-package']: system.install_packages( manager, self.command_args['--add-package'] ) if self.command_args['--delete-package']: system.delete_packages( manager, self.command_args['--delete-package'] ) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) setup = SystemSetup( self.xml_state, image_root ) setup.import_shell_environment(profile) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() system.pinch_system( manager=manager, force=True ) # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # make sure system instance is cleaned up now del system setup.call_image_script() # make sure setup instance is cleaned up now del setup log.info('Creating system image') image_builder = ImageBuilder( self.xml_state, abs_target_dir_path, image_root, custom_args={ 'signing_keys': self.command_args['--signing-key'], 'xz_options': self.runtime_config.get_xz_options() } ) result = image_builder.create() result.print_results() result.dump( os.sep.join([abs_target_dir_path, 'kiwi.result']) )
def process(self): # noqa: C901 """ Prepare and install a new system for chroot access """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() self.load_xml_description( self.command_args['--description'] ) abs_root_path = os.path.abspath(self.command_args['--root']) self.runtime_checker.check_efi_mode_for_disk_overlay_correctly_setup() self.runtime_checker.check_grub_efi_installed_for_efi_firmware() self.runtime_checker.check_boot_description_exists() self.runtime_checker.check_consistent_kernel_in_boot_and_system_image() self.runtime_checker.check_docker_tool_chain_installed() self.runtime_checker.check_volume_setup_has_no_root_definition() self.runtime_checker.check_xen_uniquely_setup_as_server_or_guest() self.runtime_checker.check_target_directory_not_in_shared_cache( abs_root_path ) self.runtime_checker.check_mediacheck_only_for_x86_arch() self.runtime_checker.check_dracut_module_for_live_iso_in_package_list() self.runtime_checker.check_dracut_module_for_disk_overlay_in_package_list() self.runtime_checker.check_dracut_module_for_disk_oem_in_package_list() self.runtime_checker.check_dracut_module_for_oem_install_in_package_list() if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo']) ) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository( *self.sextuple_token(add_repo) ) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag'] ) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from'] ) self.runtime_checker.check_repositories_configured() self.runtime_checker.check_image_include_repos_publicly_resolvable() package_requests = False if self.command_args['--add-package']: package_requests = True if self.command_args['--delete-package']: package_requests = True log.info('Preparing system') system = SystemPrepare( self.xml_state, abs_root_path, self.command_args['--allow-existing-root'] ) manager = system.setup_repositories( self.command_args['--clear-cache'], self.command_args['--signing-key'] ) system.install_bootstrap(manager) system.install_system( manager ) if package_requests: if self.command_args['--add-package']: system.install_packages( manager, self.command_args['--add-package'] ) if self.command_args['--delete-package']: system.delete_packages( manager, self.command_args['--delete-package'] ) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) setup = SystemSetup( self.xml_state, abs_root_path ) setup.import_shell_environment(profile) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() system.pinch_system( manager=manager, force=True ) # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # make sure system instance is cleaned up now del system
def process(self): # noqa: C901 """ Build a system image from the specified description. The build command combines the prepare and create commands """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() abs_target_dir_path = os.path.abspath( self.command_args['--target-dir'] ) build_dir = os.sep.join([abs_target_dir_path, 'build']) image_root = os.sep.join([build_dir, 'image-root']) Path.create(build_dir) if not self.global_args['--logfile']: log.set_logfile( os.sep.join([abs_target_dir_path, 'build', 'image-root.log']) ) self.load_xml_description( self.command_args['--description'] ) self.runtime_checker.check_efi_mode_for_disk_overlay_correctly_setup() self.runtime_checker.check_boot_description_exists() self.runtime_checker.check_consistent_kernel_in_boot_and_system_image() self.runtime_checker.check_docker_tool_chain_installed() self.runtime_checker.check_volume_setup_has_no_root_definition() self.runtime_checker.check_xen_uniquely_setup_as_server_or_guest() self.runtime_checker.check_target_directory_not_in_shared_cache( abs_target_dir_path ) self.runtime_checker.check_mediacheck_only_for_x86_arch() self.runtime_checker.check_dracut_module_for_live_iso_in_package_list() self.runtime_checker.check_dracut_module_for_disk_overlay_in_package_list() self.runtime_checker.check_dracut_module_for_disk_oem_in_package_list() self.runtime_checker.check_dracut_module_for_oem_install_in_package_list() if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo']) ) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository( *self.sextuple_token(add_repo) ) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag'] ) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from'] ) self.runtime_checker.check_repositories_configured() self.runtime_checker.check_image_include_repos_publicly_resolvable() log.info('Preparing new root system') system = SystemPrepare( self.xml_state, image_root, self.command_args['--allow-existing-root'] ) manager = system.setup_repositories( self.command_args['--clear-cache'], self.command_args['--signing-key'] ) system.install_bootstrap(manager) system.install_system( manager ) if self.command_args['--add-package']: system.install_packages( manager, self.command_args['--add-package'] ) if self.command_args['--delete-package']: system.delete_packages( manager, self.command_args['--delete-package'] ) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) setup = SystemSetup( self.xml_state, image_root ) setup.import_shell_environment(profile) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # handle uninstall package requests, gracefully uninstall # with dependency cleanup system.pinch_system(force=False) # handle delete package requests, forced uninstall without # any dependency resolution system.pinch_system(force=True) # make sure system instance is cleaned up now del system setup.call_image_script() # make sure setup instance is cleaned up now del setup log.info('Creating system image') image_builder = ImageBuilder( self.xml_state, abs_target_dir_path, image_root, custom_args={ 'signing_keys': self.command_args['--signing-key'], 'xz_options': self.runtime_config.get_xz_options() } ) result = image_builder.create() result.print_results() result.dump( os.sep.join([abs_target_dir_path, 'kiwi.result']) )
def process(self): """ Prepare and install a new system for chroot access """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() self.load_xml_description(self.command_args['--description'], self.global_args['--kiwi-file']) abs_root_path = os.path.abspath(self.command_args['--root']) prepare_checks = self.checks_before_command_args prepare_checks.update( {'check_target_directory_not_in_shared_cache': [abs_root_path]}) self.run_checks(prepare_checks) if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo'])) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository(*self.sextuple_token(add_repo)) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag']) if self.command_args['--add-container-label']: for add_label in self.command_args['--add-container-label']: try: (name, value) = add_label.split('=', 1) self.xml_state.add_container_config_label(name, value) except Exception: log.warning('Container label {0} ignored. Invalid format: ' 'expected labelname=value'.format(add_label)) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from']) self.run_checks(self.checks_after_command_args) log.info('Preparing system') system = SystemPrepare(self.xml_state, abs_root_path, self.command_args['--allow-existing-root']) manager = system.setup_repositories( self.command_args['--clear-cache'], self.command_args['--signing-key'] + self.xml_state.get_repositories_signing_keys(), self.global_args['--target-arch']) run_bootstrap = True if self.xml_state.get_package_manager() == 'apt' and \ self.command_args['--allow-existing-root']: # try to call apt-get inside of the existing root. # If the call succeeds we skip calling debootstrap again # and assume the root to be ok to proceed with apt-get # if it fails, treat the root as dirty and give the # bootstrap a try try: Command.run(['chroot', abs_root_path, 'apt-get', '--version']) run_bootstrap = False log.warning('debootstrap will only be called once, skipped') except Exception: run_bootstrap = True if run_bootstrap: system.install_bootstrap( manager, self.command_args['--add-bootstrap-package']) setup = SystemSetup(self.xml_state, abs_root_path) setup.import_description() # call post_bootstrap.sh script if present setup.call_post_bootstrap_script() system.install_system(manager) if self.command_args['--add-package']: system.install_packages(manager, self.command_args['--add-package']) if self.command_args['--delete-package']: system.delete_packages(manager, self.command_args['--delete-package']) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) profile.create(Defaults.get_profile_file(abs_root_path)) setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() setup.setup_permissions() # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() # call config.sh script if present setup.call_config_script() # handle uninstall package requests, gracefully uninstall # with dependency cleanup system.pinch_system(force=False) # handle delete package requests, forced uninstall without # any dependency resolution system.pinch_system(force=True) # delete any custom rpm macros created system.clean_package_manager_leftovers() # make sure system instance is cleaned up now del system
def process(self): # noqa: C901 """ Build a system image from the specified description. The build command combines the prepare and create commands """ self.manual = Help() if self._help(): return Privileges.check_for_root_permissions() abs_target_dir_path = os.path.abspath( self.command_args['--target-dir'] ) build_dir = os.sep.join([abs_target_dir_path, 'build']) image_root = os.sep.join([build_dir, 'image-root']) Path.create(build_dir) if not self.global_args['--logfile']: log.set_logfile( os.sep.join([abs_target_dir_path, 'build', 'image-root.log']) ) self.load_xml_description( self.command_args['--description'] ) self.runtime_checker.check_minimal_required_preferences() self.runtime_checker.check_efi_mode_for_disk_overlay_correctly_setup() self.runtime_checker.check_boot_description_exists() self.runtime_checker.check_consistent_kernel_in_boot_and_system_image() self.runtime_checker.check_docker_tool_chain_installed() self.runtime_checker.check_volume_setup_defines_multiple_fullsize_volumes() self.runtime_checker.check_volume_setup_has_no_root_definition() self.runtime_checker.check_volume_label_used_with_lvm() self.runtime_checker.check_xen_uniquely_setup_as_server_or_guest() self.runtime_checker.check_target_directory_not_in_shared_cache( abs_target_dir_path ) self.runtime_checker.check_mediacheck_only_for_x86_arch() self.runtime_checker.check_dracut_module_for_live_iso_in_package_list() self.runtime_checker.check_dracut_module_for_disk_overlay_in_package_list() self.runtime_checker.check_dracut_module_for_disk_oem_in_package_list() self.runtime_checker.check_dracut_module_for_oem_install_in_package_list() if self.command_args['--ignore-repos']: self.xml_state.delete_repository_sections() elif self.command_args['--ignore-repos-used-for-build']: self.xml_state.delete_repository_sections_used_for_build() if self.command_args['--set-repo']: self.xml_state.set_repository( *self.sextuple_token(self.command_args['--set-repo']) ) if self.command_args['--add-repo']: for add_repo in self.command_args['--add-repo']: self.xml_state.add_repository( *self.sextuple_token(add_repo) ) if self.command_args['--set-container-tag']: self.xml_state.set_container_config_tag( self.command_args['--set-container-tag'] ) if self.command_args['--add-container-label']: for add_label in self.command_args['--add-container-label']: try: (name, value) = add_label.split('=', 1) self.xml_state.add_container_config_label(name, value) except Exception: log.warning( 'Container label {0} ignored. Invalid format: ' 'expected labelname=value'.format(add_label) ) if self.command_args['--set-container-derived-from']: self.xml_state.set_derived_from_image_uri( self.command_args['--set-container-derived-from'] ) self.runtime_checker.check_repositories_configured() self.runtime_checker.check_image_include_repos_publicly_resolvable() log.info('Preparing new root system') system = SystemPrepare( self.xml_state, image_root, self.command_args['--allow-existing-root'] ) manager = system.setup_repositories( self.command_args['--clear-cache'], self.command_args['--signing-key'] ) system.install_bootstrap(manager) system.install_system( manager ) if self.command_args['--add-package']: system.install_packages( manager, self.command_args['--add-package'] ) if self.command_args['--delete-package']: system.delete_packages( manager, self.command_args['--delete-package'] ) profile = Profile(self.xml_state) defaults = Defaults() defaults.to_profile(profile) setup = SystemSetup( self.xml_state, image_root ) setup.import_shell_environment(profile) setup.import_description() setup.import_overlay_files() setup.import_image_identifier() setup.setup_groups() setup.setup_users() setup.setup_keyboard_map() setup.setup_locale() setup.setup_plymouth_splash() setup.setup_timezone() setup.setup_permissions() # make sure manager instance is cleaned up now del manager # setup permanent image repositories after cleanup setup.import_repositories_marked_as_imageinclude() setup.call_config_script() # handle uninstall package requests, gracefully uninstall # with dependency cleanup system.pinch_system(force=False) # handle delete package requests, forced uninstall without # any dependency resolution system.pinch_system(force=True) # delete any custom rpm macros created Rpm( image_root, Defaults.get_custom_rpm_image_macro_name() ).wipe_config() # make sure system instance is cleaned up now del system setup.call_image_script() # make sure setup instance is cleaned up now del setup log.info('Creating system image') image_builder = ImageBuilder( self.xml_state, abs_target_dir_path, image_root, custom_args={ 'signing_keys': self.command_args['--signing-key'], 'xz_options': self.runtime_config.get_xz_options() } ) result = image_builder.create() result.print_results() result.dump( os.sep.join([abs_target_dir_path, 'kiwi.result']) )