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 selecting a partition table type #1085

Merged
merged 10 commits into from
Dec 10, 2024

Conversation

ondrejbudai
Copy link
Member

Users need to have control over the partition table type in certain cases. Most prominently, they need a dos-style partition table for single-board computers.

Let's add a simple customizations for it.

achilleas-k
achilleas-k previously approved these changes Dec 3, 2024
Copy link
Member

@achilleas-k achilleas-k left a comment

Choose a reason for hiding this comment

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

Thank you!

supakeen
supakeen previously approved these changes Dec 4, 2024
Copy link
Member

@supakeen supakeen left a comment

Choose a reason for hiding this comment

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

Love the 🐦.

Users need to have control over the partition table type in certain
cases. Most prominently, they need a dos-style partition table for
single-board computers.

Let's add a simple customizations for it.
@ondrejbudai
Copy link
Member Author

Pushed a commit that fixes DOS partition tables with legacy boot. Our code for generation grub stage options require having a protective bios boot partition, but this partition was not recognized by the code responsible for finding it, leading to a panic.

I think that this fix will unblock us, but I wonder whether creating a protective bios boot partition on dos partition tables is the correct behaviour. IIRC, the BIOS core image was not protected, but I'm not sure why (maybe because of the partition count limits on dos?)

supakeen
supakeen previously approved these changes Dec 5, 2024
mvo5
mvo5 previously approved these changes Dec 9, 2024
Copy link
Contributor

@mvo5 mvo5 left a comment

Choose a reason for hiding this comment

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

Thank you, this seems fine and we should probably merge to unblock the Pi users but I would also like to see a followup just like @achilleas-k suggested that cleans up the DosBIOSBootID/DosESPID

pkg/disk/partition.go Show resolved Hide resolved
achilleas-k
achilleas-k previously approved these changes Dec 9, 2024
@achilleas-k
Copy link
Member

LVM test configs are failing to boot.

@achilleas-k
Copy link
Member

LVM test configs are failing to boot.

Not sure what I saw when I said this. It's not a boot failure, it's a build failure. One without a good error message too:

org.osbuild.sfdisk: 2b4d8878a950bce7632c82f685b3f146c4b3fb60d69706f3438047c5a057330a {
  "label": "dos",
  "uuid": "4e2e4024-f881-4025-94c1-b248eb7542a6",
  "partitions": [
    {
      "bootable": true,
      "size": 2048,
      "start": 2048,
      "type": "ef02",
      "uuid": "FAC7F1FB-3E8D-4137-A512-961DE09A5549"
    },
    {
      "size": 409600,
      "start": 4096,
      "type": "ef00",
      "uuid": "68B[2905](https://gitlab.com/redhat/services/products/image-builder/ci/images/-/jobs/8560780982#L2905)B-DF3E-4FB3-80FA-49D1E773AA33"
    },
    {
      "size": 1048576,
      "start": 413696,
      "type": "83"
    },
    {
      "size": 2097152,
      "start": 1462272,
      "type": "83"
    },
    {
      "size": 37756928,
      "start": 3559424,
      "type": "E6D6D379-F507-44C2-A23C-238F2A3DF928"
    }
  ]
}
device/device (org.osbuild.loopback): loop0 acquired (locked: True)
Failed to open file "/sys/fs/selinux/checkreqprot": Read-only file system
label: dos
label-id: 4e2e4024-f881-4025-94c1-b248eb7542a6
start="2048", size="2048", type="ef02", uuid="FAC7F1FB-3E8D-4137-A512-961DE09A5549", bootable
start="4096", size="409600", type="ef00", uuid="68B2905B-DF3E-4FB3-80FA-49D1E773AA33"
start="413696", size="1048576", type="83"
start="1462272", size="2097152", type="83"
start="3559424", size="37756928", type="E6D6D379-F507-44C2-A23C-238F2A3DF928"
Traceback (most recent call last):
  File "/run/osbuild/bin/org.osbuild.sfdisk", line 164, in <module>
    ret = main(args["devices"], args["options"])
  File "/run/osbuild/bin/org.osbuild.sfdisk", line 155, in main
    pt.write_to(device)
    ~~~~~~~~~~~^^^^^^^^
  File "/run/osbuild/bin/org.osbuild.sfdisk", line 111, in write_to
    self.update_from(target)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/run/osbuild/bin/org.osbuild.sfdisk", line 122, in update_from
    assert len(disk_parts) == len(self.partitions)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError
⏱  Duration: 0s
manifest - failed

Fully reproducible locally.

@achilleas-k
Copy link
Member

@ondrejbudai correctly identified this is because we're trying to write a dos partition table with more than 4 partitions.
sfdisk silently stops writing at 4 and then the read-back / sync fails to validate against the original list of commands.

ondrejbudai and others added 4 commits December 9, 2024 17:48
Follow-up to the previous commit. Translates the given partition table
type from a blueprint to the actual partition table.
Previously Partition.IsBIOSBoot could only recognize GPT-based bios
boot.
@achilleas-k achilleas-k dismissed stale reviews from mvo5, supakeen, and themself via 46a85ad December 9, 2024 16:53
@achilleas-k achilleas-k requested a review from mvo5 December 9, 2024 17:02
@achilleas-k
Copy link
Member

I added stuff. @ondrejbudai PTAL as well.

mvo5
mvo5 previously approved these changes Dec 9, 2024
Copy link
Contributor

@mvo5 mvo5 left a comment

Choose a reason for hiding this comment

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

Thank you! Some minor nitpicks inline but feel free to ignore

