Пример #1
0
    def post_process_install_requests_bootstrap(self,
                                                root_bind: RootBind = None
                                                ) -> None:
        """
        Mounts the kernel file systems to the chroot environment is
        ready after the bootstrap procedure

        :param object root_bind:
            instance of RootBind to manage kernel file systems
        """
        if root_bind:
            root_bind.mount_kernel_file_systems()
Пример #2
0
    def setup(self):
        root = mock.Mock()
        root.root_dir = 'root-dir'
        self.bind_root = RootBind(root)

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

        # stub files/dirs and mountpoints to cleanup
        self.mount_manager = mock.Mock()
        self.bind_root.cleanup_files = ['/foo.kiwi']
        self.bind_root.mount_stack = [self.mount_manager]
        self.bind_root.dir_stack = ['/mountpoint']
Пример #3
0
    def __init__(self, xml_state, root_dir, allow_existing=False):
        """
        Setup and host bind new root system at given root_dir directory
        """
        log.info('Setup root directory: %s', root_dir)
        root = RootInit(root_dir, allow_existing)
        root.create()
        image_uri = xml_state.get_derived_from_image_uri()
        if image_uri:
            root_import = RootImport(root_dir, image_uri,
                                     xml_state.build_type.get_image())
            root_import.sync_data()
        root_bind = RootBind(root)
        root_bind.setup_intermediate_config()
        root_bind.mount_kernel_file_systems()
        root_bind.mount_shared_directory()

        self.xml_state = xml_state
        self.profiles = xml_state.profiles
        self.root_bind = root_bind

        # A list of Uri references is stored inside of the System instance
        # in order to delay the Uri destructors until the System instance
        # dies. This is needed to keep bind mounted Uri locations alive
        # for System operations
        self.uri_list = []
Пример #4
0
 def import_repositories_marked_as_imageinclude(self):
     """
     Those <repository> sections which are marked with the
     imageinclude attribute should be permanently added to
     the image repository configuration
     """
     repository_sections = \
         self.xml_state.get_repository_sections_used_in_image()
     root = RootInit(root_dir=self.root_dir, allow_existing=True)
     repo = Repository(RootBind(root), self.xml_state.get_package_manager())
     repo.use_default_location()
     for xml_repo in repository_sections:
         repo_type = xml_repo.get_type()
         repo_source = xml_repo.get_source().get_path()
         repo_user = xml_repo.get_username()
         repo_secret = xml_repo.get_password()
         repo_alias = xml_repo.get_alias()
         repo_priority = xml_repo.get_priority()
         repo_dist = xml_repo.get_distribution()
         repo_components = xml_repo.get_components()
         repo_repository_gpgcheck = xml_repo.get_repository_gpgcheck()
         repo_package_gpgcheck = xml_repo.get_package_gpgcheck()
         uri = Uri(repo_source, repo_type)
         repo_source_translated = uri.translate(
             check_build_environment=False)
         if not repo_alias:
             repo_alias = uri.alias()
         log.info('Setting up image repository %s', repo_source)
         log.info('--> Type: %s', repo_type)
         log.info('--> Translated: %s', repo_source_translated)
         log.info('--> Alias: %s', repo_alias)
         repo.add_repo(repo_alias, repo_source_translated, repo_type,
                       repo_priority, repo_dist, repo_components, repo_user,
                       repo_secret, uri.credentials_file_name(),
                       repo_repository_gpgcheck, repo_package_gpgcheck)
Пример #5
0
    def __init__(
        self, xml_state, root_dir, allow_existing=False
    ):
        """
        Setup and host bind new root system at given root_dir directory
        """
        log.info('Setup root directory: %s', root_dir)
        root = RootInit(
            root_dir, allow_existing
        )
        root.create()
        image_uri = xml_state.get_derived_from_image_uri()
        if image_uri:
            root_import = RootImport(
                root_dir, image_uri, xml_state.build_type.get_image()
            )
            root_import.sync_data()
        root_bind = RootBind(
            root
        )
        root_bind.setup_intermediate_config()
        root_bind.mount_kernel_file_systems()
        root_bind.mount_shared_directory()

        self.xml_state = xml_state
        self.profiles = xml_state.profiles
        self.root_bind = root_bind

        # A list of Uri references is stored inside of the System instance
        # in order to delay the Uri destructors until the System instance
        # dies. This is needed to keep bind mounted Uri locations alive
        # for System operations
        self.uri_list = []
