def create_source_overlay(mounts_dir,
                          scratch_dir,
                          xfs_info,
                          storage_info,
                          mount_target=None):
    """
    Context manager that prepares the source system overlay and yields the mount.
    """
    api.current_logger().debug(
        'Creating source overlay in {scratch_dir} with mounts in {mounts_dir}'.
        format(scratch_dir=scratch_dir, mounts_dir=mounts_dir))
    try:
        _create_mounts_dir(scratch_dir, mounts_dir)
        mounts = _prepare_required_mounts(scratch_dir, mounts_dir,
                                          _get_mountpoints(storage_info),
                                          xfs_info)
        with mounts.pop('/') as root_mount:
            with mounting.OverlayMount(
                    name='system_overlay', source='/',
                    workdir=root_mount.target) as root_overlay:
                if mount_target:
                    target = mounting.BindMount(source=root_overlay.target,
                                                target=mount_target)
                else:
                    target = mounting.NullMount(target=root_overlay.target)
                with target:
                    with _build_overlay_mount(root_overlay, mounts) as overlay:
                        with _mount_dnf_cache(overlay.target):
                            yield overlay
    except Exception:
        cleanup_scratch(scratch_dir, mounts_dir)
        raise
예제 #2
0
def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
    """
    Implements the creation of the target userspace.
    """
    run(['rm', '-rf', userspace_dir])
    _create_target_userspace_directories(userspace_dir)
    with mounting.BindMount(source=userspace_dir,
                            target=os.path.join(context.base_dir,
                                                'el8target')):
        repos_opt = [['--enablerepo', repo] for repo in enabled_repos]
        repos_opt = list(itertools.chain(*repos_opt))
        cmd = [
            'dnf', 'install', '-y', '--nogpgcheck',
            '--setopt=module_platform_id=platform:el8', '--setopt=keepcache=1',
            '--releasever',
            api.current_actor().configuration.version.target, '--installroot',
            '/el8target', '--disablerepo', '*'
        ] + repos_opt + packages
        if config.is_verbose():
            cmd.append('-v')
        try:
            context.call(cmd, callback_raw=utils.logging_handler)
        except CalledProcessError as exc:
            raise StopActorExecutionError(
                message='Unable to install RHEL 8 userspace packages.',
                details={
                    'details': str(exc),
                    'stderr': exc.stderr
                })
예제 #3
0
def _mount_dnf_cache(overlay_target):
    """
    Convenience context manager to ensure bind mounted /var/cache/dnf and removal of the mount.
    """
    with mounting.BindMount(source='/var/cache/dnf',
                            target=os.path.join(overlay_target, 'var', 'cache',
                                                'dnf')) as cache_mount:
        yield cache_mount
예제 #4
0
    def process(self):
        if not architecture.matches_architecture(architecture.ARCH_S390X):
            return
        userspace = next(self.consume(TargetUserSpaceInfo), None)
        if not userspace:
            # actually this should not happen, but in such case, we want to still
            # rather continue even if we boot into the old kernel, but in such
            # case, people will have to do manual actions.
            # NOTE: it is really just hypothetical
            self.log_error(
                'TargetUserSpaceInfo is missing. Cannot execute zipl-switch-to-blscfg'
                ' to convert the zipl configuration to BLS.')
            raise StopActorExecutionError(
                'GENERAL FAILURE: Input data for the actor are missing.')

        # replace the original boot directory inside the container by the host one
        # - as we cannot use zipl* pointing anywhere else than default directory
        # - no, --bls-directory is not solution
        with mounting.BindMount(source='/boot',
                                target=os.path.join(userspace.path, 'boot')):
            userspace_zipl_conf = os.path.join(userspace.path, 'etc',
                                               'zipl.conf')
            if os.path.exists(userspace_zipl_conf):
                os.remove(userspace_zipl_conf)
            with mounting.NullMount(target=userspace.path) as userspace:
                with userspace.nspawn() as context:
                    context.copy_to('/etc/zipl.conf', '/etc/zipl.conf')
                    # zipl needs this one as well
                    context.copy_to('/etc/machine-id', '/etc/machine-id')
                    try:
                        context.call(['/usr/sbin/zipl-switch-to-blscfg'])
                        if filecmp.cmp('/etc/zipl.conf', userspace_zipl_conf):
                            # When the files are same, zipl failed - see the switch script
                            raise OSError(
                                'Failed to convert the ZIPL configuration to BLS.'
                            )
                        context.copy_from('/etc/zipl.conf', '/etc/zipl.conf')
                    except OSError as e:
                        self.log.error(
                            'Could not call zipl-switch-to-blscfg command.',
                            exc_info=True)
                        raise StopActorExecutionError(
                            message='Failed to execute zipl-switch-to-blscfg.',
                            details={'details': str(e)})
                    except CalledProcessError as e:
                        self.log.error(
                            'zipl-switch-to-blscfg execution failed,',
                            exc_info=True)
                        raise StopActorExecutionError(
                            message=
                            'zipl-switch-to-blscfg execution failed with non zero exit code.',
                            details={
                                'details': str(e),
                                'stdout': e.stdout,
                                'stderr': e.stderr
                            })
