예제 #1
0
파일: apt.py 프로젝트: rabueker/kiwi
    def process_install_requests_bootstrap(self,
                                           root_bind: RootBind = None
                                           ) -> command_call_type:
        """
        Process package install requests for bootstrap phase (no chroot)
        The debootstrap program is used to bootstrap a new system with
        a collection of predefined packages. The kiwi bootstrap section
        information is not used in this case

        :param object root_bind: instance of RootBind to manage kernel
            file systems before debootstrap call

        :raises KiwiDebootstrapError: if no main distribution repository
            is configured, if the debootstrap script is not found or if the
            debootstrap script execution fails
        :return: process results in command type
        :rtype: namedtuple
        """
        if not self.distribution:
            raise KiwiDebootstrapError(
                'No main distribution repository is configured')
        bootstrap_script = '/usr/share/debootstrap/scripts/' + \
            self.distribution
        if not os.path.exists(bootstrap_script):
            raise KiwiDebootstrapError(
                'debootstrap script for %s distribution not found' %
                self.distribution)

        # APT package manager does not support bootstrapping. To circumvent
        # this limitation there is the debootstrap tool for APT based distros.
        # Because of that there is a little overlap between KIWI and
        # debootstrap. Debootstrap manages itself the kernel file systems for
        # chroot environment, thus we need to umount the kernel file systems
        # before calling debootstrap and remount them afterwards.
        if root_bind:
            root_bind.umount_kernel_file_systems()

        # debootsrap will create its own dev/fd devices
        debootstrap_device_node_conflicts = ['dev/fd', 'dev/pts']
        for node in debootstrap_device_node_conflicts:
            Path.wipe(os.path.normpath(os.sep.join([self.root_dir, node])))

        if 'apt' in self.package_requests:
            # debootstrap takes care to install apt
            self.package_requests.remove('apt')
        try:
            cmd = ['debootstrap']
            if self.repository.unauthenticated == 'false' and \
               os.path.exists(self.repository.keyring):
                cmd.append('--keyring={}'.format(self.repository.keyring))
            else:
                cmd.append('--no-check-gpg')
            if self.deboostrap_minbase:
                cmd.append('--variant=minbase')
            if self.package_requests:
                cmd.append('--include={}'.format(','.join(
                    self.package_requests)))
            if self.repository.components:
                cmd.append('--components={0}'.format(','.join(
                    self.repository.components)))
            self.cleanup_requests()
            cmd.extend(
                [self.distribution, self.root_dir, self.distribution_path])

            return Command.call(cmd, self.command_env)
        except Exception as e:
            raise KiwiDebootstrapError('%s: %s' %
                                       (type(e).__name__, format(e)))