Пример #6
0
    def setup(self):
        root = mock.Mock()
        root.root_dir = 'root-dir'
        self.bind_root = RootBind(root)

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

        # stub files/dirs and mountpoints to cleanup
        self.mount_manager = mock.Mock()
        self.bind_root.cleanup_files = ['/foo.kiwi']
        self.bind_root.mount_stack = [self.mount_manager]
        self.bind_root.dir_stack = ['/mountpoint']
Пример #7
0
    def __init__(
        self, xml_state, root_dir, allow_existing=False
    ):
        """
        Setup and host bind new root system at given root_dir directory
        """
        log.info('Setup root directory: %s', root_dir)
        if not log.getLogLevel() == logging.DEBUG and not log.get_logfile():
            self.issue_message = dedent('''
                {headline}: {reason}

                Further details to clarify the error might have been
                reported earlier in the package manager log information
                and did not get exposed to the caller. Thus if the above
                message is not clear on the error please call kiwi with
                the --debug or --logfile option.
            ''')
        else:
            self.issue_message = '{headline}: {reason}'
        root = RootInit(
            root_dir, allow_existing
        )
        root.create()
        image_uri = xml_state.get_derived_from_image_uri()
        if image_uri:
            root_import = RootImport.new(
                root_dir, image_uri, xml_state.build_type.get_image()
            )
            root_import.sync_data()
        root_bind = RootBind(
            root
        )
        root_bind.setup_intermediate_config()
        root_bind.mount_kernel_file_systems()
        root_bind.mount_shared_directory()

        self.xml_state = xml_state
        self.profiles = xml_state.profiles
        self.root_bind = root_bind

        # A list of Uri references is stored inside of the System instance
        # in order to delay the Uri destructors until the System instance
        # dies. This is needed to keep bind mounted Uri locations alive
        # for System operations
        self.uri_list = []
Пример #8
0
class TestRootBind(object):
    def setup(self):
        root = mock.Mock()
        root.root_dir = 'root-dir'
        self.bind_root = RootBind(root)

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

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

    @raises(KiwiMountKernelFileSystemsError)
    @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')
        self.bind_root.mount_kernel_file_systems()
        mock.cleanup.assert_called_once_with()

    @raises(KiwiMountSharedDirectoryError)
    @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')
        self.bind_root.mount_shared_directory()
        mock.cleanup.assert_called_once_with()

    @raises(KiwiSetupIntermediateConfigError)
    @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')
        self.bind_root.setup_intermediate_config()
        mock.cleanup.assert_called_once_with()

    @patch('kiwi.system.root_bind.MountManager')
    def test_mount_kernel_file_systems(self, mock_mount):
        shared_mount = mock.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')
    @patch('kiwi.system.root_bind.Path.create')
    def test_mount_shared_directory(self, mock_path, mock_mount):
        shared_mount = mock.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('os.path.exists')
    def test_intermediate_config(self, mock_exists, mock_command):
        mock_exists.return_value = True
        self.bind_root.setup_intermediate_config()
        assert mock_command.call_args_list == [
            call(['cp', '/foo', 'root-dir/foo.kiwi']),
            call(['ln', '-s', '-f', 'foo.kiwi', 'root-dir/foo'])
        ]

    @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')
    def test_cleanup(self, mock_islink, mock_remove_hierarchy, mock_command,
                     mock_is_mounted):
        mock_is_mounted.return_value = False
        mock_islink.return_value = True
        self.bind_root.cleanup()
        self.mount_manager.umount_lazy.assert_called_once_with()
        mock_remove_hierarchy.assert_called_once_with('root-dir/mountpoint')
        mock_command.assert_called_once_with(
            ['rm', '-f', 'root-dir/foo.kiwi', 'root-dir/foo'])

    @patch('os.path.islink')
    @patch('kiwi.logger.log.warning')
    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    def test_cleanup_continue_on_error(self, mock_remove_hierarchy,
                                       mock_command, mock_warn, mock_islink):
        mock_islink.return_value = True
        mock_remove_hierarchy.side_effect = Exception
        mock_command.side_effect = Exception
        self.mount_manager.umount_lazy.side_effect = Exception
        self.bind_root.cleanup()
        assert mock_warn.call_args_list == [
            call('Image root directory %s not cleanly umounted: %s',
                 'root-dir', ''),
            call('Failed to remove directory %s: %s', '/mountpoint', ''),
            call('Failed to remove intermediate config files: %s', '')
        ]

    @patch('kiwi.logger.log.warning')
    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    def test_cleanup_nothing_mounted(self, mock_remove_hierarchy, mock_command,
                                     mock_warn):
        self.mount_manager.is_mounted.return_value = False
        self.mount_manager.mountpoint = '/mountpoint'
        self.bind_root.cleanup()
        mock_warn.assert_called_once_with('Path %s not a mountpoint',
                                          '/mountpoint')

    def test_move_to_root(self):
        assert self.bind_root.move_to_root(
            [self.bind_root.root_dir + '/argument']) == ['//argument']
