Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the new partitioning customizations to RHEL and CentOS #1077

Merged
merged 4 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/distro/fedora/distro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,7 @@ func TestDistro_DiskCustomizationRunsValidateLayoutConstraints(t *testing.T) {
Size: imgType.Size(0),
}
_, _, err := imgType.Manifest(&bp, imgOpts, nil, 0)
assert.EqualError(t, err, "cannot use disk customization: multiple LVM volume groups are not yet supported")
assert.EqualError(t, err, "multiple LVM volume groups are not yet supported")
})
}
}
Expand Down
11 changes: 3 additions & 8 deletions pkg/distro/fedora/imagetype.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,9 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil {
return nil, err
}
if err := partitioning.ValidateLayoutConstraints(); err != nil {
return nil, err
}

if osc := customizations.GetOpenSCAP(); osc != nil {
supported := oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList)
Expand Down Expand Up @@ -471,13 +474,5 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
}

diskc, err := customizations.GetPartitioning()
if err != nil {
return nil, err
}
if err := diskc.ValidateLayoutConstraints(); err != nil {
return nil, fmt.Errorf("cannot use disk customization: %w", err)
}

return nil, nil
}
2 changes: 1 addition & 1 deletion pkg/distro/rhel/distro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestESP(t *testing.T) {

distro_test_common.TestESP(t, distros, func(i distro.ImageType) (*disk.PartitionTable, error) {
it := i.(*rhel.ImageType)
return it.GetPartitionTable([]blueprint.FilesystemCustomization{}, distro.ImageOptions{}, rng)
return it.GetPartitionTable(&blueprint.Customizations{}, distro.ImageOptions{}, rng)
})
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/distro/rhel/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ func DiskImage(workload workload.Workload,
img.Workload = workload
img.Compression = t.Compression
// TODO: move generation into LiveImage
pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng)
pt, err := t.GetPartitionTable(customizations, options, rng)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -567,7 +567,7 @@ func EdgeRawImage(workload workload.Workload,
img.OSName = "rhel-edge"

// TODO: move generation into LiveImage
pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng)
pt, err := t.GetPartitionTable(customizations, options, rng)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -609,7 +609,7 @@ func EdgeSimplifiedInstallerImage(workload workload.Workload,
rawImg.OSName = "rhel-edge"

// TODO: move generation into LiveImage
pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng)
pt, err := t.GetPartitionTable(customizations, options, rng)
if err != nil {
return nil, err
}
Expand Down
31 changes: 29 additions & 2 deletions pkg/distro/rhel/imagetype.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ const (
BlueprintPkgsKey = "blueprint"
)

// Default directory size minimums for all image types.
var requiredDirectorySizes = map[string]uint64{
"/": 1 * datasizes.GiB,
"/usr": 2 * datasizes.GiB,
}

type ImageFunc func(workload workload.Workload, t *ImageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error)

type PackageSetFunc func(t *ImageType) rpmmd.PackageSet
Expand Down Expand Up @@ -180,7 +186,7 @@ func (t *ImageType) BootMode() platform.BootMode {
}

func (t *ImageType) GetPartitionTable(
mountpoints []blueprint.FilesystemCustomization,
customizations *blueprint.Customizations,
options distro.ImageOptions,
rng *rand.Rand,
) (*disk.PartitionTable, error) {
Expand All @@ -193,8 +199,29 @@ func (t *ImageType) GetPartitionTable(
}

imageSize := t.Size(options.Size)
partitioning, err := customizations.GetPartitioning()
if err != nil {
return nil, err
}
if partitioning != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could be defensive here and double check that customizations.Filesystem and partitioning is never both non-nil and raise an internal error. But maybe overkill.

// Use the new custom partition table to create a PT fully based on the user's customizations.
// This overrides FilesystemCustomizations, but we should never have both defined.
if options.Size > 0 {
// user specified a size on the command line, so let's override the
// customization with the calculated/rounded imageSize
partitioning.MinSize = imageSize
}

partOptions := &disk.CustomPartitionTableOptions{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the fact that this is duplicated with fedor/imagetype.go is unavoidable currently (and consistent with the rest of the code)(?)

PartitionTableType: basePartitionTable.Type, // PT type is not customizable, it is determined by the base PT for an image type or architecture
BootMode: t.BootMode(),
DefaultFSType: disk.FS_XFS, // default fs type for RHEL
RequiredMinSizes: requiredDirectorySizes,
}
return disk.NewCustomPartitionTable(partitioning, partOptions, rng)
}

return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, options.PartitioningMode, nil, rng)
return disk.NewPartitionTable(&basePartitionTable, customizations.GetFilesystems(), imageSize, options.PartitioningMode, nil, rng)
}