예제 #2
0
class TestRootBind:
    @fixture(autouse=True)
    def inject_fixtures(self, caplog):
        self._caplog = caplog

    def setup(self):
        root = Mock()
        root.root_dir = 'root-dir'
        self.bind_root = RootBind(root)

        # stub config files and bind locations
        self.bind_root.config_files = ['/etc/sysconfig/proxy']
        self.bind_root.bind_locations = ['/proc']

        # stub files/dirs and mountpoints to cleanup
        self.mount_manager = Mock()
        self.bind_root.cleanup_files = ['/etc/sysconfig/proxy.kiwi']
        self.bind_root.mount_stack = [self.mount_manager]
        self.bind_root.dir_stack = ['/mountpoint']

    def teardown(self):
        sys.argv = argv_kiwi_tests

    @patch('kiwi.system.root_bind.MountManager.bind_mount')
    @patch('kiwi.system.root_bind.RootBind.cleanup')
    @patch('os.path.exists')
    def test_kernel_file_systems_raises_error(self, mock_exists, mock_cleanup,
                                              mock_mount):
        mock_exists.return_value = True
        mock_mount.side_effect = KiwiMountKernelFileSystemsError('mount-error')
        with raises(KiwiMountKernelFileSystemsError):
            self.bind_root.mount_kernel_file_systems()
        mock_cleanup.assert_called_once_with()

    @patch('kiwi.system.root_bind.MountManager.bind_mount')
    @patch('kiwi.system.root_bind.Path.create')
    @patch('kiwi.system.root_bind.RootBind.cleanup')
    def test_shared_directory_raises_error(self, mock_cleanup, mock_path,
                                           mock_mount):
        mock_mount.side_effect = KiwiMountSharedDirectoryError('mount-error')
        with raises(KiwiMountSharedDirectoryError):
            self.bind_root.mount_shared_directory()
        mock_cleanup.assert_called_once_with()

    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.RootBind.cleanup')
    @patch('os.path.exists')
    def test_intermediate_config_raises_error(self, mock_exists, mock_cleanup,
                                              mock_command):
        mock_exists.return_value = True
        mock_command.side_effect = KiwiSetupIntermediateConfigError(
            'config-error')
        with raises(KiwiSetupIntermediateConfigError):
            self.bind_root.setup_intermediate_config()
        mock_cleanup.assert_called_once_with()

    @patch('kiwi.system.root_bind.os.path.exists')
    @patch('kiwi.system.root_bind.MountManager')
    def test_mount_kernel_file_systems(self, mock_mount, mock_exists):
        mock_exists.return_value = True
        shared_mount = Mock()
        mock_mount.return_value = shared_mount
        self.bind_root.mount_kernel_file_systems()
        mock_mount.assert_called_once_with(device='/proc',
                                           mountpoint='root-dir/proc')
        shared_mount.bind_mount.assert_called_once_with()

    @patch('kiwi.system.root_bind.MountManager')
    def test_umount_kernel_file_systems(self, mock_mount):
        self.mount_manager.device = '/proc'
        self.mount_manager.is_mounted = Mock(return_value=True)
        self.bind_root.umount_kernel_file_systems()
        self.mount_manager.umount_lazy.assert_called_once_with()
        assert self.bind_root.mount_stack == []

    @patch('kiwi.system.root_bind.MountManager')
    def test_umount_kernel_file_systems_raises_error(self, mock_mount):
        self.mount_manager.device = '/proc'
        self.mount_manager.is_mounted = Mock(return_value=True)
        self.mount_manager.umount_lazy = Mock(side_effect=Exception)
        self.bind_root.umount_kernel_file_systems()
        self.mount_manager.umount_lazy.assert_called_once_with()
        assert self.bind_root.mount_stack == [self.mount_manager]

    @patch('kiwi.system.root_bind.MountManager')
    @patch('kiwi.system.root_bind.Path.create')
    def test_mount_shared_directory(self, mock_path, mock_mount):
        shared_mount = Mock()
        mock_mount.return_value = shared_mount
        self.bind_root.mount_shared_directory()
        mock_path.call_args_list = [
            call('root-dir/var/cache/kiwi'),
            call('/var/cache/kiwi')
        ]
        mock_mount.assert_called_once_with(
            device='/var/cache/kiwi', mountpoint='root-dir/var/cache/kiwi')
        shared_mount.bind_mount.assert_called_once_with()

    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Checksum')
    @patch('os.path.exists')
    def test_intermediate_config(self, mock_exists, mock_Checksum,
                                 mock_command):
        checksum = Mock()
        mock_Checksum.return_value = checksum
        mock_exists.return_value = True

        with patch('builtins.open') as m_open:
            self.bind_root.setup_intermediate_config()
            m_open.assert_called_once_with('root-dir/etc/sysconfig/proxy.sha',
                                           'w')

        assert mock_command.call_args_list == [
            call([
                'cp', '/etc/sysconfig/proxy',
                'root-dir/etc/sysconfig/proxy.kiwi'
            ]),
            call([
                'ln', '-s', '-f', 'proxy.kiwi', 'root-dir/etc/sysconfig/proxy'
            ])
        ]
        checksum.sha256.assert_called_once_with()

    @patch('kiwi.system.root_bind.Checksum')
    @patch('kiwi.system.root_bind.MountManager.is_mounted')
    @patch('kiwi.system.root_bind.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    @patch('os.path.islink')
    @patch('os.path.exists')
    @patch('shutil.move')
    def test_cleanup(self, mock_move, mock_exists, mock_islink,
                     mock_remove_hierarchy, mock_command, mock_is_mounted,
                     mock_Checksum):
        checksum = Mock()
        checksum.matches.return_value = False
        mock_Checksum.return_value = checksum
        os_exists_return_values = [False, True, True, False]

        def exists_side_effect(*args):
            return os_exists_return_values.pop()

        mock_is_mounted.return_value = False
        mock_exists.side_effect = exists_side_effect
        mock_islink.return_value = True
        with self._caplog.at_level(logging.WARNING):
            self.bind_root.cleanup()
            self.mount_manager.umount_lazy.assert_called_once_with()
            mock_remove_hierarchy.assert_called_once_with(root='root-dir',
                                                          path='/mountpoint')
            assert mock_command.call_args_list == [
                call(['rm', '-f', 'root-dir/etc/sysconfig/proxy']),
                call([
                    'cp',
                    'root-dir/usr/share/fillup-templates/sysconfig.proxy',
                    'root-dir/etc/sysconfig/proxy'
                ]),
                call([
                    'rm', '-f', 'root-dir/etc/sysconfig/proxy.kiwi',
                    'root-dir/etc/sysconfig/proxy.sha'
                ])
            ]
            mock_move.assert_called_once_with(
                'root-dir/etc/sysconfig/proxy.rpmnew',
                'root-dir/etc/sysconfig/proxy')

    @patch('os.path.islink')
    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    @patch('kiwi.system.root_bind.Checksum')
    def test_cleanup_continue_on_error(self, mock_Checksum,
                                       mock_remove_hierarchy, mock_command,
                                       mock_islink):
        mock_islink.return_value = True
        mock_remove_hierarchy.side_effect = Exception('rm')
        mock_command.side_effect = Exception
        self.mount_manager.umount_lazy.side_effect = Exception
        with self._caplog.at_level(logging.WARNING):
            self.bind_root.cleanup()
            assert 'Image root directory root-dir not cleanly umounted:' in \
                self._caplog.text
            assert 'Failed to remove directory hierarchy '
            'root-dir/mountpoint: rm' in self._caplog.text
            assert 'Failed to cleanup intermediate config files' in \
                self._caplog.text

    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    @patch('kiwi.system.root_bind.Checksum')
    def test_cleanup_nothing_mounted(self, mock_Checksum,
                                     mock_remove_hierarchy, mock_command):
        self.mount_manager.is_mounted.return_value = False
        self.mount_manager.mountpoint = '/mountpoint'
        with self._caplog.at_level(logging.WARNING):
            self.bind_root.cleanup()
            assert 'Path /mountpoint not a mountpoint' in self._caplog.text