# # Copyright (C) 2019 Red Hat, Inc. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. Any Red Hat trademarks that are incorporated in the # source code or documentation are not subject to the GNU General Public # License and may only be used or replicated with the express permission of # Red Hat, Inc. # from blivet.partitioning import do_partitioning, grow_lvm from blivet.static_data import luks_data from pyanaconda.anaconda_loggers import get_module_logger from pyanaconda.modules.common.structures.partitioning import PartitioningRequest from pyanaconda.modules.storage.partitioning.automatic.noninteractive_partitioning import \ NonInteractivePartitioningTask from pyanaconda.modules.storage.partitioning.automatic.utils import get_candidate_disks, \ schedule_implicit_partitions, schedule_volumes, schedule_partitions, get_pbkdf_args, \ get_default_partitioning, get_part_spec, get_disks_for_implicit_partitions from pyanaconda.core.storage import suggest_swap_size log = get_module_logger(__name__) __all__ = ["AutomaticPartitioningTask"] class AutomaticPartitioningTask(NonInteractivePartitioningTask): """A task for the automatic partitioning configuration.""" def __init__(self, storage, request: PartitioningRequest): """Create a task. :param storage: an instance of Blivet :param request: an instance of PartitioningRequest """ super().__init__(storage) self._request = request def _get_initialization_config(self): """Get the initialization config. FIXME: This is a temporary method. """ config = super()._get_initialization_config() # If autopart is selected we want to remove whatever has been created/scheduled # to make room for autopart. If custom is selected, we want to leave alone any # storage layout the user may have set up before now. config.clear_non_existent = True return config def _configure_partitioning(self, storage): """Configure the partitioning. :param storage: an instance of Blivet """ log.debug("Executing the automatic partitioning.") # Get the partitioning scheme. scheme = self._request.partitioning_scheme # Set the filesystem type. fstype = self._request.file_system_type if fstype: storage.set_default_fstype(fstype) # Get the encryption configuration. encrypted = self._request.encrypted # Get LUKS format args. luks_format_args = self._get_luks_format_args(self._storage, self._request) # Set the default pbkdf args. pbkdf_args = luks_format_args.get('pbkdf_args', None) if pbkdf_args and not luks_data.pbkdf_args: luks_data.pbkdf_args = pbkdf_args # Get the autopart requests. requests = self._get_partitioning(storage, scheme, self._request) # Do the autopart. self._do_autopart(storage, scheme, requests, encrypted, luks_format_args) @staticmethod def _get_luks_format_args(storage, request): """Arguments for the LUKS format constructor. :param storage: blivet.Blivet instance :param request: a partitioning request :return: a dictionary of arguments """ if not request.encrypted: return {} luks_version = request.luks_version or storage.default_luks_version escrow_cert = storage.get_escrow_certificate(request.escrow_certificate) pbkdf_args = get_pbkdf_args( luks_version=luks_version, pbkdf_type=request.pbkdf or None, max_memory_kb=request.pbkdf_memory, iterations=request.pbkdf_iterations, time_ms=request.pbkdf_time ) return { "passphrase": request.passphrase, "cipher": request.cipher, "luks_version": luks_version, "pbkdf_args": pbkdf_args, "escrow_cert": escrow_cert, "add_backup_passphrase": request.backup_passphrase_enabled, } @staticmethod def _get_partitioning(storage, scheme, request: PartitioningRequest): """Get the partitioning requests for autopart. :param storage: blivet.Blivet instance :param scheme: a type of the partitioning scheme :param request: partitioning parameters :return: a list of full partitioning specs """ specs = [] swap = None # Create partitioning specs based on the default configuration. for spec in get_default_partitioning(): # Skip mount points excluded from the chosen scheme. if spec.schemes and scheme not in spec.schemes: continue # Skip excluded mount points. if (spec.mountpoint or spec.fstype) in request.excluded_mount_points: continue # Detect swap. if spec.fstype == "swap": swap = spec specs.append(spec) # Add a swap if hibernation was requested in kickstart. if request.hibernation and swap is None: swap = get_part_spec({"name": "swap"}) specs.append(swap) # Configure specs. for spec in specs: # Set the default filesystem type. if spec.fstype is None: spec.fstype = storage.get_fstype(spec.mountpoint) # Update the size of swap. if spec.fstype == "swap": disk_space = storage.get_disk_free_space() swap.size = suggest_swap_size(hibernation=request.hibernation, disk_space=disk_space) return specs @staticmethod def _do_autopart(storage, scheme, requests, encrypted=False, luks_fmt_args=None): """Perform automatic partitioning. :param storage: an instance of Blivet :param scheme: a type of the partitioning scheme :param requests: list of partitioning requests :param encrypted: encrypt the scheduled partitions :param luks_fmt_args: arguments for the LUKS format constructor """ log.debug("scheme: %s", scheme) log.debug("requests:\n%s", "".join([str(p) for p in requests])) log.debug("encrypted: %s", encrypted) log.debug("storage.disks: %s", [d.name for d in storage.disks]) log.debug("storage.partitioned: %s", [d.name for d in storage.partitioned if d.format.supported]) log.debug("all names: %s", [d.name for d in storage.devices]) log.debug("boot disk: %s", getattr(storage.bootloader.stage1_disk, "name", None)) disks = get_candidate_disks(storage) log.debug("candidate disks: %s", [d.name for d in disks]) # Schedule implicit partitions. extra_disks = get_disks_for_implicit_partitions(disks, scheme, requests) devs = schedule_implicit_partitions(storage, extra_disks, scheme, encrypted, luks_fmt_args) # Schedule requested partitions. devs = schedule_partitions(storage, disks, devs, scheme, requests, encrypted, luks_fmt_args) # run the autopart function to allocate and grow partitions do_partitioning(storage, boot_disk=storage.bootloader.stage1_disk) schedule_volumes(storage, devs, scheme, requests, encrypted) # grow LVs grow_lvm(storage) # only newly added swaps should appear in the fstab new_swaps = (dev for dev in storage.swaps if not dev.format.exists) storage.set_fstab_swaps(new_swaps)