Пример #9
0
    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)))
Пример #10
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')
    @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-dir/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
Пример #11
0
class TestRootBind(object):
    def setup(self):
        root = mock.Mock()
        root.root_dir = 'root-dir'
        self.bind_root = RootBind(root)

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

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

    @raises(KiwiMountKernelFileSystemsError)
    @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'
        )
        self.bind_root.mount_kernel_file_systems()
        mock.cleanup.assert_called_once_with()

    @raises(KiwiMountSharedDirectoryError)
    @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'
        )
        self.bind_root.mount_shared_directory()
        mock.cleanup.assert_called_once_with()

    @raises(KiwiSetupIntermediateConfigError)
    @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'
        )
        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()
        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')
    @patch('kiwi.system.root_bind.Path.create')
    def test_mount_shared_directory(self, mock_path, mock_mount):
        shared_mount = mock.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('os.path.exists')
    def test_intermediate_config(self, mock_exists, mock_command):
        mock_exists.return_value = True
        self.bind_root.setup_intermediate_config()
        assert mock_command.call_args_list == [
            call([
                'cp', '/foo', 'root-dir/foo.kiwi'
            ]),
            call([
                'ln', '-s', '-f', 'foo.kiwi', 'root-dir/foo'
            ])
        ]

    @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_is_mounted.return_value = False
        mock_exists.return_value = True
        mock_islink.return_value = True
        self.bind_root.cleanup()
        self.mount_manager.umount_lazy.assert_called_once_with()
        mock_remove_hierarchy.assert_called_once_with('root-dir/mountpoint')
        mock_command.assert_called_once_with(
            ['rm', '-f', 'root-dir/foo.kiwi', 'root-dir/foo']
        )
        mock_move.assert_called_once_with(
            'root-dir/foo.rpmnew', 'root-dir/foo'
        )

    @patch('os.path.islink')
    @patch('kiwi.logger.log.warning')
    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    def test_cleanup_continue_on_error(
        self, mock_remove_hierarchy, mock_command, mock_warn, mock_islink
    ):
        mock_islink.return_value = True
        mock_remove_hierarchy.side_effect = Exception
        mock_command.side_effect = Exception
        self.mount_manager.umount_lazy.side_effect = Exception
        self.bind_root.cleanup()
        assert mock_warn.call_args_list == [
            call(
                'Image root directory %s not cleanly umounted: %s',
                'root-dir', ''
            ),
            call(
                'Failed to remove directory %s: %s', '/mountpoint', ''
            ),
            call(
                'Failed to remove intermediate config files: %s', ''
            )
        ]

    @patch('kiwi.logger.log.warning')
    @patch('kiwi.command.Command.run')
    @patch('kiwi.system.root_bind.Path.remove_hierarchy')
    def test_cleanup_nothing_mounted(
        self, mock_remove_hierarchy, mock_command, mock_warn
    ):
        self.mount_manager.is_mounted.return_value = False
        self.mount_manager.mountpoint = '/mountpoint'
        self.bind_root.cleanup()
        mock_warn.assert_called_once_with(
            'Path %s not a mountpoint', '/mountpoint'
        )

    def test_move_to_root(self):
        assert self.bind_root.move_to_root(
            [self.bind_root.root_dir + '/argument']
        ) == ['//argument']
Пример #12
0
class TestRootBind:
    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 = ['/foo']
        self.bind_root.bind_locations = ['/proc']

        # stub files/dirs and mountpoints to cleanup
        self.mount_manager = Mock()
        self.bind_root.cleanup_files = ['/foo.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')
    @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/foo.sha', 'w')

        assert mock_command.call_args_list == [
            call(['cp', '/foo', 'root-dir/foo.kiwi']),
            call(['ln', '-s', '-f', 'foo.kiwi', 'root-dir/foo'])
        ]
        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')
    @patch('kiwi.logger.log.warning')
    def test_cleanup(self, mock_log_warn, 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]

        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
        self.bind_root.cleanup()
        self.mount_manager.umount_lazy.assert_called_once_with()
        mock_remove_hierarchy.assert_called_once_with('root-dir/mountpoint')
        mock_command.assert_called_once_with([
            'rm', '-f', 'root-dir/foo.kiwi', 'root-dir/foo.sha', 'root-dir/foo'
        ])
        mock_move.assert_called_once_with('root-dir/foo.rpmnew',
                                          'root-dir/foo')
        assert mock_log_warn.called

    @patch('os.path.islink')
    @patch('kiwi.logger.log.warning')
    @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_warn, 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
        self.bind_root.cleanup()
        assert mock_warn.call_args_list == [
            call('Image root directory %s not cleanly umounted: %s',
                 'root-dir', ''),
            call('Failed to remove directory hierarchy root-dir/mountpoint: rm'
                 ),
            call('Failed to remove intermediate config files: %s', '')
        ]

    @patch('kiwi.logger.log.warning')
    @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,
                                     mock_warn):
        self.mount_manager.is_mounted.return_value = False
        self.mount_manager.mountpoint = '/mountpoint'
        self.bind_root.cleanup()
        mock_warn.assert_called_once_with('Path %s not a mountpoint',
                                          '/mountpoint')

    def test_move_to_root(self):
        assert self.bind_root.move_to_root(
            [self.bind_root.root_dir + '/argument']) == ['/argument']
