190 lines
6.7 KiB
Python
190 lines
6.7 KiB
Python
|
#
|
||
|
# Manual partitioning module.
|
||
|
#
|
||
|
# Copyright (C) 2018 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.size import Size
|
||
|
|
||
|
from pyanaconda.anaconda_loggers import get_module_logger
|
||
|
from pyanaconda.core.signal import Signal
|
||
|
from pyanaconda.modules.common.structures.partitioning import MountPointRequest
|
||
|
from pyanaconda.modules.storage.partitioning.base import PartitioningModule
|
||
|
from pyanaconda.modules.storage.partitioning.constants import PartitioningMethod
|
||
|
from pyanaconda.modules.storage.partitioning.manual.manual_interface import \
|
||
|
ManualPartitioningInterface
|
||
|
from pyanaconda.modules.storage.partitioning.manual.manual_partitioning import \
|
||
|
ManualPartitioningTask
|
||
|
|
||
|
log = get_module_logger(__name__)
|
||
|
|
||
|
|
||
|
class ManualPartitioningModule(PartitioningModule):
|
||
|
"""The manual partitioning module."""
|
||
|
|
||
|
def __init__(self):
|
||
|
"""Initialize the module."""
|
||
|
super().__init__()
|
||
|
self.requests_changed = Signal()
|
||
|
self._requests = list()
|
||
|
|
||
|
@property
|
||
|
def partitioning_method(self):
|
||
|
"""Type of the partitioning method."""
|
||
|
return PartitioningMethod.MANUAL
|
||
|
|
||
|
def for_publication(self):
|
||
|
"""Return a DBus representation."""
|
||
|
return ManualPartitioningInterface(self)
|
||
|
|
||
|
def process_kickstart(self, data):
|
||
|
"""Process the kickstart data."""
|
||
|
requests = []
|
||
|
|
||
|
for mount_data in data.mount.mount_points:
|
||
|
request = MountPointRequest()
|
||
|
request.mount_point = mount_data.mount_point
|
||
|
request.device_spec = mount_data.device
|
||
|
request.reformat = mount_data.reformat
|
||
|
request.format_type = mount_data.format
|
||
|
request.format_options = mount_data.mkfs_opts
|
||
|
request.mount_options = mount_data.mount_opts
|
||
|
requests.append(request)
|
||
|
|
||
|
self.set_requests(requests)
|
||
|
|
||
|
def setup_kickstart(self, data):
|
||
|
"""Setup the kickstart data."""
|
||
|
data_list = []
|
||
|
|
||
|
for request in self.requests:
|
||
|
mount_data = data.MountData()
|
||
|
mount_data.mount_point = request.mount_point
|
||
|
mount_data.device = request.device_spec
|
||
|
mount_data.reformat = request.reformat
|
||
|
mount_data.format = request.format_type
|
||
|
mount_data.mkfs_opts = request.format_options
|
||
|
mount_data.mount_opts = request.mount_options
|
||
|
data_list.append(mount_data)
|
||
|
|
||
|
data.mount.mount_points = data_list
|
||
|
|
||
|
@property
|
||
|
def requests(self):
|
||
|
"""A list of mount point requests."""
|
||
|
return self._requests
|
||
|
|
||
|
def set_requests(self, requests):
|
||
|
"""Set the list of mount point requests.
|
||
|
|
||
|
:param requests: a list of instances of MountPointRequest
|
||
|
"""
|
||
|
self._requests = requests
|
||
|
self.requests_changed.emit()
|
||
|
log.debug("Requests are set to '%s'.", requests)
|
||
|
|
||
|
def gather_requests(self):
|
||
|
"""Gather all mount point requests.
|
||
|
|
||
|
Return mount point requests for all usable devices. If there is
|
||
|
a defined request for the given device, we will use it. Otherwise,
|
||
|
we will generate a new request.
|
||
|
|
||
|
:return: a list of instances of MountPointRequest
|
||
|
"""
|
||
|
available_requests = set(self.requests)
|
||
|
requests = []
|
||
|
|
||
|
for device in self._iterate_usable_devices():
|
||
|
# Find an existing request.
|
||
|
request = self._find_request_for_device(device, available_requests)
|
||
|
|
||
|
# And use it only once.
|
||
|
if request:
|
||
|
available_requests.remove(request)
|
||
|
# Otherwise, create a new request.
|
||
|
else:
|
||
|
request = self._create_request_for_device(device)
|
||
|
|
||
|
# Add the request for this device.
|
||
|
requests.append(request)
|
||
|
|
||
|
return requests
|
||
|
|
||
|
def _iterate_usable_devices(self):
|
||
|
"""Iterate over all usable devices.
|
||
|
|
||
|
:return: an iterator over Blivet's devices
|
||
|
"""
|
||
|
selected_disks = set(self._selected_disks)
|
||
|
|
||
|
for device in self.storage.devicetree.devices:
|
||
|
if not device.isleaf and not device.raw_device.type == "btrfs subvolume":
|
||
|
continue
|
||
|
|
||
|
# We don't want to allow to use snapshots in mount point assignment.
|
||
|
if device.raw_device.type == "btrfs snapshot":
|
||
|
continue
|
||
|
|
||
|
# Is the device usable?
|
||
|
if device.protected or device.size == Size(0):
|
||
|
continue
|
||
|
|
||
|
# All device's disks have to be in selected disks.
|
||
|
if selected_disks and not selected_disks.issuperset({d.name for d in device.disks}):
|
||
|
continue
|
||
|
|
||
|
yield device
|
||
|
|
||
|
def _find_request_for_device(self, device, requests):
|
||
|
"""Find a mount point request for the given device.
|
||
|
|
||
|
:param device: a Blivet's device object
|
||
|
:param requests: a list of requests to search
|
||
|
:return: an instance of MountPointRequest or None
|
||
|
"""
|
||
|
for request in requests:
|
||
|
if device is self.storage.devicetree.resolve_device(request.device_spec):
|
||
|
return request
|
||
|
|
||
|
return None
|
||
|
|
||
|
def _create_request_for_device(self, device):
|
||
|
"""Create a mount point request for the given device.
|
||
|
|
||
|
:param device: a Blivet's device object
|
||
|
:return: an instance of MountPointRequest
|
||
|
"""
|
||
|
request = MountPointRequest()
|
||
|
request.device_spec = device.name
|
||
|
request.format_type = device.format.type or ""
|
||
|
request.reformat = False
|
||
|
|
||
|
if device.format.mountable:
|
||
|
if device.format.mountpoint:
|
||
|
request.mount_point = device.format.mountpoint
|
||
|
if device.format.mountopts:
|
||
|
request.mount_options = device.format.mountopts
|
||
|
|
||
|
return request
|
||
|
|
||
|
def configure_with_task(self):
|
||
|
"""Schedule the partitioning actions."""
|
||
|
return ManualPartitioningTask(
|
||
|
self.storage,
|
||
|
self.requests
|
||
|
)
|