func (t *ImageType) getDefaultImageConfig() *distro.ImageConfig {
Expand Down
2 changes: 1 addition & 1 deletion pkg/distro/rhel/rhel10/distro_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func TestRhel10_NoBootPartition(t *testing.T) {
// and we do not support /boot on LVM, so it must be on a separate partition.
continue
}
pt, err := it.GetPartitionTable([]blueprint.FilesystemCustomization{}, distro.ImageOptions{}, rng)
pt, err := it.GetPartitionTable(&blueprint.Customizations{}, distro.ImageOptions{}, rng)
assert.NoError(t, err)
_, err = pt.GetMountpointSize("/boot")
require.EqualError(t, err, "cannot find mountpoint /boot")
Expand Down
98 changes: 98 additions & 0 deletions pkg/distro/rhel/rhel10/distro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,3 +574,101 @@ func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) {
}
}
}

func TestDiskAndFilesystemCustomizationsError(t *testing.T) {
// simple test that checks that disk customizations are allowed
r8distro := rhelFamilyDistros[0].distro
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Filesystem: []blueprint.FilesystemCustomization{
{
MinSize: 1024,
Mountpoint: "/home",
},
},
Disk: &blueprint.DiskCustomization{
Partitions: []blueprint.PartitionCustomization{
{
Type: "plain",
FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{
Mountpoint: "/",
Label: "root",
FSType: "ext4",
},
},
},
},
},
}

// these produce error message and are tested elsewhere
skipTest := map[string]bool{
"edge-commit": true,
"edge-container": true,
"edge-installer": true,
"edge-simplified-installer": true,
"azure-eap7-rhui": true,
"edge-vsphere": true,
"edge-raw-image": true,
"edge-ami": true,
}

for _, archName := range r8distro.ListArches() {
arch, _ := r8distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
options := distro.ImageOptions{}
_, _, err := imgType.Manifest(&bp, options, nil, 0)
if skipTest[imgTypeName] {
continue
}
assert.EqualError(t, err, "partitioning customizations cannot be used with custom filesystems (mountpoints)")
}
}
}

func TestNoDiskCustomizationsNoError(t *testing.T) {
// simple test that checks that disk customizations are allowed
r8distro := rhelFamilyDistros[0].distro
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Disk: &blueprint.DiskCustomization{
Partitions: []blueprint.PartitionCustomization{
{
Type: "plain",
FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{
Mountpoint: "/",
Label: "root",
FSType: "ext4",
},
},
},
},
},
}

// these produce error message and are tested elsewhere
skipTest := map[string]bool{
"edge-commit": true,
"edge-container": true,
"edge-installer": true,
"edge-simplified-installer": true,
"azure-eap7-rhui": true,
"edge-vsphere": true,
"edge-raw-image": true,
"edge-ami": true,
}

for _, archName := range r8distro.ListArches() {
arch, _ := r8distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
options := distro.ImageOptions{}
_, _, err := imgType.Manifest(&bp, options, nil, 0)
if skipTest[imgTypeName] {
continue
}
assert.NoError(t, err)
}
}
}
19 changes: 17 additions & 2 deletions pkg/distro/rhel/rhel10/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,24 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima
}

mountpoints := customizations.GetFilesystems()

err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
partitioning, err := customizations.GetPartitioning()
if err != nil {
return nil, err
}

if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil {
return warnings, err
}

if len(mountpoints) > 0 && partitioning != nil {
return nil, fmt.Errorf("partitioning customizations cannot be used with custom filesystems (mountpoints)")
}

if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil {
return warnings, err
}