Пример #13
0
class TestRootBind(object):
    def setup(self):
        root = mock.Mock()
        root.root_dir = "root-dir"
        self.bind_root = RootBind(root)

        # stub config files and bind locations
        self.bind_root.config_files = ["/foo"]
        self.bind_root.bind_locations = ["/proc"]

        # stub files/dirs and mountpoints to cleanup
        self.mount_manager = mock.Mock()
        self.bind_root.cleanup_files = ["/foo.kiwi"]
        self.bind_root.mount_stack = [self.mount_manager]
        self.bind_root.dir_stack = ["/mountpoint"]

    @raises(KiwiMountKernelFileSystemsError)
    @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")
        self.bind_root.mount_kernel_file_systems()
        mock.cleanup.assert_called_once_with()

    @raises(KiwiMountSharedDirectoryError)
    @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")
        self.bind_root.mount_shared_directory()
        mock.cleanup.assert_called_once_with()

    @raises(KiwiSetupIntermediateConfigError)
    @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")
        self.bind_root.setup_intermediate_config()
        mock.cleanup.assert_called_once_with()

    @patch("kiwi.system.root_bind.MountManager")
    def test_mount_kernel_file_systems(self, mock_mount):
        shared_mount = mock.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")
    @patch("kiwi.system.root_bind.Path.create")
    def test_mount_shared_directory(self, mock_path, mock_mount):
        shared_mount = mock.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("os.path.exists")
    def test_intermediate_config(self, mock_exists, mock_command):
        mock_exists.return_value = True
        self.bind_root.setup_intermediate_config()
        assert mock_command.call_args_list == [
            call(["cp", "/foo", "root-dir/foo.kiwi"]),
            call(["ln", "-s", "-f", "foo.kiwi", "root-dir/foo"]),
        ]

    @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")
    def test_cleanup(self, mock_islink, mock_remove_hierarchy, mock_command, mock_is_mounted):
        mock_is_mounted.return_value = False
        mock_islink.return_value = True
        self.bind_root.cleanup()
        self.mount_manager.umount_lazy.assert_called_once_with()
        mock_remove_hierarchy.assert_called_once_with("root-dir/mountpoint")
        mock_command.assert_called_once_with(["rm", "-f", "root-dir/foo.kiwi", "root-dir/foo"])

    @patch("os.path.islink")
    @patch("kiwi.logger.log.warning")
    @patch("kiwi.command.Command.run")
    @patch("kiwi.system.root_bind.Path.remove_hierarchy")
    def test_cleanup_continue_on_error(self, mock_remove_hierarchy, mock_command, mock_warn, mock_islink):
        mock_islink.return_value = True
        mock_remove_hierarchy.side_effect = Exception
        mock_command.side_effect = Exception
        self.mount_manager.umount_lazy.side_effect = Exception
        self.bind_root.cleanup()
        assert mock_warn.call_args_list == [
            call("Image root directory %s not cleanly umounted: %s", "root-dir", ""),
            call("Failed to remove directory %s: %s", "/mountpoint", ""),
            call("Failed to remove intermediate config files: %s", ""),
        ]

    @patch("kiwi.logger.log.warning")
    @patch("kiwi.command.Command.run")
    @patch("kiwi.system.root_bind.Path.remove_hierarchy")
    def test_cleanup_nothing_mounted(self, mock_remove_hierarchy, mock_command, mock_warn):
        self.mount_manager.is_mounted.return_value = False
        self.mount_manager.mountpoint = "/mountpoint"
        self.bind_root.cleanup()
        mock_warn.assert_called_once_with("Path %s not a mountpoint", "/mountpoint")

    def test_move_to_root(self):
        assert self.bind_root.move_to_root([self.bind_root.root_dir + "/argument"]) == ["//argument"]