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
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 })
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
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
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
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)
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 })
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)
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 )