pkg/osbuild/sfdisk_stage.go Show resolved Hide resolved
pkg/osbuild/sfdisk_stage_test.go Show resolved Hide resolved
DOS partition tables only support up to 4 partitions.  Don't create the
sfdisk stage options if this rule is violated.  Stage validation
failures panic, so we panic on the stage creation.  This might change in
the future (to return errors) but for now we use panics and put the
responsibility on the callers to validate their inputs if they want to
have better error control.

Test sfdisk stage validation failure
Return an error when a partition table is created with type dos and more
than 4 partitions.

This check can only happen after the partition table is created,
otherwise we would have to predict all the partitions that get created
automatically, which would duplicate a lot of the logic in
NewCustomPartitionTable().

Update tests:
- Convert the plain+swap (valid) test to GPT since now it's invalid as
  DOS.
- Add a fail test for a DOS partition table with too many partitions.
We can't catch all cases of dos partition table with too many
partitions, but catching the obvious ones early can help.
Add a new test config with a dos partition table type.  This is a copy
of the LVM test config with the extra /data partition removed to make it
valid (max 4 partitions).

Only test on CentOS 9 and 10 to avoid growing the test cases by too
much.
@achilleas-k
Copy link
Member

This should be green now, but I noticed a couple of issues with partition types being set to GUIDs for DOS. It doesn't break anything in light testing, but the partitions are marked as empty (00), which might be a problem.

I can fix it here or in a quick follow-up.

@achilleas-k
Copy link
Member

diff --git a/pkg/disk/partition_table.go b/pkg/disk/partition_table.go
index 797cf9567..4e91b7af4 100644
--- a/pkg/disk/partition_table.go
+++ b/pkg/disk/partition_table.go
@@ -1275,7 +1275,9 @@ func NewCustomPartitionTable(customizations *blueprint.DiskCustomization, option
 				return nil, fmt.Errorf("%s %w", errPrefix, err)
 			}
 		case "btrfs":
-			addBtrfsPartition(pt, part)
+			if err := addBtrfsPartition(pt, part); err != nil {
+				return nil, fmt.Errorf("%s %w", errPrefix, err)
+			}
 		default:
 			return nil, fmt.Errorf("%s invalid partition type: %s", errPrefix, part.Type)
 		}
@@ -1406,8 +1408,12 @@ func addLVMPartition(pt *PartitionTable, partition blueprint.PartitionCustomizat
 	}
 
 	// create partition for volume group
+	partType, err := getPartitionTypeIDfor(pt.Type, "lvm")
+	if err != nil {
+		return fmt.Errorf("error creating lvm partition %q: %w", vgname, err)
+	}
 	newpart := Partition{
-		Type:     LVMPartitionGUID,
+		Type:     partType,
 		Size:     partition.MinSize,
 		Bootable: false,
 		Payload:  newvg,
@@ -1416,7 +1422,7 @@ func addLVMPartition(pt *PartitionTable, partition blueprint.PartitionCustomizat
 	return nil
 }
 
-func addBtrfsPartition(pt *PartitionTable, partition blueprint.PartitionCustomization) {
+func addBtrfsPartition(pt *PartitionTable, partition blueprint.PartitionCustomization) error {
 	subvols := make([]BtrfsSubvolume, len(partition.Subvolumes))
 	for idx, subvol := range partition.Subvolumes {
 		newsubvol := BtrfsSubvolume{
@@ -1431,14 +1437,19 @@ func addBtrfsPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz
 	}
 
 	// create partition for btrfs volume
+	partType, err := getPartitionTypeIDfor(pt.Type, "data")
+	if err != nil {
+		return fmt.Errorf("error creating btrfs partition: %w", err)
+	}
 	newpart := Partition{
-		Type:     FilesystemDataGUID,
+		Type:     partType,
 		Bootable: false,
 		Payload:  newvol,
 		Size:     partition.MinSize,
 	}
 
 	pt.Partitions = append(pt.Partitions, newpart)
+	return nil
 }
 
 // Determine if a boot partition is needed based on the customizations. A boot

The correct partition type ID for ESP is 'ef' (not 'ef00') [1].
The partition type ID for LVM is '8e' [1].

BIOS boot partitions aren't meant for (or required) on dos partition
tables [2].  We will eventually make this a partitionless gap in the PT,
but for now let's simply use the code for 'empty'.

Use the getPartitionTypeIDfor() function for all partition type
assignments when creating partitions.

Add tests that cover all basic partition table configurations (plain,
lvm, btrfs) using dos and gpt.

[1] https://tldp.org/HOWTO/Partition-Mass-Storage-Definitions-Naming-HOWTO/x190.html
[2] https://www.gnu.org/software/grub/manual/grub/html_node/BIOS-installation.html#BIOS-installation
@achilleas-k
Copy link
Member

This should be green now, but I noticed a couple of issues with partition types being set to GUIDs for DOS. It doesn't break anything in light testing, but the partitions are marked as empty (00), which might be a problem.

I can fix it here or in a quick follow-up.

Fixed all partition type IDs and added tests.

Copy link
Contributor

@mvo5 mvo5 left a comment

Choose a reason for hiding this comment

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

Thank you!

// Partition type ID for BIOS boot partition on dos
DosBIOSBootID = "ef02"
// Partition type ID for LVM on dos
DosLVMTypeID = "8e"
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe for a followup, let's use this new constant everywhere, right now I still see:

$ git grep '"8e"'
cmd/otk/osbuild-gen-partition-table/main_test.go:                                                       Type:  "8e",
pkg/disk/partition_table.go:                    part.Type = "8e"

@supakeen supakeen added this pull request to the merge queue Dec 10, 2024
Merged via the queue into osbuild:main with commit 544bc43 Dec 10, 2024
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants