diff --git a/bib/cmd/bootc-image-builder/export_test.go b/bib/cmd/bootc-image-builder/export_test.go index 8ada1c72..9b5d1f6e 100644 --- a/bib/cmd/bootc-image-builder/export_test.go +++ b/bib/cmd/bootc-image-builder/export_test.go @@ -7,6 +7,8 @@ var ( CheckMountpoints = checkMountpoints PartitionTables = partitionTables UpdateFilesystemSizes = updateFilesystemSizes + GenPartitionTable = genPartitionTable + CreateRand = createRand ) func MockOsGetuid(new func() int) (restore func()) { diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index c88379cd..3e84e038 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -203,6 +203,32 @@ func setFSTypes(pt *disk.PartitionTable, rootfs string) error { }) } +func genPartitionTable(c *ManifestConfig, customizations *blueprint.Customizations, rng *rand.Rand) (*disk.PartitionTable, error) { + basept, ok := partitionTables[c.Architecture.String()] + if !ok { + return nil, fmt.Errorf("pipelines: no partition tables defined for %s", c.Architecture) + } + + partitioningMode := disk.RawPartitioningMode + if c.RootFSType == "btrfs" { + partitioningMode = disk.BtrfsPartitioningMode + } + if err := checkFilesystemCustomizations(customizations.GetFilesystems(), partitioningMode); err != nil { + return nil, err + } + fsCustomizations := updateFilesystemSizes(customizations.GetFilesystems(), c.RootfsMinsize) + + pt, err := disk.NewPartitionTable(&basept, fsCustomizations, DEFAULT_SIZE, partitioningMode, nil, rng) + if err != nil { + return nil, err + } + + if err := setFSTypes(pt, c.RootFSType); err != nil { + return nil, fmt.Errorf("error setting root filesystem type: %w", err) + } + return pt, nil +} + func manifestForDiskImage(c *ManifestConfig, rng *rand.Rand) (*manifest.Manifest, error) { if c.Imgref == "" { return nil, fmt.Errorf("pipeline: no base image defined") @@ -266,28 +292,10 @@ func manifestForDiskImage(c *ManifestConfig, rng *rand.Rand) (*manifest.Manifest img.KernelOptionsAppend = append(img.KernelOptionsAppend, kopts.Append) } - basept, ok := partitionTables[c.Architecture.String()] - if !ok { - return nil, fmt.Errorf("pipelines: no partition tables defined for %s", c.Architecture) - } - - partitioningMode := disk.RawPartitioningMode - if c.RootFSType == "btrfs" { - partitioningMode = disk.BtrfsPartitioningMode - } - if err := checkFilesystemCustomizations(customizations.GetFilesystems(), partitioningMode); err != nil { - return nil, err - } - fsCustomizations := updateFilesystemSizes(customizations.GetFilesystems(), c.RootfsMinsize) - - pt, err := disk.NewPartitionTable(&basept, fsCustomizations, DEFAULT_SIZE, partitioningMode, nil, rng) + pt, err := genPartitionTable(c, customizations, rng) if err != nil { return nil, err } - - if err := setFSTypes(pt, c.RootFSType); err != nil { - return nil, fmt.Errorf("error setting root filesystem type: %w", err) - } img.PartitionTable = pt // For the bootc-disk image, the filename is the basename and the extension diff --git a/bib/cmd/bootc-image-builder/image_test.go b/bib/cmd/bootc-image-builder/image_test.go index e23d3017..f62cfee0 100644 --- a/bib/cmd/bootc-image-builder/image_test.go +++ b/bib/cmd/bootc-image-builder/image_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/blueprint" "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/manifest" @@ -347,3 +348,78 @@ func TestUpdateFilesystemSizes(t *testing.T) { } } + +func findMountableSizeableFor(pt *disk.PartitionTable, needle string) (disk.Mountable, disk.Sizeable) { + var foundMnt disk.Mountable + var foundParent disk.Sizeable + err := pt.ForEachMountable(func(mnt disk.Mountable, path []disk.Entity) error { + if mnt.GetMountpoint() == needle { + foundMnt = mnt + for idx := len(path) - 1; idx >= 0; idx-- { + if sz, ok := path[idx].(disk.Sizeable); ok { + foundParent = sz + break + } + } + } + return nil + }) + if err != nil { + panic(err) + } + return foundMnt, foundParent +} + +func TestGenPartitionTableSetsRootfsForAllFilesystemsXFS(t *testing.T) { + rng := bib.CreateRand() + + cnf := &bib.ManifestConfig{ + Architecture: arch.FromString("amd64"), + RootFSType: "xfs", + } + cus := &blueprint.Customizations{ + Filesystem: []blueprint.FilesystemCustomization{ + {Mountpoint: "/var/data", MinSize: 2_000_000}, + {Mountpoint: "/var/stuff", MinSize: 10_000_000}, + }, + } + pt, err := bib.GenPartitionTable(cnf, cus, rng) + assert.NoError(t, err) + + for _, mntPoint := range []string{"/", "/boot", "/var/data"} { + mnt, _ := findMountableSizeableFor(pt, mntPoint) + assert.Equal(t, "xfs", mnt.GetFSType()) + } + mnt, parent := findMountableSizeableFor(pt, "/var/data") + assert.True(t, parent.GetSize() >= 2_000_000) + + mnt, parent = findMountableSizeableFor(pt, "/var/stuff") + assert.True(t, parent.GetSize() >= 10_000_000) + + // ESP is always vfat + mnt, _ = findMountableSizeableFor(pt, "/boot/efi") + assert.Equal(t, "vfat", mnt.GetFSType()) +} + +func TestGenPartitionTableSetsRootfsForAllFilesystemsBtrfs(t *testing.T) { + rng := bib.CreateRand() + + cnf := &bib.ManifestConfig{ + Architecture: arch.FromString("amd64"), + RootFSType: "btrfs", + } + cus := &blueprint.Customizations{} + pt, err := bib.GenPartitionTable(cnf, cus, rng) + assert.NoError(t, err) + + mnt, _ := findMountableSizeableFor(pt, "/") + assert.Equal(t, "btrfs", mnt.GetFSType()) + + // btrfs has a default (ext4) /boot + mnt, _ = findMountableSizeableFor(pt, "/boot") + assert.Equal(t, "ext4", mnt.GetFSType()) + + // ESP is always vfat + mnt, _ = findMountableSizeableFor(pt, "/boot/efi") + assert.Equal(t, "vfat", mnt.GetFSType()) +}