def _get_partitioning(storage, scheme, excluded_mount_points=()): """Get the partitioning requests for autopart. :param storage: blivet.Blivet instance :param scheme: a type of the partitioning scheme :param excluded_mount_points: a list of mount points to exclude :return: a list of full partitioning specs """ requests = [] for request in get_default_partitioning(): # Skip mount points excluded from the chosen scheme. if request.schemes and scheme not in request.schemes: continue # Skip excluded mount points. if (request.mountpoint or request.fstype) in excluded_mount_points: continue # Set the default filesystem type. if request.fstype is None: request.fstype = storage.get_fstype(request.mountpoint) # Update the size of swap. if request.fstype == "swap": disk_space = storage.get_disk_free_space() request.size = suggest_swap_size(disk_space=disk_space) requests.append(request) return requests
def _check_space_and_run_dialog(self, partitioning, disks): # User wants to reclaim the space. if self._reclaim_checkbox.get_active(): return RESPONSE_RECLAIM # Get the device tree of the partitioning module. device_tree = STORAGE.get_proxy(partitioning.GetDeviceTree()) # Calculate the required and free space. disk_free = Size(device_tree.GetDiskFreeSpace(disks)) fs_free = Size(device_tree.GetDiskReclaimableSpace(disks)) disks_size = Size(device_tree.GetDiskTotalSpace(disks)) sw_space = Size(self.payload.space_required) auto_swap = suggest_swap_size() log.debug("disk free: %s fs free: %s sw needs: %s auto swap: %s", disk_free, fs_free, sw_space, auto_swap) # We need enough space for the software, the swap and the metadata. # It is not an ideal estimate, but it works. required_space = sw_space + auto_swap + STORAGE_METADATA_RATIO * disk_free # There is enough space to continue. if disk_free >= required_space: return RESPONSE_OK # Ask user what to do. if disks_size >= required_space - auto_swap: dialog = NeedSpaceDialog(self.data, payload=self.payload) dialog.refresh(required_space, sw_space, auto_swap, disk_free, fs_free) else: dialog = NoSpaceDialog(self.data, payload=self.payload) dialog.refresh(required_space, sw_space, auto_swap, disk_free, fs_free) return self.run_lightbox_dialog(dialog)
def _execute_logvol_data(self, storage, data, logvol_data): """Execute the logvol data. :param storage: an instance of the Blivet's storage object :param data: an instance of kickstart data :param logvol_data: an instance of LogVolData """ devicetree = storage.devicetree # FIXME: we should be running sanityCheck on partitioning that is not ks # autopart, but that's likely too invasive for #873135 at this moment if logvol_data.mountpoint == "/boot" and blivet.arch.is_s390(): raise StorageError( _("/boot cannot be of type \"lvmlv\" on s390x") ) # we might have truncated or otherwise changed the specified vg name vgname = data.onPart.get(logvol_data.vgname, logvol_data.vgname) size = None if logvol_data.percent: size = Size(0) if logvol_data.mountpoint == "swap": ty = "swap" logvol_data.mountpoint = "" if logvol_data.recommended or logvol_data.hibernation: disk_space = self._disk_free_space size = suggest_swap_size( hibernation=logvol_data.hibernation, disk_space=disk_space ) logvol_data.grow = False else: if logvol_data.fstype != "": ty = logvol_data.fstype else: ty = storage.default_fstype if size is None and not logvol_data.preexist: if not logvol_data.size: raise StorageError( _("Size cannot be decided on from kickstart nor obtained from device.") ) size = self._get_size(logvol_data.size, "MiB") if logvol_data.thin_pool: logvol_data.mountpoint = "" ty = None # Sanity check mountpoint self._check_mount_point(logvol_data.mountpoint) # Check that the VG this LV is a member of has already been specified. vg = devicetree.get_device_by_name(vgname) if not vg: raise StorageError( _("No volume group exists with the name \"{}\". Specify volume " "groups before logical volumes.").format(logvol_data.vgname) ) # If cache PVs specified, check that they belong to the same VG this LV is a member of if logvol_data.cache_pvs: pv_devices = self._get_cache_pv_devices(devicetree, logvol_data) if not all(pv in vg.pvs for pv in pv_devices): raise StorageError( _("Cache PVs must belong to the same VG as the cached LV") ) pool = None if logvol_data.thin_volume: pool = devicetree.get_device_by_name("%s-%s" % (vg.name, logvol_data.pool_name)) if not pool: raise StorageError( _("No thin pool exists with the name \"{}\". Specify thin pools " "before thin volumes.").format(logvol_data.pool_name) ) # If this specifies an existing request that we should not format, # quit here after setting up enough information to mount it later. if not logvol_data.format: if not logvol_data.name: raise StorageError( _("logvol --noformat must also use the --name= option.") ) dev = devicetree.get_device_by_name("%s-%s" % (vg.name, logvol_data.name)) if not dev: raise StorageError( _("Logical volume \"{}\" given in logvol command does " "not exist.").format(logvol_data.name) ) if logvol_data.resize: size = dev.raw_device.align_target_size(size) if size < dev.currentSize: # shrink try: devicetree.actions.add(ActionResizeFormat(dev, size)) devicetree.actions.add(ActionResizeDevice(dev, size)) except ValueError as e: self._handle_invalid_target_size(e, logvol_data.size, dev.name) else: # grow try: devicetree.actions.add(ActionResizeDevice(dev, size)) devicetree.actions.add(ActionResizeFormat(dev, size)) except ValueError as e: self._handle_invalid_target_size(e, logvol_data.size, dev.name) dev.format.mountpoint = logvol_data.mountpoint dev.format.mountopts = logvol_data.fsopts if ty == "swap": storage.add_fstab_swap(dev) return # Make sure this LV name is not already used in the requested VG. if not logvol_data.preexist: tmp = devicetree.get_device_by_name("%s-%s" % (vg.name, logvol_data.name)) if tmp: raise StorageError( _("Logical volume name \"{}\" is already in use in volume group " "\"{}\".").format(logvol_data.name, vg.name) ) if not logvol_data.percent and size and not logvol_data.grow and size < vg.pe_size: raise StorageError( _("Logical volume size \"{}\" must be larger than the volume " "group extent size of \"{}\".").format(size, vg.pe_size) ) # Now get a format to hold a lot of these extra values. fmt = get_format( ty, mountpoint=logvol_data.mountpoint, label=logvol_data.label, fsprofile=logvol_data.fsprofile, create_options=logvol_data.mkfsopts, mountopts=logvol_data.fsopts ) if not fmt.type and not logvol_data.thin_pool: raise StorageError( _("The \"{}\" file system type is not supported.").format(ty) ) add_fstab_swap = None # If we were given a pre-existing LV to create a filesystem on, we need # to verify it and its VG exists and then schedule a new format action # to take place there. Also, we only support a subset of all the # options on pre-existing LVs. if logvol_data.preexist: device = devicetree.get_device_by_name("%s-%s" % (vg.name, logvol_data.name)) if not device: raise StorageError( _("Logical volume \"{}\" given in logvol command does " "not exist.").format(logvol_data.name) ) storage.devicetree.recursive_remove(device, remove_device=False) if logvol_data.resize: size = device.raw_device.align_target_size(size) try: devicetree.actions.add(ActionResizeDevice(device, size)) except ValueError as e: self._handle_invalid_target_size(e, logvol_data.size, device.name) devicetree.actions.add(ActionCreateFormat(device, fmt)) if ty == "swap": add_fstab_swap = device else: # If a previous device has claimed this mount point, delete the # old one. try: if logvol_data.mountpoint: device = storage.mountpoints[logvol_data.mountpoint] storage.destroy_device(device) except KeyError: pass if logvol_data.thin_volume: parents = [pool] else: parents = [vg] pool_args = {} if logvol_data.thin_pool: if logvol_data.profile: matching = (p for p in KNOWN_THPOOL_PROFILES if p.name == logvol_data.profile) profile = next(matching, None) if profile: pool_args["profile"] = profile else: log.warning( "No matching profile for %s found in LVM configuration", logvol_data.profile ) if logvol_data.metadata_size: pool_args["metadata_size"] = Size("%d MiB" % logvol_data.metadata_size) if logvol_data.chunk_size: pool_args["chunk_size"] = Size("%d KiB" % logvol_data.chunk_size) if logvol_data.maxSizeMB: maxsize = self._get_size(logvol_data.maxSizeMB, "MiB") else: maxsize = None if logvol_data.cache_size and logvol_data.cache_pvs: pv_devices = self._get_cache_pv_devices(devicetree, logvol_data) cache_size = Size("%d MiB" % logvol_data.cache_size) cache_mode = logvol_data.cache_mode or None cache_request = LVMCacheRequest(cache_size, pv_devices, cache_mode) else: cache_request = None request = storage.new_lv( fmt=fmt, name=logvol_data.name, parents=parents, size=size, thin_pool=logvol_data.thin_pool, thin_volume=logvol_data.thin_volume, grow=logvol_data.grow, maxsize=maxsize, percent=logvol_data.percent, cache_request=cache_request, **pool_args ) storage.create_device(request) if ty == "swap": add_fstab_swap = request if logvol_data.encrypted: passphrase = self._get_passphrase(logvol_data) cert = storage.get_escrow_certificate(logvol_data.escrowcert) # Get the version of LUKS and PBKDF arguments. logvol_data.luks_version = logvol_data.luks_version or storage.default_luks_version pbkdf_args = get_pbkdf_args( luks_version=logvol_data.luks_version, pbkdf_type=logvol_data.pbkdf, max_memory_kb=logvol_data.pbkdf_memory, iterations=logvol_data.pbkdf_iterations, time_ms=logvol_data.pbkdf_time ) if pbkdf_args and not luks_data.pbkdf_args: luks_data.pbkdf_args = pbkdf_args if logvol_data.preexist: luksformat = fmt device.format = get_format( "luks", passphrase=passphrase, device=device.path, cipher=logvol_data.cipher, escrow_cert=cert, add_backup_passphrase=logvol_data.backuppassphrase, luks_version=logvol_data.luks_version, pbkdf_args=pbkdf_args ) luksdev = LUKSDevice( "luks%d" % storage.next_id, fmt=luksformat, parents=device ) else: luksformat = request.format request.format = get_format( "luks", passphrase=passphrase, cipher=logvol_data.cipher, escrow_cert=cert, add_backup_passphrase=logvol_data.backuppassphrase, luks_version=logvol_data.luks_version, pbkdf_args=pbkdf_args ) luksdev = LUKSDevice( "luks%d" % storage.next_id, fmt=luksformat, parents=request ) if ty == "swap": # swap is on the LUKS device not on the LUKS' parent device, # override the info here add_fstab_swap = luksdev storage.create_device(luksdev) if add_fstab_swap: storage.add_fstab_swap(add_fstab_swap)
def _execute_partition_data(self, storage, data, partition_data): """Execute the partition data. :param storage: an instance of the Blivet's storage object :param data: an instance of kickstart data :param partition_data: an instance of PartData """ devicetree = storage.devicetree kwargs = {} if partition_data.onbiosdisk != "": # edd_dict is only modified during storage.reset(), so don't do that # while executing storage. for (disk, biosdisk) in storage.edd_dict.items(): if "%x" % biosdisk == partition_data.onbiosdisk: partition_data.disk = disk break if not partition_data.disk: raise StorageError( _("No disk found for specified BIOS disk \"{}\".").format( partition_data.onbiosdisk ) ) size = None if partition_data.mountpoint == "swap": ty = "swap" partition_data.mountpoint = "" if partition_data.recommended or partition_data.hibernation: disk_space = self._disk_free_space size = suggest_swap_size( hibernation=partition_data.hibernation, disk_space=disk_space ) partition_data.grow = False # if people want to specify no mountpoint for some reason, let them # this is really needed for pSeries boot partitions :( elif partition_data.mountpoint == "None": partition_data.mountpoint = "" if partition_data.fstype: ty = partition_data.fstype else: ty = storage.default_fstype elif partition_data.mountpoint == 'appleboot': ty = "appleboot" partition_data.mountpoint = "" elif partition_data.mountpoint == 'prepboot': ty = "prepboot" partition_data.mountpoint = "" elif partition_data.mountpoint == 'biosboot': ty = "biosboot" partition_data.mountpoint = "" elif partition_data.mountpoint.startswith("raid."): ty = "mdmember" kwargs["name"] = partition_data.mountpoint partition_data.mountpoint = "" if devicetree.get_device_by_name(kwargs["name"]): raise StorageError( _("RAID partition \"{}\" is defined multiple times.").format(kwargs["name"]) ) if partition_data.onPart: data.onPart[kwargs["name"]] = partition_data.onPart elif partition_data.mountpoint.startswith("pv."): ty = "lvmpv" kwargs["name"] = partition_data.mountpoint partition_data.mountpoint = "" if devicetree.get_device_by_name(kwargs["name"]): raise StorageError( _("PV partition \"{}\" is defined multiple times.").format(kwargs["name"]) ) if partition_data.onPart: data.onPart[kwargs["name"]] = partition_data.onPart elif partition_data.mountpoint.startswith("btrfs."): ty = "btrfs" kwargs["name"] = partition_data.mountpoint partition_data.mountpoint = "" if devicetree.get_device_by_name(kwargs["name"]): raise StorageError( _("Btrfs partition \"{}\" is defined multiple times.").format(kwargs["name"]) ) if partition_data.onPart: data.onPart[kwargs["name"]] = partition_data.onPart elif partition_data.mountpoint == "/boot/efi": if blivet.arch.is_mactel(): ty = "macefi" else: ty = "EFI System Partition" partition_data.fsopts = "defaults,uid=0,gid=0,umask=077,shortname=winnt" else: if partition_data.fstype != "": ty = partition_data.fstype elif partition_data.mountpoint == "/boot": ty = storage.default_boot_fstype else: ty = storage.default_fstype if not size and partition_data.size: size = self._get_size(partition_data.size, "MiB") # If this specified an existing request that we should not format, # quit here after setting up enough information to mount it later. if not partition_data.format: if not partition_data.onPart: raise StorageError(_("part --noformat must also use the --onpart option.")) dev = devicetree.resolve_device(partition_data.onPart) if not dev: raise StorageError( _("Partition \"{}\" given in part command does " "not exist.").format(partition_data.onPart) ) if partition_data.resize: size = dev.raw_device.align_target_size(size) if size < dev.currentSize: # shrink try: devicetree.actions.add(ActionResizeFormat(dev, size)) devicetree.actions.add(ActionResizeDevice(dev, size)) except ValueError as e: self._handle_invalid_target_size(e, partition_data.size, dev.name) else: # grow try: devicetree.actions.add(ActionResizeDevice(dev, size)) devicetree.actions.add(ActionResizeFormat(dev, size)) except ValueError as e: self._handle_invalid_target_size(e, partition_data.size, dev.name) dev.format.mountpoint = partition_data.mountpoint dev.format.mountopts = partition_data.fsopts if ty == "swap": storage.add_fstab_swap(dev) return # Now get a format to hold a lot of these extra values. kwargs["fmt"] = get_format(ty, mountpoint=partition_data.mountpoint, label=partition_data.label, fsprofile=partition_data.fsprofile, mountopts=partition_data.fsopts, create_options=partition_data.mkfsopts, size=size) if not kwargs["fmt"].type: raise StorageError( _("The \"{}\" file system type is not supported.").format(ty) ) # If we were given a specific disk to create the partition on, verify # that it exists first. If it doesn't exist, see if it exists with # mapper/ on the front. If that doesn't exist either, it's an error. if partition_data.disk: disk = devicetree.resolve_device(partition_data.disk) # if this is a multipath member promote it to the real mpath if disk and disk.format.type == "multipath_member": mpath_device = disk.children[0] log.info("kickstart: part: promoting %s to %s", disk.name, mpath_device.name) disk = mpath_device if not disk: raise StorageError( _("Disk \"{}\" given in part command does " "not exist.").format(partition_data.disk) ) if not disk.partitionable: raise StorageError( _("Cannot install to unpartitionable device " "\"{}\".").format(partition_data.disk) ) if disk and disk.partitioned: kwargs["parents"] = [disk] elif disk: raise StorageError( _("Disk \"{}\" in part command is not " "partitioned.").format(partition_data.disk) ) if not kwargs["parents"]: raise StorageError( _("Disk \"{}\" given in part command does " "not exist.").format(partition_data.disk) ) kwargs["grow"] = partition_data.grow kwargs["size"] = size if partition_data.maxSizeMB: maxsize = self._get_size(partition_data.maxSizeMB, "MiB") else: maxsize = None kwargs["maxsize"] = maxsize kwargs["primary"] = partition_data.primOnly add_fstab_swap = None # If we were given a pre-existing partition to create a filesystem on, # we need to verify it exists and then schedule a new format action to # take place there. Also, we only support a subset of all the options # on pre-existing partitions. if partition_data.onPart: device = devicetree.resolve_device(partition_data.onPart) if not device: raise StorageError( _("Partition \"{}\" given in part command does " "not exist.").format(partition_data.onPart) ) storage.devicetree.recursive_remove(device, remove_device=False) if partition_data.resize: size = device.raw_device.align_target_size(size) try: devicetree.actions.add(ActionResizeDevice(device, size)) except ValueError as e: self._handle_invalid_target_size(e, partition_data.size, device.name) devicetree.actions.add(ActionCreateFormat(device, kwargs["fmt"])) if ty == "swap": add_fstab_swap = device # tmpfs mounts are not disks and don't occupy a disk partition, # so handle them here elif partition_data.fstype == "tmpfs": request = storage.new_tmp_fs(**kwargs) storage.create_device(request) else: # If a previous device has claimed this mount point, delete the # old one. try: if partition_data.mountpoint: device = storage.mountpoints[partition_data.mountpoint] storage.destroy_device(device) except KeyError: pass request = storage.new_partition(**kwargs) storage.create_device(request) if ty == "swap": add_fstab_swap = request if partition_data.encrypted: passphrase = self._get_passphrase(partition_data) cert = storage.get_escrow_certificate(partition_data.escrowcert) # Get the version of LUKS and PBKDF arguments. partition_data.luks_version = (partition_data.luks_version or storage.default_luks_version) pbkdf_args = get_pbkdf_args( luks_version=partition_data.luks_version, pbkdf_type=partition_data.pbkdf, max_memory_kb=partition_data.pbkdf_memory, iterations=partition_data.pbkdf_iterations, time_ms=partition_data.pbkdf_time ) if pbkdf_args and not luks_data.pbkdf_args: luks_data.pbkdf_args = pbkdf_args if partition_data.onPart: luksformat = kwargs["fmt"] device.format = get_format( "luks", passphrase=passphrase, device=device.path, cipher=partition_data.cipher, escrow_cert=cert, add_backup_passphrase=partition_data.backuppassphrase, luks_version=partition_data.luks_version, pbkdf_args=pbkdf_args ) luksdev = LUKSDevice( "luks%d" % storage.next_id, fmt=luksformat, parents=device ) else: luksformat = request.format request.format = get_format( "luks", passphrase=passphrase, cipher=partition_data.cipher, escrow_cert=cert, add_backup_passphrase=partition_data.backuppassphrase, luks_version=partition_data.luks_version, pbkdf_args=pbkdf_args ) luksdev = LUKSDevice("luks%d" % storage.next_id, fmt=luksformat, parents=request) if ty == "swap": # swap is on the LUKS device not on the LUKS' parent device, # override the info here add_fstab_swap = luksdev storage.create_device(luksdev) if add_fstab_swap: storage.add_fstab_swap(add_fstab_swap)