def _prepare_required_mounts(scratch_dir, mounts_dir, mount_points, xfs_info): result = { mountpoint: mounting.NullMount(_mount_dir(mounts_dir, mountpoint)) for mountpoint in mount_points } if not xfs_info.mountpoints_without_ftype: return result space_needed = _overlay_disk_size() * len( xfs_info.mountpoints_without_ftype) disk_images_directory = os.path.join(scratch_dir, 'diskimages') # Ensure we cleanup old disk images before we check for space contraints. run(['rm', '-rf', disk_images_directory]) _create_diskimages_dir(scratch_dir, disk_images_directory) _ensure_enough_diskimage_space(space_needed, scratch_dir) for mountpoint in xfs_info.mountpoints_without_ftype: if mountpoint in mount_points: image = _create_mount_disk_image(disk_images_directory, mountpoint) result[mountpoint] = mounting.LoopMount(source=image, target=_mount_dir( mounts_dir, mountpoint)) return result
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 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 _prepare_mounts(mounts_dir, scratch_dir, cleanup, detach, xfs_present): """ A context manager function that prepares the scratch userspace and creates a mounting target directory. In case of XFS with ftype=0 it will trigger the creation of the disk image and mounts it and ensure the cleanup after leaving the context. """ if cleanup: cleanup_scratch(scratch_dir, mounts_dir) _create_mounts_dir(scratch_dir=scratch_dir, mounts_dir=mounts_dir) if xfs_present: mount = mounting.LoopMount(source=_create_mount_disk_image( scratch_dir, mounts_dir), target=mounts_dir, config=mounting.MountConfig.MountOnly) else: mount = mounting.NullMount(target=mounts_dir) with mount: yield mount
def _prepare_required_mounts(scratch_dir, mounts_dir, mount_points, xfs_info): result = { mount_point.fs_file: mounting.NullMount(_mount_dir(mounts_dir, mount_point.fs_file)) for mount_point in mount_points } if not xfs_info.mountpoints_without_ftype: return result space_needed = _overlay_disk_size() * len( xfs_info.mountpoints_without_ftype) disk_images_directory = os.path.join(scratch_dir, 'diskimages') # Ensure we cleanup old disk images before we check for space contraints. run(['rm', '-rf', disk_images_directory]) _create_diskimages_dir(scratch_dir, disk_images_directory) _ensure_enough_diskimage_space(space_needed, scratch_dir) mount_names = [mount_point.fs_file for mount_point in mount_points] # TODO(pstodulk): this (adding rootfs into the set always) is hotfix for # bz #1911802 (not ideal one..). The problem occurs one rootfs is ext4 fs, # but /var/lib/leapp/... is under XFS without ftype; In such a case we can # see still the very same problems as before. But letting you know that # probably this is not the final solution, as we could possibly see the # same problems on another partitions too (needs to be tested...). However, # it could fit for now until we provide the complete solution around XFS # workarounds (including management of required spaces for virtual FSs per # mountpoints - without that, we cannot fix this properly) for mountpoint in set(xfs_info.mountpoints_without_ftype + ['/']): if mountpoint in mount_names: image = _create_mount_disk_image(disk_images_directory, mountpoint) result[mountpoint] = mounting.LoopMount(source=image, target=_mount_dir( mounts_dir, mountpoint)) return result
def _overlay_if(condition, name, source, workdir): if condition: return mounting.OverlayMount(name=name, source=source, workdir=workdir) return mounting.NullMount(target=source)