When the size of a logical volume is not aligned to the extent size of
the volume group, LVM2 will automatically align it by rounding up[1]:
Rounding up size to full physical extent 29.80 GiB
Rounding up size to full physical extent <3.82 GiB
Since we don't take that into account when we create a new volume or
set the size of an existing one, the size for the whole volume group
will be short by that amount and thus the creation of the last volume
will fail:
Volume group <uuid> has insufficient free space (975 extents): 977 required.
To fix this a new `AlignUp` method is added to the `MountpointCreator`
creator interface. It will align a given size to the requirements of
the implementing container, like e.g. `LVMVolumeGroup`. It is then
used by a new `alignEntityBranch` which takes a size and walks the
entity path, calling `AlignUp` for all entities that implement said
`MountpointCreator` interface; thus the resulting size should fullfil
the alignment requirement for all elements in the path.
NB: `PartitionTable` already had an `AlignUp` method.
Add a corresponding test.
[1]: 8686657664/lib/metadata/metadata.c (L1072)
Co-authored-by: Achilleas Koutsou <achilleas@koutsou.net>
Since the LVM support was added to all distros, our disk
related code is adaptive, i.e. we will set the correct BLS
and grub2 prefix if there a `boot` partiton is present in
the layout after all customizations happen, which includes
LVMification.
One thing that was not yet fully working was layouts that
do not yet have a `/boot` partition but allow LVMification.
In that case `NewPartitionTable` and if `/boot` was the
first (or only) customization, would LVMify the partition
which in turn would create the `/boot` partition; but after
`newPT.ensureLVM()` the call to `newPT.createFilesystem`
with `/boot` would try to create another `/boot` mountpoint.
In order to deal with this situation correctly we are now
using a two phase approach: 1) enlarge existing mountpoints
and collect new ones. 2) if there are new ones and LMVify
was allowed, switch to LVM layout. Do a second pass and now
create or enlarge existing partitions, handling `/boot` in
the process.
Replace the simple allow list of paths with the more sophisticated
path policies. It enables us to e.g. allow one path but not any
sub-path. This will be useful for `/boot` where we want to allow
its customization but not any sub-path because that might actually
break booting.
Use the Extended Bootloader Partition GUID for `/boot`, instead of the
Linux filesystem data GUID. This is useful for autodetection of a
partition purpose based on its GUID without reading the `/etc/fstab`
first.
Ensure that when creating mountpoints, e.g. when converting the
partitions layout to LVM, the `/boot` partition get the proper GUID
assigned.
Regenerate RHEL-90 and centos-9 image test cases.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=2057231
This is only required in RHEL9.0, but best practice is to always pin these things
down. Also increases uniformity between distros.
Simplify a bit the volid generator by making it require `rand.Rand` rather than
`io.Reader`, and hence eliminating the need for error handling.
Re-introduce the VolumeContainer interface but with a different
meaning: it is supposed to be implemented by all container that
contain volumes and as a result have themselves a size, like eg
LVM2, LUKS2 and PartitionTable (the latter is not yet included).
The sole method on the interface for now is MetadataSize, which
should return the metadata for the container itself.
Use that new `VolumeContainer.MetadataSize` method when we up-
date the sizes of elements in `resizeEntitybranch`.
Add support for building images for the Azure marketplace: add a
new image type "azure-rhui" that can be used to build images
tailored to the Azure marketplace.
Add two sample manifests for 8.5 and 8.6, but note that even the
8.5 is using the 8.6 distro definitions. Also no image-info is
included since `image-info` cannot (yet) handle LVM setups and
the azure marketplace images use the LVM setup.
This is for all entities that have a uniquely identifiable via a UUID.
Currently the interface only contains a single function, GenUUID(),
that should generate a new UUID via a random source (`rand.Rand`).
NB: Partitions are uniquely identifiable if and only if the layout is
GPT.
Co-Authored-By: Achilleas Koutsou <achilleas@koutsou.net>
All disk.Entitity types now implement Clone() which should return a
deep copy of the same object. Add the Clone() method to the entity
interface. The return type is Entity, but callers can assume it's
safe to convert back to the original type.
Co-Authored-By: Christian Kellner <christian@kellner.me>
Add a generic entity data model that can be used to navigate and operate
on any specific disk image layout. Since the latter allows for arbitrary
nesting of different container types, such as LUKS2, LVM2, and with file
systems that can have sub-volumes, the entity model is very generic.
Co-Authored-By: Achilleas Koutsou <achilleas@koutsou.net>
Split up disk.go into smaller more manageable pieces: finish
by moving `Partition` to its own file.
Co-Authored-By: Christian Kellner <christian@kellner.me>
Split up disk.go into smaller more managable pieces: continue
with moving `Filesystem` to its own file.
Co-Authored-By: Christian Kellner <christian@kellner.me>
Split up disk.go into smaller more managable pieces: start with
extracting `PartitionTable` and all its methods to a new file.
Co-Authored-By: Christian Kellner <christian@kellner.me>
Use bytes internally everywhere and convert to sectors only when writing
the options for the stages.
Changed the AlignUp() method to not do the alignment if the input is
already aligned. This changes the behaviour when the size is 0, but
that's not a realistic use case. Updated unit tests to match.
Manifests are unaffected.
Co-Authored-By: Christian Kellner <christian@kellner.me>
Instead of just reserving a fixed amount of sectors for the
partition header and footer, calculate the size of the
header and footer dynamically when the layout is GPT.
Return an error if the maximum numbers of partitions has been
reached and thus creating further partitions would result in
errors.
Currently we limit MBR partition types to 4 as we dont support
logical partitions and GPT layouts to 128. According to the
UEFI specificatio (2.8) a minimum of 16384 bytes are reserved
for the partition entries array. Each entry is 128 bytes wide
thus resulting in at least 128 entries; we choose this to be
the maximum as well for now.
Align partitions during their re-layout. Specifically, we align the
first partition which removes the need for the hard coded magic
number of 2048, which represents the proper alignment for a grain
size of 1MB given a sector size of 512 (our setup).
NB: Since all our partitions should sizes that are themselves
aligned, i.e. evenly dividable by the default grain (1MB) this
will not actually change any manifest.
Add a utility method that can be used to align data to the next "grain"
which is currently defined as 1 MiB -- the default used by sfdisk.
Add corresponding tests.
Instead of hard coding a padding of 100 sectors for all layouts, i.e.
MBR and GTP, adjust the needed space depending on the layout: for MBR
we don't need to reserve any space at all since it does not have a
secondary header. For GTP we reserve 33 sectors, as indicated in the
UEFI specific, which allows for the header itself and up to 128 entries.
To not modify the layout of already released distributions, like RHEL
8.4 and 8.5, a new member called `ExtraPadding` is added to `Partition
Table` and then used in the corresponding layouts to preserve the
existing padding of 100.
Allow the sector size to be specified on the partition table level by
introducing a new `SectorSize` field. Modify the conversion helpers
to use that new field with a fallback to default sector size in case
the field is `0`.
Add simple helper methods that convert between bytes and sectors. This
is a method of `PartitionTable`, since the sector size can in theory
be per partition table and this prepares for that case.
Add a new helper to `PartitionTable` that generates all necessary
uuids for uuid fields that are empty but should not. These are
the file system uuids and, in case of a GPT layout, partition ids.
Simple wrapper around FindFilesystemForMountpoint that will
return a boolean if a filesystem with the given mountpoint
is defined in the partition table.
The `PartitionTable` object contains an array of `Partitions`, which
is shared among all shallow copies of `PartitionTable` instances, as
when it is used via a value receiver in method calls. The individual
objects are thus not fully isolated since modifications of array
elements, or in some cases modifications to the array itself, are
shared and visible between all shallow `PartitionTable` copies. Thus
use a pointer receiver for all methods of `PartitionTable` to make
it explicit that modifications will affect other objects.
The previous commit made sure that `PartitionTable.RootPartition`
is indeed returning the pointer partition object inside the array
of the `PartitionTable`. Thus changes to the returned object will
now directly affect the object and thus there is no need to call
`PartitionTable.updateRootPartition` anymore.
When we iterate over the partitions to find the root partition,
we are getting the partition by value so even if we return a
pointer to that then, it is actually a pointer duplicated object.
Return the pointer to the actual partition object instead.
In various places we are interested in the root and boot file-
systems. Currently those were accessed via by retrieving the
partition that contain them and the accessing the filesystem
member. Add accessors to `PartitionTable` that directly return
the needed filesystem. This will help if the file system is
stored inside a container like LVM or LUKS instead of directly
on a partition.
Specifying the boot partition filesystem UUID in grub2 stage is required
in case the `/boot` mountpoint is on a separate partition. This is the
case of RHEL-8.5 and RHEL-9.0 `ami` and `ec2` images.
Extend `disk.PartitionTable` with a new `BootPartition` method, which
returns a pointer to partition with FS mountpoint `/boot` if there is
such partition, or `nil` otherwise.
Extend the RHEL-8.5 and RHEL-9.0 code creating options structure for
grub2 osbuild stage to include the boot partition in case it has been
provided.
Signed-off-by: Tomas Hozza <thozza@redhat.com>