Skip to content

Commit

Permalink
disk: enable customizing ESP partitions
Browse files Browse the repository at this point in the history
This commits allow people to customize their ESP partition. Previously,
we always added an ESP partition ourselves, regardless of the given
customizations, so the customization errored out if there was an ESP
because of a conflict. This commit alters the behaviour, so ESP is
only added automatically if it's not in the customizations.
  • Loading branch information
ondrejbudai committed Dec 20, 2024
1 parent 7abbefe commit b8e1adb
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 14 deletions.
42 changes: 33 additions & 9 deletions pkg/disk/partition_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,7 @@ func addBootPartition(pt *PartitionTable, bootFsType FSType) error {
// The function will append the new partitions to the end of the existing
// partition table therefore it is best to call this function early to put them
// near the front (as is conventional).
func addPartitionsForBootMode(pt *PartitionTable, bootMode platform.BootMode) error {
func addPartitionsForBootMode(pt *PartitionTable, disk *blueprint.DiskCustomization, bootMode platform.BootMode) error {
switch bootMode {
case platform.BOOT_LEGACY:
// add BIOS boot partition
Expand All @@ -1090,24 +1090,21 @@ func addPartitionsForBootMode(pt *PartitionTable, bootMode platform.BootMode) er
pt.Partitions = append(pt.Partitions, part)
return nil
case platform.BOOT_UEFI:
// add ESP
part, err := mkESP(200*datasizes.MiB, pt.Type)
if err != nil {
// maybe add ESP
if err := maybeAddESP(pt, disk); err != nil {
return err
}
pt.Partitions = append(pt.Partitions, part)
return nil
case platform.BOOT_HYBRID:
// add both
bios, err := mkBIOSBoot(pt.Type)
if err != nil {
return err
}
esp, err := mkESP(200*datasizes.MiB, pt.Type)
if err != nil {
pt.Partitions = append(pt.Partitions, bios)
if err := maybeAddESP(pt, disk); err != nil {
return err
}
pt.Partitions = append(pt.Partitions, bios, esp)
return nil
case platform.BOOT_NONE:
return nil
Expand Down Expand Up @@ -1214,6 +1211,18 @@ func maybeAddBootPartition(pt *PartitionTable, disk *blueprint.DiskCustomization
return nil
}

func maybeAddESP(pt *PartitionTable, disk *blueprint.DiskCustomization) error {
if needsESP(disk) {
// we need an ESP to boot UEFI, create ESP if it does not already exist
part, err := mkESP(200*datasizes.MiB, pt.Type)
if err != nil {
return err
}
pt.Partitions = append(pt.Partitions, part)
}
return nil
}

// NewCustomPartitionTable creates a partition table based almost entirely on the disk customizations from a blueprint.
func NewCustomPartitionTable(customizations *blueprint.DiskCustomization, options *CustomPartitionTableOptions, rng *rand.Rand) (*PartitionTable, error) {
if options == nil {
Expand Down Expand Up @@ -1256,7 +1265,7 @@ func NewCustomPartitionTable(customizations *blueprint.DiskCustomization, option
// if needed
//
// TODO: switch to ensure ESP in case customizations already include it
if err := addPartitionsForBootMode(pt, options.BootMode); err != nil {
if err := addPartitionsForBootMode(pt, customizations, options.BootMode); err != nil {
return nil, fmt.Errorf("%s %w", errPrefix, err)
}
// add the /boot partition (if it is needed)
Expand Down Expand Up @@ -1524,3 +1533,18 @@ func needsBoot(disk *blueprint.DiskCustomization) bool {
}
return foundBtrfsOrLVM
}

// determine whether an ESP is needed based on the customizations. An ESP is
// needed if there is no /boot/efi partition defined in the customization.
func needsESP(disk *blueprint.DiskCustomization) bool {
if disk == nil {
return true
}

for _, part := range disk.Partitions {
if part.Mountpoint == "/boot/efi" {
return false
}
}
return true
}
112 changes: 107 additions & 5 deletions pkg/disk/partition_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -927,10 +927,11 @@ func TestAddBootPartition(t *testing.T) {

func TestAddPartitionsForBootMode(t *testing.T) {
type testCase struct {
pt disk.PartitionTable
bootMode platform.BootMode
expected disk.PartitionTable
errmsg string
pt disk.PartitionTable
bootMode platform.BootMode
expected disk.PartitionTable
diskCustomization *blueprint.DiskCustomization
errmsg string
}

testCases := map[string]testCase{
Expand Down Expand Up @@ -1084,6 +1085,44 @@ func TestAddPartitionsForBootMode(t *testing.T) {
},
},
},
"esp-present-uefi": {
pt: disk.PartitionTable{Type: disk.PT_GPT},
bootMode: platform.BOOT_UEFI,
diskCustomization: &blueprint.DiskCustomization{
Partitions: []blueprint.PartitionCustomization{
{
FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{
Mountpoint: "/boot/efi",
},
},
},
},
expected: disk.PartitionTable{Type: disk.PT_GPT},
},
"esp-present-hybrid": {
pt: disk.PartitionTable{Type: disk.PT_GPT},
bootMode: platform.BOOT_HYBRID,
diskCustomization: &blueprint.DiskCustomization{
Partitions: []blueprint.PartitionCustomization{
{
FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{
Mountpoint: "/boot/efi",
},
},
},
},
expected: disk.PartitionTable{
Type: disk.PT_GPT,
Partitions: []disk.Partition{
{
Size: 1 * datasizes.MiB,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
},
},
},
"bad-pttype-bios": {
pt: disk.PartitionTable{Type: disk.PartitionTableType(911)},
bootMode: platform.BOOT_LEGACY,
Expand Down Expand Up @@ -1111,7 +1150,7 @@ func TestAddPartitionsForBootMode(t *testing.T) {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
pt := tc.pt
err := disk.AddPartitionsForBootMode(&pt, tc.bootMode)
err := disk.AddPartitionsForBootMode(&pt, tc.diskCustomization, tc.bootMode)
if tc.errmsg == "" {
assert.NoError(err)
assert.Equal(tc.expected, pt)
Expand Down Expand Up @@ -2517,6 +2556,69 @@ func TestNewCustomPartitionTable(t *testing.T) {
},
},
},
"custom-esp": {
customizations: &blueprint.DiskCustomization{
Type: "dos",
Partitions: []blueprint.PartitionCustomization{
{
MinSize: 1 * datasizes.GiB,
GUID: "06",
FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{
Mountpoint: "/boot/efi",
FSType: "vfat",
},
},
},
},
options: &disk.CustomPartitionTableOptions{
DefaultFSType: disk.FS_EXT4,
BootMode: platform.BOOT_HYBRID,
PartitionTableType: disk.PT_GPT,
},
expected: &disk.PartitionTable{
Type: disk.PT_DOS,
Size: 1*datasizes.GiB + 2*datasizes.MiB,
UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
Partitions: []disk.Partition{
{
Start: 1 * datasizes.MiB, // header
Size: 1 * datasizes.MiB,
Bootable: true,
Type: disk.BIOSBootPartitionDOSID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Start: 2 * datasizes.MiB,
Size: 1 * datasizes.GiB,
Type: "06",
Payload: &disk.Filesystem{
Type: "vfat",
UUID: "6e4ff95f",
Mountpoint: "/boot/efi",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Start: 1*datasizes.GiB + 2*datasizes.MiB,
Size: 0,
Type: disk.FilesystemLinuxDOSID,
UUID: "", // partitions on dos PTs don't have UUIDs
Bootable: false,
Payload: &disk.Filesystem{
Type: "ext4",
Label: "root",
Mountpoint: "/",
UUID: "f662a5ee-e82a-4df4-8a2d-0b75fb180daf",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
}

for name := range testCases {
Expand Down

0 comments on commit b8e1adb

Please sign in to comment.