anaconda/anaconda-40.22.3.13/pyanaconda/modules/storage/partitioning/automatic/automatic_partitioning.py
2024-11-14 21:39:56 -08:00

209 lines
8.1 KiB
Python

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