From 41fbcd7f07d280b4e9c01b2bdcd1a6ade5351792 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 3 Sep 2025 16:22:01 +0200 Subject: [PATCH] Support raw payloads in yaml partition info Primarily, this removes the SourcePipeline option in the Raw payload type, and instead always uses whatever is a "natural" source for the type of image being built. This makes a lot more sense, because the pipeline names is an internally generated thing and the user shouldn't need to know what to use here. We also add Raw handling to Partition.partitionTableFeatures() to avoid this causing a panic. --- internal/testdisk/partition.go | 3 +-- pkg/disk/partition_table.go | 3 +++ pkg/disk/raw.go | 6 ++---- pkg/image/bootc_disk.go | 6 ++++++ pkg/manifest/anaconda_installer_iso_tree.go | 2 +- pkg/manifest/coi_iso_tree.go | 2 +- pkg/manifest/raw.go | 2 +- pkg/manifest/raw_bootc.go | 8 ++++++-- pkg/manifest/raw_ostree.go | 2 +- pkg/osbuild/disk.go | 4 ++-- pkg/osbuild/disk_test.go | 2 +- pkg/osbuild/mkfs_stage.go | 4 ++-- pkg/osbuild/mkfs_stages_test.go | 10 +++++----- 13 files changed, 32 insertions(+), 22 deletions(-) diff --git a/internal/testdisk/partition.go b/internal/testdisk/partition.go index d887a9bc4b..f496e04fac 100644 --- a/internal/testdisk/partition.go +++ b/internal/testdisk/partition.go @@ -400,8 +400,7 @@ func MakeFakePartitionTable(mntPoints ...string) *disk.PartitionTable { payload = swap case "raw": payload = &disk.Raw{ - SourcePipeline: "build", - SourcePath: "/usr/lib/modules/5.0/aboot.img", + SourcePath: "/usr/lib/modules/5.0/aboot.img", } default: payload = &disk.Filesystem{ diff --git a/pkg/disk/partition_table.go b/pkg/disk/partition_table.go index 6cf353bb2d..4883a603f3 100644 --- a/pkg/disk/partition_table.go +++ b/pkg/disk/partition_table.go @@ -853,6 +853,7 @@ type partitionTableFeatures struct { EXT4 bool LUKS bool Swap bool + Raw bool } // features examines all of the PartitionTable entities and returns a struct @@ -881,6 +882,8 @@ func (pt *PartitionTable) features() partitionTableFeatures { case "ext4": ptFeatures.EXT4 = true } + case *Raw: + ptFeatures.Raw = true case *Swap: ptFeatures.Swap = true case *LUKSContainer: diff --git a/pkg/disk/raw.go b/pkg/disk/raw.go index 19976b3b1f..c837b0ef6d 100644 --- a/pkg/disk/raw.go +++ b/pkg/disk/raw.go @@ -7,8 +7,7 @@ import ( // Raw defines the payload for a raw partition. It's similar to a // [Filesystem] but with fewer fields. It is a [PayloadEntity]. type Raw struct { - SourcePipeline string - SourcePath string + SourcePath string `json:"source_path" yaml:"source_path"` } func init() { @@ -25,7 +24,6 @@ func (s *Raw) Clone() Entity { } return &Raw{ - SourcePipeline: s.SourcePipeline, - SourcePath: s.SourcePath, + SourcePath: s.SourcePath, } } diff --git a/pkg/image/bootc_disk.go b/pkg/image/bootc_disk.go index e349df843c..a173ec6cbc 100644 --- a/pkg/image/bootc_disk.go +++ b/pkg/image/bootc_disk.go @@ -46,6 +46,7 @@ func (img *BootcDiskImage) InstantiateManifestFromContainers(m *manifest.Manifes var copyFilesFrom map[string][]string var ensureDirs []*fsnode.Directory + var customSourcePipeline = "" if *img.ContainerSource != *img.BuildContainerSource { // If we're using a different build container from the target container then we copy // the bootc customization file directories from the target container. This includes the @@ -79,6 +80,8 @@ func (img *BootcDiskImage) InstantiateManifestFromContainers(m *manifest.Manifes EnsureDirs: ensureDirs, }) targetBuildPipeline.Checkpoint() + + customSourcePipeline = targetBuildPipeline.Name() } buildContainers := []container.SourceSpec{*img.BuildContainerSource} @@ -97,6 +100,9 @@ func (img *BootcDiskImage) InstantiateManifestFromContainers(m *manifest.Manifes var hostPipeline manifest.Build rawImage := manifest.NewRawBootcImage(buildPipeline, containers, img.platform) + if customSourcePipeline != "" { + rawImage.SourcePipeline = customSourcePipeline + } rawImage.PartitionTable = img.PartitionTable rawImage.Users = img.OSCustomizations.Users rawImage.Groups = img.OSCustomizations.Groups diff --git a/pkg/manifest/anaconda_installer_iso_tree.go b/pkg/manifest/anaconda_installer_iso_tree.go index d5bf648880..27ddf29966 100644 --- a/pkg/manifest/anaconda_installer_iso_tree.go +++ b/pkg/manifest/anaconda_installer_iso_tree.go @@ -484,7 +484,7 @@ func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline { Size: fmt.Sprintf("%d", p.PartitionTable.Size), })) - for _, stage := range osbuild.GenFsStages(p.PartitionTable, filename) { + for _, stage := range osbuild.GenFsStages(p.PartitionTable, filename, p.anacondaPipeline.Name()) { pipeline.AddStage(stage) } diff --git a/pkg/manifest/coi_iso_tree.go b/pkg/manifest/coi_iso_tree.go index 3fbf1155c5..de1fff0dc7 100644 --- a/pkg/manifest/coi_iso_tree.go +++ b/pkg/manifest/coi_iso_tree.go @@ -111,7 +111,7 @@ func (p *CoreOSISOTree) serialize() osbuild.Pipeline { Size: fmt.Sprintf("%d", p.PartitionTable.Size), })) - for _, stage := range osbuild.GenFsStages(p.PartitionTable, filename) { + for _, stage := range osbuild.GenFsStages(p.PartitionTable, filename, p.payloadPipeline.Name()) { pipeline.AddStage(stage) } diff --git a/pkg/manifest/raw.go b/pkg/manifest/raw.go index 56aa82b357..6a455c946e 100644 --- a/pkg/manifest/raw.go +++ b/pkg/manifest/raw.go @@ -52,7 +52,7 @@ func (p *RawImage) serialize() osbuild.Pipeline { panic("no partition table in live image") } - for _, stage := range osbuild.GenImagePrepareStages(pt, p.Filename(), p.PartTool) { + for _, stage := range osbuild.GenImagePrepareStages(pt, p.Filename(), p.PartTool, p.treePipeline.Name()) { pipeline.AddStage(stage) } diff --git a/pkg/manifest/raw_bootc.go b/pkg/manifest/raw_bootc.go index c120100a93..0a1de4e368 100644 --- a/pkg/manifest/raw_bootc.go +++ b/pkg/manifest/raw_bootc.go @@ -48,6 +48,9 @@ type RawBootcImage struct { // MountUnits creates systemd .mount units to describe the filesystem // instead of writing to /etc/fstab MountUnits bool + + // Source pipeline for files written to raw partitions + SourcePipeline string } func (p RawBootcImage) Filename() string { @@ -64,7 +67,8 @@ func NewRawBootcImage(buildPipeline Build, containers []container.SourceSpec, pl filename: "disk.img", platform: platform, - containers: containers, + containers: containers, + SourcePipeline: buildPipeline.Name(), } buildPipeline.addDependent(p) return p @@ -133,7 +137,7 @@ func (p *RawBootcImage) serialize() osbuild.Pipeline { panic(fmt.Errorf("no partition table in live image")) } - for _, stage := range osbuild.GenImagePrepareStages(pt, p.filename, osbuild.PTSfdisk) { + for _, stage := range osbuild.GenImagePrepareStages(pt, p.filename, osbuild.PTSfdisk, p.SourcePipeline) { pipeline.AddStage(stage) } diff --git a/pkg/manifest/raw_ostree.go b/pkg/manifest/raw_ostree.go index ef4c7a2a53..1fdc780a57 100644 --- a/pkg/manifest/raw_ostree.go +++ b/pkg/manifest/raw_ostree.go @@ -58,7 +58,7 @@ func (p *RawOSTreeImage) serialize() osbuild.Pipeline { panic("no partition table in live image") } - for _, stage := range osbuild.GenImagePrepareStages(pt, p.Filename(), osbuild.PTSfdisk) { + for _, stage := range osbuild.GenImagePrepareStages(pt, p.Filename(), osbuild.PTSfdisk, p.treePipeline.Name()) { pipeline.AddStage(stage) } diff --git a/pkg/osbuild/disk.go b/pkg/osbuild/disk.go index 2cbecfb8a6..03eb1f004e 100644 --- a/pkg/osbuild/disk.go +++ b/pkg/osbuild/disk.go @@ -67,7 +67,7 @@ const ( PTSgdisk PartTool = "sgdisk" ) -func GenImagePrepareStages(pt *disk.PartitionTable, filename string, partTool PartTool) []*Stage { +func GenImagePrepareStages(pt *disk.PartitionTable, filename string, partTool PartTool, sourcePipeline string) []*Stage { stages := make([]*Stage, 0) // create an empty file of the given size via `org.osbuild.truncate` @@ -106,7 +106,7 @@ func GenImagePrepareStages(pt *disk.PartitionTable, filename string, partTool Pa // Generate all the filesystems, subvolumes, and swap areas on partitons // and devices - s = GenFsStages(pt, filename) + s = GenFsStages(pt, filename, sourcePipeline) stages = append(stages, s...) return stages diff --git a/pkg/osbuild/disk_test.go b/pkg/osbuild/disk_test.go index cb032532b2..b4e678887f 100644 --- a/pkg/osbuild/disk_test.go +++ b/pkg/osbuild/disk_test.go @@ -74,7 +74,7 @@ func TestGenImageKernelOptionsBtrfsNotRootCmdlineGenerated(t *testing.T) { func TestGenImagePrepareStages(t *testing.T) { pt := testdisk.MakeFakeBtrfsPartitionTable("/", "/boot") filename := "image.raw" - actualStages := GenImagePrepareStages(pt, filename, PTSfdisk) + actualStages := GenImagePrepareStages(pt, filename, PTSfdisk, "build") assert.Equal(t, []*Stage{ { diff --git a/pkg/osbuild/mkfs_stage.go b/pkg/osbuild/mkfs_stage.go index 44d9f00c6f..d1c047a07f 100644 --- a/pkg/osbuild/mkfs_stage.go +++ b/pkg/osbuild/mkfs_stage.go @@ -30,7 +30,7 @@ func getDevicesForFsStage(path []disk.Entity, filename string) map[string]Device // - org.osbuild.mkfs.*: for all filesystems and btrfs volumes // - org.osbuild.btrfs.subvol: for all btrfs subvolumes // - org.osbuild.mkswap: for swap areas -func GenFsStages(pt *disk.PartitionTable, filename string) []*Stage { +func GenFsStages(pt *disk.PartitionTable, filename string, soucePipeline string) []*Stage { stages := make([]*Stage, 0, len(pt.Partitions)) genStage := func(ent disk.Entity, path []disk.Entity) error { @@ -99,7 +99,7 @@ func GenFsStages(pt *disk.PartitionTable, filename string) []*Stage { options := &WriteDeviceStageOptions{ From: fmt.Sprintf("input://%s", filepath.Join(inputName, e.SourcePath)), } - inputs := NewPipelineTreeInputs(inputName, e.SourcePipeline) + inputs := NewPipelineTreeInputs(inputName, soucePipeline) stages = append(stages, NewWriteDeviceStage(options, inputs, stageDevices)) } return nil diff --git a/pkg/osbuild/mkfs_stages_test.go b/pkg/osbuild/mkfs_stages_test.go index 34e3e84ee2..28d23f9deb 100644 --- a/pkg/osbuild/mkfs_stages_test.go +++ b/pkg/osbuild/mkfs_stages_test.go @@ -79,7 +79,7 @@ func TestNewMkfsStage(t *testing.T) { func TestGenFsStages(t *testing.T) { pt := testdisk.MakeFakePartitionTable("/", "/boot", "/boot/efi", "swap") - stages := GenFsStages(pt, "file.img") + stages := GenFsStages(pt, "file.img", "build") assert.Equal(t, []*Stage{ { Type: "org.osbuild.mkfs.ext4", @@ -152,7 +152,7 @@ func TestGenFsStages(t *testing.T) { func TestGenFsStagesBtrfs(t *testing.T) { // Let's put there /extra to make sure that / and /extra creates only one btrfs partition pt := testdisk.MakeFakeBtrfsPartitionTable("/", "/boot", "/boot/efi", "/extra", "swap") - stages := GenFsStages(pt, "file.img") + stages := GenFsStages(pt, "file.img", "build") assert.Equal(t, []*Stage{ { Type: "org.osbuild.mkfs.ext4", @@ -258,7 +258,7 @@ func TestGenFsStagesBtrfs(t *testing.T) { func TestGenFsStagesLVM(t *testing.T) { pt := testdisk.MakeFakeLVMPartitionTable("/", "/boot", "/boot/efi", "/home", "swap") - stages := GenFsStages(pt, "file.img") + stages := GenFsStages(pt, "file.img", "build") assert.Equal(t, []*Stage{ { Type: "org.osbuild.mkfs.ext4", @@ -365,7 +365,7 @@ func TestGenFsStagesLVM(t *testing.T) { func TestGenFsStagesRaw(t *testing.T) { pt := testdisk.MakeFakePartitionTable("/", "/boot", "/boot/efi", "raw") - stages := GenFsStages(pt, "file.img") + stages := GenFsStages(pt, "file.img", "build") assert.Equal(t, []*Stage{ { Type: "org.osbuild.mkfs.ext4", @@ -448,6 +448,6 @@ func TestGenFsStagesUnhappy(t *testing.T) { } assert.PanicsWithValue(t, "unknown fs type: ext2", func() { - GenFsStages(pt, "file.img") + GenFsStages(pt, "file.img", "build") }) }