if err := partitioning.ValidateLayoutConstraints(); err != nil {
return warnings, err
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/distro/rhel/rhel8/distro_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestEC2Partitioning(t *testing.T) {
require.NoError(t, err)

it := i.(*rhel.ImageType)
pt, err := it.GetPartitionTable([]blueprint.FilesystemCustomization{}, distro.ImageOptions{}, rng)
pt, err := it.GetPartitionTable(&blueprint.Customizations{}, distro.ImageOptions{}, rng)
require.NoError(t, err)

// x86_64 is /boot-less, check that
Expand Down
46 changes: 43 additions & 3 deletions pkg/distro/rhel/rhel8/distro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ func TestDistro_CustomFileSystemManifestError(t *testing.T) {
imgType, _ := arch.GetImageType(imgTypeName)
_, _, err := imgType.Manifest(&bp, distro.ImageOptions{}, nil, 0)
if imgTypeName == "edge-commit" || imgTypeName == "edge-container" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
assert.EqualError(t, err, "custom mountpoints are not supported for ostree types")
} else if unsupported[imgTypeName] {
assert.Error(t, err)
} else {
Expand Down Expand Up @@ -712,7 +712,7 @@ func TestDistro_TestRootMountPoint(t *testing.T) {
imgType, _ := arch.GetImageType(imgTypeName)
_, _, err := imgType.Manifest(&bp, distro.ImageOptions{}, nil, 0)
if imgTypeName == "edge-commit" || imgTypeName == "edge-container" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
assert.EqualError(t, err, "custom mountpoints are not supported for ostree types")
} else if unsupported[imgTypeName] {
assert.Error(t, err)
} else {
Expand Down Expand Up @@ -872,7 +872,7 @@ func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) {
imgType, _ := arch.GetImageType(imgTypeName)
_, _, err := imgType.Manifest(&bp, distro.ImageOptions{}, nil, 0)
if imgTypeName == "edge-commit" || imgTypeName == "edge-container" {
assert.EqualError(t, err, "Custom mountpoints are not supported for ostree types")
assert.EqualError(t, err, "custom mountpoints are not supported for ostree types")
} else if unsupported[imgTypeName] {
assert.Error(t, err)
} else {
Expand All @@ -881,3 +881,43 @@ func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) {
}
}
}

func TestNoDiskCustomizationsSupported(t *testing.T) {
r8distro := rhelFamilyDistros[0].distro
bp := blueprint.Blueprint{
Customizations: &blueprint.Customizations{
Disk: &blueprint.DiskCustomization{
Partitions: []blueprint.PartitionCustomization{
{
Type: "plain",
FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{
Mountpoint: "/",
Label: "root",
FSType: "ext4",
},
},
},
},
},
}

// these produce a different error message and are tested elsewhere
skipTest := map[string]bool{
"edge-installer": true,
"edge-simplified-installer": true,
"edge-raw-image": true,
"azure-eap7-rhui": true,
}

for _, archName := range r8distro.ListArches() {
arch, _ := r8distro.GetArch(archName)
for _, imgTypeName := range arch.ListImageTypes() {
imgType, _ := arch.GetImageType(imgTypeName)
_, _, err := imgType.Manifest(&bp, distro.ImageOptions{}, nil, 0)
if skipTest[imgTypeName] {
continue
}
assert.EqualError(t, err, fmt.Sprintf("partitioning customizations are not supported on %s", r8distro.Name()))
}
}
}
20 changes: 17 additions & 3 deletions pkg/distro/rhel/rhel8/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,27 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima
}

mountpoints := customizations.GetFilesystems()
partitioning, err := customizations.GetPartitioning()
if err != nil {
return nil, err
}
if partitioning != nil {
return nil, fmt.Errorf("partitioning customizations are not supported on %s", t.Arch().Distro().Name())
}

if mountpoints != nil && t.RPMOSTree {
return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types")
return warnings, fmt.Errorf("custom mountpoints are not supported for ostree types")
}

err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil {
return warnings, err
}

if err := partitioning.ValidateLayoutConstraints(); err != nil {
return warnings, err
}

if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil {
return warnings, err
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/distro/rhel/rhel9/distro_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestEC2Partitioning(t *testing.T) {
require.NoError(t, err)

it := i.(*rhel.ImageType)
pt, err := it.GetPartitionTable([]blueprint.FilesystemCustomization{}, distro.ImageOptions{}, rng)
pt, err := it.GetPartitionTable(&blueprint.Customizations{}, distro.ImageOptions{}, rng)
require.NoError(t, err)

bootSize, err := pt.GetMountpointSize("/boot")
Expand Down
Loading
Loading