This document describes which components are involved and how they cooperate to create a partitioning proposal for AutoYaST.
When it comes to partitioning, we can categorize AutoYaST use cases into three different levels:
- Automatic partitioning. The user does not care about the partitioning and trusts in AutoYaST to do the right thing.
- Semi-automatic partitioning. The user would like to set some basic settings. E.g., a user would like to use LVM but has no idea about how to configure devices and partitions.
- Expert partitioning. The user specifies how the layout should look. However, a complete definition is not required, and AutoYaST should propose reasonable defaults for missing parts.
An AutoYaST profile can define two different kinds of storage settings:
- General settings, which allows altering the
partitioning
section of the product features and enabling/disabling multipath. - Partitioning layout settings, which defines how the partitioning should look like (partitions, volume groups, RAIDs devices, etc.).
Translating these groups of settings to use cases levels:
- Level 1: no settings at all.
- Level 2: just general settings.
- Level 3: partitioning layout settings and, optionally, general settings.
The AutoYaST partitioning process starts in the storage_auto client, which
lives in the autoyast2-installation
package. This client relies heavily on the
AutoinstStorage module, which is responsible, among other things, of
importing the AutoYaST profile (via the #Import
method) and performing the
partitioning (#Write
).
This document focuses on the #Import
method, which creates a partitioning
proposal and provides libstorage-ng with the desired devicegraph. The
following is just a sketch of the steps of the partitioning process (the rest of
the sections contain the details for all of them):
- The general settings are imported. It happens before the
AutoinstStorage#Import
method is called. - The settings are preprocessed. Currently, the only preprocessing which
takes place is replacing
device=ask
with a real device name after asking the user. Any preprocessing which implies interacting with the user should be done at this point. - Build the proposed devicegraph. It is the complicated part, and it involves a lot of stuff that is described later.
- If any issue is found during step 3, present it to the user.
The third step is quite generic, and it is completely different depending on the use case. The Y2Autoinstall::StorageProposal class decides which approach to follow:
- If there is no
<partitioning>
section, AutoYaST relies in the {Y2Storage::GuidedProposal} class (levels 1 and 2). - If a
<partitioning>
section exists, AutoYaST applies an specific process (level 3).
In this case, the user does not specify any partitioning setting, and AutoYaST is responsible for proposing a sensible layout. Under the hood, AutoYaST basically relies on the {Y2Storage::GuidedProposal} using the default configuration for the installation product.
With this approach, the user can define some high-level settings and let AutoYaST build the proposal.
<general>
<storage>
<proposal>
<lvm config:type="boolean">true</lvm>
</proposal>
<start_multipath config:type="boolean">true</start_multipath>
</storage>
</general>
The elements in the proposal
section are merged with those in the product's
control file. It is like adjusting the guided proposal parameters in the regular
installer. However, only a few of them are supported.
When the profile contains a partitioning
section, AutoYaST does not use the
guided proposal, but it follows these steps (see {Y2Storage::AutoinstProposal}):
- Convert the AutoYaST profile --a hash containing nested hashes and arrays-- into something better to work with.
- Associate each
drive
section included in the profile with a real device. - Plan for new stuff by creating a set of planned devices.
- Delete unwanted stuff from the devicegraph.
- Modify the devicegraph according to the list of planned devices.
- Add devices required to boot if needed.
As you may know, an AutoYaST profile is basically an XML file which is converted into a complex hash, including nested hashes and arrays. Working with such a data structure is not convenient at all. For that reason, as a first step, the partitioning section of the profile is turned into a {Y2Storage::AutoinstProfile::PartitioningSection} object, which offers a better API for this use case.
This class does not work in isolation, as each section of the profile is represented by different classes ({Y2Storage::AutoinstProfile::DriveSection}, {Y2Storage::AutoinstProfile::PartitionSection}, etc.).
As a side note, the {Y2Storage::AutoinstProfile::PartitioningSection} class is used when cloning a system too. Check the {Y2Storage::AutoinstProfile::PartitioningSection.new_from_storage} method for further details.
The partitioning
section of the AutoYaST profile is organized into drives
containing a list of partitions
each. The result must honor that organization.
E.g., two partitions that are listed in the same drive will always end up in the
same disk and two partitions in different drives cannot end up sharing the disk.
The matching between a drive and the real disk can be done explicitly in the
profile (using the device
tag) or can be left for AutoYaST to decide. In the
latter case, the algorithm used by AutoYaST is dead simple: it just tries to use
the first available device that is not explicitly skipped (there is also a
syntax for skipping devices). The documentation states it tries to find a device
that "looks reasonable" but, in reality, it just uses whatever is not skipped,
with no optimization in place or even without checking if the device is big
enough.
The relationship between profile and real drives is kept in an instance of {Y2Storage::Proposal::AutoinstDrivesMap}.
With the drives map in-place, the profile information can already be used to create {Y2Storage::Planned::Device} objects. Those objects are meant to contain information about the devices that will be created or reused. There are especialized classes for each device: {Y2Storage::Planned::Partition}, {Y2Storage::Planned::LvmLv}, {Y2Storage::Planned::LvmVg}, {Y2Storage::Planned::Md}, {Y2Storage::Planned::Bcache}, {Y2Storage::Planned::StrayBlkDevice}, {Y2Storage::Planned::Nfs} and {Y2Storage::Planned::Btrfs} for multi-device Btrfs filesystems.
The class responsible for driving this phase is
{Y2Storage::Proposal::AutoinstDevicesPlanner}. Basically, it goes through the
list of drives contained in the profile creating the corresponding planned
devices according to the type
(:CT_DISK
, :CT_LVM
, etc.).
However, each type of drive is processed by a different planner class:
- {Y2Storage::Proposal::AutoinstDiskDevicePlanner} for
:CT_DISK
andCT_DMMULTIPATH
(the latter is deprecated). - {Y2Storage::Proposal::AutoinstVgPlanner} for
:CT_LVM
. - {Y2Storage::Proposal::AutoinstMdPlanner} for
:CT_MD
. - {Y2Storage::Proposal::AutoinstBcachePlanner} for
:CT_BCACHE
. - {Y2Storage::Proposal::AutoinstNfsPlanner} for
:CT_NFS
. - {Y2Storage::Proposal::AutoinstBtrfsPlanner} for
:CT_BTRFS
.
All delete operations are postponed until the list of planned devices is ready. The reason is that AutoYaST needs to know which devices are going to be reused to avoid removing them.
{Y2Storage::Proposal::AutoinstSpaceMaker} is the class responsible for cleaning
up the devicegraph according to the use
and initialize
attributes of each
drive section.
This phase consists on updating the devicegraph to contain the planned devices. For that purpose, and similarly to the {Y2Storage::Proposal::AutoinstDevicesPlanner} case, a {Y2Storage::Proposal::AutoinstDevicesCreator} class exists. It receives the devicegraph and the list of planned devices.
The logic to create each plan device, however, is splitted into several classes:
- {Y2Storage::Proposal::LvmCreator} for {Y2Storage::Planned::LvmVg}.
- {Y2Storage::Proposal::AutoinstMdCreator} for {Y2Storage::Planned::Md}.
- {Y2Storage::Proposal::AutoinstBcacheCreator} for {Y2Storage::Planned::Bcache}.
- {Y2Storage::Proposal::NfsCreator} for {Y2Storage::Planned::Nfs}.
- {Y2Storage::Proposal::BtrfsCreator} for {Y2Storage::Planned::Btrfs}.
Note that there are no separate classes for {Y2Storage::Planned::Disk} and {Y2Storage::Planned::StrayBlkDevice}. The logic for that kind of devices lives in the {Y2Storage::Proposal::AutoinstDevicesCreator} for historical reasons and, ideally, it should be extracted.
It is worth to mention that, if not enough space is found, AutoYaST will try to reduce the size of the planned devices to make them fit. Check the {Y2Storage::Proposal::AutoinstPartitionSize} for further details.
After adjusting the devicegraph to include the list of planned devices, AutoYaST checks whether the resulting system is bootable. If that's not the case, AutoYaST will try to add the needed devices to the devicegraph.
{Y2Storage::BootRequirementsChecker} is the class responsible for finding out whether the system is bootable and determining the missing partitions (if any).
It is possible that, given a profile, AutoYaST finds issues when trying to figure out the partitioning layout. Some of those issues might be severe enough to stop the installation; in other cases, it just displays a warning.
The {Y2Storage::AutoinstIssues} module uses Installation::AutoinstIssues::List (defined in yast2 package). {Y2Storage::AutoinstIssues} contains a set of possible issues -- all of them are classes which inherit from Installation::AutoinstIssues::Issue --.