def get_canonical_volume_list(self): """ Implements hierarchical sorting of volumes according to their paths and provides information about the volume configured as the one eating all the rest space :return: list of canonical_volume_type tuples :rtype: list """ canonical_volume_type = namedtuple( 'canonical_volume_type', [ 'volumes', 'full_size_volume' ] ) volume_paths = {} full_size_volume = None for volume in self.volumes: if volume.fullsize: full_size_volume = volume elif volume.realpath: volume_paths[volume.realpath] = volume volume_list = [] for realpath in Path.sort_by_hierarchy(sorted(volume_paths.keys())): volume_list.append(volume_paths[realpath]) return canonical_volume_type( volumes=volume_list, full_size_volume=full_size_volume )
def get_canonical_volume_list(self): """ Implements hierarchical sorting of volumes according to their paths and provides information about the volume configured as the one eating all the rest space :return: list of canonical_volume_type tuples :rtype: list """ canonical_volume_type = namedtuple('canonical_volume_type', ['volumes', 'full_size_volume']) volume_paths = {} full_size_volume = None for volume in self.volumes: if volume.fullsize: full_size_volume = volume elif volume.realpath: volume_paths[volume.realpath] = volume volume_list = [] for realpath in Path.sort_by_hierarchy(sorted(volume_paths.keys())): volume_list.append(volume_paths[realpath]) return canonical_volume_type(volumes=volume_list, full_size_volume=full_size_volume)
def _mount_system( self, root_device, boot_device, efi_device=None, volumes=None ): self.root_mount = MountManager( device=root_device ) self.boot_mount = MountManager( device=boot_device, mountpoint=self.root_mount.mountpoint + '/boot' ) if efi_device: self.efi_mount = MountManager( device=efi_device, mountpoint=self.root_mount.mountpoint + '/boot/efi' ) self.root_mount.mount() if not self.root_mount.device == self.boot_mount.device: self.boot_mount.mount() if efi_device: self.efi_mount.mount() if volumes: for volume_path in Path.sort_by_hierarchy( sorted(volumes.keys()) ): volume_mount = MountManager( device=volumes[volume_path]['volume_device'], mountpoint=self.root_mount.mountpoint + '/' + volume_path ) self.volumes_mount.append(volume_mount) volume_mount.mount( options=[volumes[volume_path]['volume_options']] ) if self.root_filesystem_is_overlay: # In case of an overlay root system all parts of the rootfs # are read-only by squashfs except for the extra boot partition. # However tools like grub's mkconfig creates temporary files # at call time and therefore /tmp needs to be writable during # the call time of the tools self.tmp_mount = MountManager( device='/tmp', mountpoint=self.root_mount.mountpoint + '/tmp' ) self.tmp_mount.bind_mount() self.device_mount = MountManager( device='/dev', mountpoint=self.root_mount.mountpoint + '/dev' ) self.proc_mount = MountManager( device='/proc', mountpoint=self.root_mount.mountpoint + '/proc' ) self.device_mount.bind_mount() self.proc_mount.bind_mount()
def _mount_volumes(self, mountpoint) -> None: for volume_path in Path.sort_by_hierarchy(sorted(self.volumes.keys())): volume_mount = MountManager( device=self.volumes[volume_path]['volume_device'], mountpoint=os.path.join(mountpoint, volume_path)) self.mount_list.append(volume_mount) volume_mount.mount( options=[self.volumes[volume_path]['volume_options']])
def create_volumes(self, filesystem_name): """ Create configured lvm volumes and filesystems All volumes receive the same filesystem :param str filesystem_name: volumes filesystem name """ log.info('Creating volumes(%s)', filesystem_name) self.create_volume_paths_in_root_dir() canonical_volume_list = self.get_canonical_volume_list() for volume in canonical_volume_list.volumes: volume_mbsize = self.get_volume_mbsize( volume, self.volumes, filesystem_name, self.custom_args['resize_on_boot']) log.info('--> volume %s with %s MB', volume.name, volume_mbsize) self._create_volume_no_zero(self.lvm_tool_options, [ '-L', format(volume_mbsize), '-n', volume.name, self.volume_group ]) self.apply_attributes_on_volume(self.root_dir, volume) self._add_to_volume_map(volume.name) if volume.label != 'SWAP': self._create_filesystem(volume.name, volume.label, filesystem_name) self._add_to_mount_list(volume.name, volume.realpath) if canonical_volume_list.full_size_volume: full_size_volume = canonical_volume_list.full_size_volume log.info('--> fullsize volume %s', full_size_volume.name) self._create_volume_no_zero(self.lvm_tool_options, [ '-l', '+100%FREE', '-n', full_size_volume.name, self.volume_group ]) self._add_to_volume_map(full_size_volume.name) self._create_filesystem(full_size_volume.name, full_size_volume.label, filesystem_name) self._add_to_mount_list(full_size_volume.name, full_size_volume.realpath) # re-order mount_list by mountpoint hierarchy # This is needed because the handling of the fullsize volume and # all other volumes is outside of the canonical order. If the # fullsize volume forms a nested structure together with another # volume the volume mount list must be re-ordered to avoid # mounting the volumes in the wrong order volume_paths = {} for volume_mount in self.mount_list: volume_paths[volume_mount.mountpoint] = volume_mount self.mount_list = [] for mount_path in Path.sort_by_hierarchy(sorted(volume_paths.keys())): self.mount_list.append(volume_paths[mount_path])
def export(self, filename: str) -> None: """ Export entries, respect canonical mount order :param string filename: path to file name """ fstab_entries_by_path = {} for entry in self.fstab: fstab_entries_by_path[entry.mountpoint] = entry with open(filename, 'w') as fstab: for device_path in Path.sort_by_hierarchy( sorted(fstab_entries_by_path.keys())): entry = fstab_entries_by_path[device_path] fstab.write(self._file_entry(entry) + os.linesep)
def _mount_device_and_volumes(self): if self.root_mount is None: self.root_mount = MountManager( device=self.custom_args['root_device']) self.root_mount.mount() if self.boot_mount is None: if 's390' in self.arch: self.boot_mount = MountManager( device=self.custom_args['boot_device'], mountpoint=self.root_mount.mountpoint + '/boot/zipl') else: self.boot_mount = MountManager( device=self.custom_args['boot_device'], mountpoint=self.root_mount.mountpoint + '/boot') if not self.root_mount.device == self.boot_mount.device: self.boot_mount.mount() if self.efi_mount is None and self.custom_args.get('efi_device'): self.efi_mount = MountManager( device=self.custom_args['efi_device'], mountpoint=self.root_mount.mountpoint + '/boot/efi') self.efi_mount.mount() if self.volumes and not self.volumes_mount: for volume_path in Path.sort_by_hierarchy( sorted(self.volumes.keys())): volume_mount = MountManager( device=self.volumes[volume_path]['volume_device'], mountpoint=self.root_mount.mountpoint + '/' + volume_path) self.volumes_mount.append(volume_mount) volume_mount.mount( options=[self.volumes[volume_path]['volume_options']]) if self.device_mount is None: self.device_mount = MountManager( device='/dev', mountpoint=self.root_mount.mountpoint + '/dev') self.device_mount.bind_mount() if self.proc_mount is None: self.proc_mount = MountManager( device='/proc', mountpoint=self.root_mount.mountpoint + '/proc') self.proc_mount.bind_mount() if self.sysfs_mount is None: self.sysfs_mount = MountManager( device='/sys', mountpoint=self.root_mount.mountpoint + '/sys') self.sysfs_mount.bind_mount()
def install(self): """ Install bootloader on disk device """ log.info('Installing grub2 on disk %s', self.device) if self.target_removable: self.install_arguments.append('--removable') if self.arch == 'x86_64' or self.arch == 'i686' or self.arch == 'i586': self.target = 'i386-pc' self.install_device = self.device self.modules = ' '.join( Defaults.get_grub_bios_modules(multiboot=True)) self.install_arguments.append('--skip-fs-probe') elif self.arch.startswith('ppc64'): if not self.custom_args or 'prep_device' not in self.custom_args: raise KiwiBootLoaderGrubInstallError( 'prep device name required for grub2 installation on ppc') self.target = 'powerpc-ieee1275' self.install_device = self.custom_args['prep_device'] self.modules = ' '.join(Defaults.get_grub_ofw_modules()) self.install_arguments.append('--skip-fs-probe') self.install_arguments.append('--no-nvram') else: raise KiwiBootLoaderGrubPlatformError( 'host architecture %s not supported for grub2 installation' % self.arch) self.root_mount = MountManager(device=self.custom_args['root_device']) self.boot_mount = MountManager(device=self.custom_args['boot_device'], mountpoint=self.root_mount.mountpoint + '/boot') self.root_mount.mount() if not self.root_mount.device == self.boot_mount.device: self.boot_mount.mount() if self.volumes: for volume_path in Path.sort_by_hierarchy( sorted(self.volumes.keys())): volume_mount = MountManager( device=self.volumes[volume_path]['volume_device'], mountpoint=self.root_mount.mountpoint + '/' + volume_path) self.volumes_mount.append(volume_mount) volume_mount.mount( options=[self.volumes[volume_path]['volume_options']]) self.device_mount = MountManager( device='/dev', mountpoint=self.root_mount.mountpoint + '/dev') self.proc_mount = MountManager(device='/proc', mountpoint=self.root_mount.mountpoint + '/proc') self.sysfs_mount = MountManager(device='/sys', mountpoint=self.root_mount.mountpoint + '/sys') self.device_mount.bind_mount() self.proc_mount.bind_mount() self.sysfs_mount.bind_mount() # check if a grub installation could be found in the image system grub_directory = Defaults.get_grub_path(self.root_mount.mountpoint + '/usr/lib') if not grub_directory: raise KiwiBootLoaderGrubDataError( 'No grub2 installation found in %s' % self.root_mount.mountpoint) grub_directory = grub_directory.replace(self.root_mount.mountpoint, '') module_directory = grub_directory + '/' + self.target boot_directory = '/boot' # wipe existing grubenv to allow the grub installer to create a new one grubenv_glob = os.sep.join( [self.root_mount.mountpoint, 'boot', '*', 'grubenv']) for grubenv in glob.glob(grubenv_glob): Path.wipe(grubenv) # install grub2 boot code Command.run([ 'chroot', self.root_mount.mountpoint, self._get_grub2_install_tool_name(self.root_mount.mountpoint) ] + self.install_arguments + [ '--directory', module_directory, '--boot-directory', boot_directory, '--target', self.target, '--modules', self.modules, self.install_device ]) if self.firmware and self.firmware.efi_mode() == 'uefi': shim_install = self._get_shim_install_tool_name( self.root_mount.mountpoint) # if shim-install does _not_ exist the fallback mechanism # has applied at the bootloader/config level and we expect # no further tool calls to be required if shim_install: self.efi_mount = MountManager( device=self.custom_args['efi_device'], mountpoint=self.root_mount.mountpoint + '/boot/efi') self.efi_mount.mount() # Before we call shim-install, the grub installer binary is # replaced by a noop. Actually there is no reason for # shim-install to call the grub installer because it should # only setup the system for EFI secure boot which does not # require any bootloader code in the master boot record. # In addition kiwi has called the grub installer right # before self._disable_grub2_install(self.root_mount.mountpoint) Command.run([ 'chroot', self.root_mount.mountpoint, 'shim-install', '--removable', self.install_device ]) # restore the grub installer noop self._enable_grub2_install(self.root_mount.mountpoint)
def test_sort_by_hierarchy(self): ordered = Path.sort_by_hierarchy( ['usr', 'usr/bin', 'etc', 'usr/lib'] ) assert ordered == ['usr', 'etc', 'usr/bin', 'usr/lib']
def test_sort_by_hierarchy(self): ordered = Path.sort_by_hierarchy(['usr', 'usr/bin', 'etc', 'usr/lib']) assert ordered == ['usr', 'etc', 'usr/bin', 'usr/lib']
def create_volumes(self, filesystem_name): """ Create configured lvm volumes and filesystems All volumes receive the same filesystem :param string filesystem_name: volumes filesystem name """ log.info( 'Creating volumes(%s)', filesystem_name ) self.create_volume_paths_in_root_dir() canonical_volume_list = self.get_canonical_volume_list() for volume in canonical_volume_list.volumes: volume_mbsize = self.get_volume_mbsize( volume, self.volumes, filesystem_name, self.custom_args['image_type'] ) log.info( '--> volume %s with %s MB', volume.name, volume_mbsize ) Command.run( [ 'lvcreate', '-L', format(volume_mbsize), '-n', volume.name, self.volume_group ] ) self.apply_attributes_on_volume( self.root_dir, volume ) self._add_to_volume_map(volume.name) self._create_filesystem( volume.name, filesystem_name ) self._add_to_mount_list( volume.name, volume.realpath ) if canonical_volume_list.full_size_volume: full_size_volume = canonical_volume_list.full_size_volume log.info('--> fullsize volume %s', full_size_volume.name) Command.run( [ 'lvcreate', '-l', '+100%FREE', '-n', full_size_volume.name, self.volume_group ] ) self._add_to_volume_map(full_size_volume.name) self._create_filesystem( full_size_volume.name, filesystem_name ) self._add_to_mount_list( full_size_volume.name, full_size_volume.realpath ) # re-order mount_list by mountpoint hierarchy # This is needed because the handling of the fullsize volume and # all other volumes is outside of the canonical order. If the # fullsize volume forms a nested structure together with another # volume the volume mount list must be re-ordered to avoid # mounting the volumes in the wrong order volume_paths = {} for volume_mount in self.mount_list: volume_paths[volume_mount.mountpoint] = volume_mount self.mount_list = [] for mount_path in Path.sort_by_hierarchy(sorted(volume_paths.keys())): self.mount_list.append(volume_paths[mount_path])
def install(self): """ Install bootloader on disk device """ log.info('Installing grub2 on disk %s', self.device) if self.target_removable: self.install_arguments.append('--removable') if self.arch == 'x86_64' or self.arch == 'i686' or self.arch == 'i586': self.target = 'i386-pc' self.install_device = self.device self.modules = ' '.join( Defaults.get_grub_bios_modules(multiboot=True) ) self.install_arguments.append('--skip-fs-probe') elif self.arch.startswith('ppc64'): if not self.custom_args or 'prep_device' not in self.custom_args: raise KiwiBootLoaderGrubInstallError( 'prep device name required for grub2 installation on ppc' ) self.target = 'powerpc-ieee1275' self.install_device = self.custom_args['prep_device'] self.modules = ' '.join(Defaults.get_grub_ofw_modules()) self.install_arguments.append('--skip-fs-probe') self.install_arguments.append('--no-nvram') else: raise KiwiBootLoaderGrubPlatformError( 'host architecture %s not supported for grub2 installation' % self.arch ) self.root_mount = MountManager( device=self.custom_args['root_device'] ) self.boot_mount = MountManager( device=self.custom_args['boot_device'], mountpoint=self.root_mount.mountpoint + '/boot' ) self.root_mount.mount() if not self.root_mount.device == self.boot_mount.device: self.boot_mount.mount() if self.volumes: for volume_path in Path.sort_by_hierarchy( sorted(self.volumes.keys()) ): volume_mount = MountManager( device=self.volumes[volume_path]['volume_device'], mountpoint=self.root_mount.mountpoint + '/' + volume_path ) self.volumes_mount.append(volume_mount) volume_mount.mount( options=[self.volumes[volume_path]['volume_options']] ) self.device_mount = MountManager( device='/dev', mountpoint=self.root_mount.mountpoint + '/dev' ) self.proc_mount = MountManager( device='/proc', mountpoint=self.root_mount.mountpoint + '/proc' ) self.sysfs_mount = MountManager( device='/sys', mountpoint=self.root_mount.mountpoint + '/sys' ) self.device_mount.bind_mount() self.proc_mount.bind_mount() self.sysfs_mount.bind_mount() # check if a grub installation could be found in the image system grub_directory = Defaults.get_grub_path( self.root_mount.mountpoint + '/usr/lib' ) if not grub_directory: raise KiwiBootLoaderGrubDataError( 'No grub2 installation found in %s' % self.root_mount.mountpoint ) grub_directory = grub_directory.replace( self.root_mount.mountpoint, '' ) module_directory = grub_directory + '/' + self.target boot_directory = '/boot' # wipe existing grubenv to allow the grub installer to create a new one grubenv_glob = os.sep.join( [self.root_mount.mountpoint, 'boot', '*', 'grubenv'] ) for grubenv in glob.glob(grubenv_glob): Path.wipe(grubenv) # install grub2 boot code Command.run( [ 'chroot', self.root_mount.mountpoint, self._get_grub2_install_tool_name(self.root_mount.mountpoint) ] + self.install_arguments + [ '--directory', module_directory, '--boot-directory', boot_directory, '--target', self.target, '--modules', self.modules, self.install_device ] ) if self.firmware and self.firmware.efi_mode() == 'uefi': shim_install = self._get_shim_install_tool_name( self.root_mount.mountpoint ) # if shim-install does _not_ exist the fallback mechanism # has applied at the bootloader/config level and we expect # no further tool calls to be required if shim_install: self.efi_mount = MountManager( device=self.custom_args['efi_device'], mountpoint=self.root_mount.mountpoint + '/boot/efi' ) self.efi_mount.mount() # Before we call shim-install, the grub installer binary is # replaced by a noop. Actually there is no reason for # shim-install to call the grub installer because it should # only setup the system for EFI secure boot which does not # require any bootloader code in the master boot record. # In addition kiwi has called the grub installer right # before self._disable_grub2_install(self.root_mount.mountpoint) Command.run( [ 'chroot', self.root_mount.mountpoint, 'shim-install', '--removable', self.install_device ] ) # restore the grub installer noop self._enable_grub2_install(self.root_mount.mountpoint)
def install(self): # noqa: C901 """ Install bootloader on disk device """ log.info('Installing grub2 on disk %s', self.device) if self.target_removable: self.install_arguments.append('--removable') if Defaults.is_x86_arch(self.arch): self.target = 'i386-pc' self.install_device = self.device self.modules = ' '.join( Defaults.get_grub_bios_modules(multiboot=True) ) self.install_arguments.append('--skip-fs-probe') elif self.arch.startswith('ppc64'): if not self.custom_args or 'prep_device' not in self.custom_args: raise KiwiBootLoaderGrubInstallError( 'prep device name required for grub2 installation on ppc' ) self.target = 'powerpc-ieee1275' self.install_device = self.custom_args['prep_device'] self.modules = ' '.join(Defaults.get_grub_ofw_modules()) self.install_arguments.append('--skip-fs-probe') self.install_arguments.append('--no-nvram') elif self.arch.startswith('s390'): self.target = 's390x-emu' self.install_device = self.device self.modules = ' '.join(Defaults.get_grub_s390_modules()) self.install_arguments.append('--skip-fs-probe') self.install_arguments.append('--no-nvram') else: raise KiwiBootLoaderGrubPlatformError( 'host architecture %s not supported for grub2 installation' % self.arch ) self.root_mount = MountManager( device=self.custom_args['root_device'] ) if 's390' in self.arch: self.boot_mount = MountManager( device=self.custom_args['boot_device'], mountpoint=self.root_mount.mountpoint + '/boot/zipl' ) else: self.boot_mount = MountManager( device=self.custom_args['boot_device'], mountpoint=self.root_mount.mountpoint + '/boot' ) if self.custom_args.get('efi_device'): self.efi_mount = MountManager( device=self.custom_args['efi_device'], mountpoint=self.root_mount.mountpoint + '/boot/efi' ) self.root_mount.mount() if not self.root_mount.device == self.boot_mount.device: self.boot_mount.mount() if self.efi_mount: self.efi_mount.mount() if self.volumes: for volume_path in Path.sort_by_hierarchy( sorted(self.volumes.keys()) ): volume_mount = MountManager( device=self.volumes[volume_path]['volume_device'], mountpoint=self.root_mount.mountpoint + '/' + volume_path ) self.volumes_mount.append(volume_mount) volume_mount.mount( options=[self.volumes[volume_path]['volume_options']] ) self.device_mount = MountManager( device='/dev', mountpoint=self.root_mount.mountpoint + '/dev' ) self.proc_mount = MountManager( device='/proc', mountpoint=self.root_mount.mountpoint + '/proc' ) self.sysfs_mount = MountManager( device='/sys', mountpoint=self.root_mount.mountpoint + '/sys' ) self.device_mount.bind_mount() self.proc_mount.bind_mount() self.sysfs_mount.bind_mount() # check if a grub installation could be found in the image system module_directory = Defaults.get_grub_path( self.root_mount.mountpoint, self.target, raise_on_error=False ) if not module_directory: raise KiwiBootLoaderGrubDataError( 'No grub2 installation found in {0} for target {1}'.format( self.root_mount.mountpoint, self.target ) ) module_directory = module_directory.replace( self.root_mount.mountpoint, '' ) boot_directory = '/boot' # wipe existing grubenv to allow the grub installer to create a new one grubenv_glob = os.sep.join( [self.root_mount.mountpoint, 'boot', '*', 'grubenv'] ) for grubenv in glob.glob(grubenv_glob): Path.wipe(grubenv) # install grub2 boot code if self.firmware.get_partition_table_type() == 'dasd': # On s390 and in CDL mode (4k DASD) the call of grub2-install # does not work because grub2-install is not able to identify # a 4k fdasd partitioned device as a grub supported device # and fails. As grub2-install is only used to invoke # grub2-zipl-setup and has no other job to do we can # circumvent this problem by directly calling grub2-zipl-setup # instead. Command.run( [ 'chroot', self.root_mount.mountpoint, 'grub2-zipl-setup', '--keep' ] ) zipl_config_file = ''.join( [ self.root_mount.mountpoint, '/boot/zipl/config' ] ) zipl2grub_config_file_orig = ''.join( [ self.root_mount.mountpoint, '/etc/default/zipl2grub.conf.in.orig' ] ) if os.path.exists(zipl2grub_config_file_orig): Command.run( [ 'mv', zipl2grub_config_file_orig, zipl2grub_config_file_orig.replace('.orig', '') ] ) if os.path.exists(zipl_config_file): Command.run( ['mv', zipl_config_file, zipl_config_file + '.kiwi'] ) else: Command.run( [ 'chroot', self.root_mount.mountpoint, self._get_grub2_install_tool_name( self.root_mount.mountpoint ) ] + self.install_arguments + [ '--directory', module_directory, '--boot-directory', boot_directory, '--target', self.target, '--modules', self.modules, self.install_device ] ) if self.firmware and self.firmware.efi_mode() == 'uefi': shim_install = self._get_shim_install_tool_name( self.root_mount.mountpoint ) # if shim-install does _not_ exist the fallback mechanism # has applied at the bootloader/config level and we expect # no further tool calls to be required if shim_install: # Before we call shim-install, the grub installer binary is # replaced by a noop. Actually there is no reason for # shim-install to call the grub installer because it should # only setup the system for EFI secure boot which does not # require any bootloader code in the master boot record. # In addition kiwi has called the grub installer right # before self._disable_grub2_install(self.root_mount.mountpoint) Command.run( [ 'chroot', self.root_mount.mountpoint, 'shim-install', '--removable', self.install_device ] ) # restore the grub installer noop self._enable_grub2_install(self.root_mount.mountpoint)