def _build_overlay_mount(root_mount, mounts):
    if not root_mount:
        raise StopActorExecutionError(
            'Root mount point has not been prepared for overlayfs.')
    if not mounts:
        yield root_mount
    else:
        current = mounts.keys()[0]
        current_mount = mounts.pop(current)
        name = _mount_name(current)
        with mounting.OverlayMount(name=name,
                                   source=current,
                                   workdir=current_mount.target) as overlay:
            with mounting.BindMount(source=overlay.target,
                                    target=os.path.join(
                                        root_mount.target,
                                        current.lstrip('/'))):
                with _build_overlay_mount(root_mount, mounts) as mount:
                    yield mount
예제 #6
0
def _build_overlay_mount(root_mount, mounts):
    if not root_mount:
        raise StopActorExecutionError(
            'Root mount point has not been prepared for overlayfs.')
    if not mounts:
        yield root_mount
    else:
        current = mounts.keys()[0]
        current_mount = mounts.pop(current)
        name = _mount_name(current)
        # We will not make an overlay over /boot/efi as it is vfat that does not support overlayfs
        with _overlay_if(current != '/boot/efi',
                         name=name,
                         source=current,
                         workdir=current_mount.target) as overlay:
            with mounting.BindMount(source=overlay.target,
                                    target=os.path.join(
                                        root_mount.target,
                                        current.lstrip('/'))):
                with _build_overlay_mount(root_mount, mounts) as mount:
                    yield mount
예제 #7
0
def perform_transaction_check(target_userspace_info, used_repos, tasks,
                              xfs_present):
    """
    Perform DNF transaction check using our plugin
    """
    with _prepare_transaction(
            used_repos=used_repos,
            target_userspace_info=target_userspace_info) as (context,
                                                             target_repoids,
                                                             userspace_info):
        with overlaygen.create_source_overlay(
                mounts_dir=userspace_info.mounts,
                scratch_dir=userspace_info.scratch,
                xfs_present=xfs_present) as overlay:
            utils.apply_yum_workaround(overlay.nspawn())
            with mounting.BindMount(source=overlay.target,
                                    target=os.path.join(
                                        context.base_dir, 'installroot')):
                _transaction(context=context,
                             stage='check',
                             target_repoids=target_repoids,
                             tasks=tasks)
예제 #8
0
def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
    """
    Implement the creation of the target userspace.
    """
    _backup_to_persistent_package_cache(userspace_dir)

    target_major_version = get_target_major_version()
    run(['rm', '-rf', userspace_dir])
    _create_target_userspace_directories(userspace_dir)
    with mounting.BindMount(source=userspace_dir,
                            target=os.path.join(
                                context.base_dir,
                                'el{}target'.format(target_major_version))):
        _restore_persistent_package_cache(userspace_dir)

        repos_opt = [['--enablerepo', repo] for repo in enabled_repos]
        repos_opt = list(itertools.chain(*repos_opt))
        cmd = [
            'dnf', 'install', '-y', '--nogpgcheck',
            '--setopt=module_platform_id=platform:el{}'.format(
                target_major_version), '--setopt=keepcache=1', '--releasever',
            api.current_actor().configuration.version.target, '--installroot',
            '/el{}target'.format(target_major_version), '--disablerepo', '*'
        ] + repos_opt + packages
        if config.is_verbose():
            cmd.append('-v')
        if rhsm.skip_rhsm():
            cmd += ['--disableplugin', 'subscription-manager']
        try:
            context.call(cmd, callback_raw=utils.logging_handler)
        except CalledProcessError as exc:
            raise StopActorExecutionError(
                message='Unable to install RHEL {} userspace packages.'.format(
                    target_major_version),
                details={
                    'details': str(exc),
                    'stderr': exc.stderr
                })
예제 #9
0
def perform_rpm_download(target_userspace_info, used_repos, tasks,
                         xfs_present):
    """
    Perform RPM download including the transaction test using dnf with our plugin
    """
    with _prepare_transaction(
            used_repos=used_repos,
            target_userspace_info=target_userspace_info) as (context,
                                                             target_repoids,
                                                             userspace_info):
        with overlaygen.create_source_overlay(
                mounts_dir=userspace_info.mounts,
                scratch_dir=userspace_info.scratch,
                xfs_present=xfs_present) as overlay:
            utils.apply_yum_workaround(overlay.nspawn())
            with mounting.BindMount(source=overlay.target,
                                    target=os.path.join(
                                        context.base_dir, 'installroot')):
                _transaction(context=context,
                             stage='download',
                             target_repoids=target_repoids,
                             tasks=tasks,
                             test=True)
예제 #10
0
def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
    """
    Implements the creation of the target userspace.
    """
    run(['rm', '-rf', userspace_dir])
    _create_target_userspace_directories(userspace_dir)
    with mounting.BindMount(source=userspace_dir, target=os.path.join(context.base_dir, 'el8target')):
        repos_opt = [['--enablerepo', repo] for repo in enabled_repos]
        repos_opt = list(itertools.chain(*repos_opt))
        context.call(
            [
                'dnf',
                'install',
                '-y',
                '--nogpgcheck',
                '--setopt=module_platform_id=platform:el8',
                '--setopt=keepcache=1',
                '--releasever', '8',
                '--installroot', '/el8target',
                '--disablerepo', '*'
            ] + repos_opt + packages,
            callback_raw=utils.logging_handler
        )