pipelines: make OSPipeline own the PartitionTable

The OSPipeline might need to know what disk layout it will be put onto, enforce this by making
the PartitionTable a property of the OSPipeline, and require child pipelines to query it when needed.
This commit is contained in:
Tom Gundersen 2022-06-26 18:56:17 +01:00
parent ae34513d18
commit f60092033b
3 changed files with 59 additions and 70 deletions

View file

@ -17,19 +17,14 @@ func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, opti
buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey]) buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey])
pipelines = append(pipelines, buildPipeline.Serialize()) pipelines = append(pipelines, buildPipeline.Serialize())
partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, rng)
if err != nil {
return nil, err
}
treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, partitionTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pipelines = append(pipelines, treePipeline.Serialize()) pipelines = append(pipelines, treePipeline.Serialize())
diskfile := "disk.img" diskfile := "disk.img"
imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, partitionTable, t.arch) imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, t.arch)
pipelines = append(pipelines, imagePipeline.Serialize()) pipelines = append(pipelines, imagePipeline.Serialize())
qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatQCOW2, osbuild.QCOW2Options{Compat: "1.1"}) qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatQCOW2, osbuild.QCOW2Options{Compat: "1.1"})
@ -44,19 +39,14 @@ func vhdPipelines(t *imageType, customizations *blueprint.Customizations, option
buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey]) buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey])
pipelines = append(pipelines, buildPipeline.Serialize()) pipelines = append(pipelines, buildPipeline.Serialize())
partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, rng)
if err != nil {
return nil, err
}
treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, partitionTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pipelines = append(pipelines, treePipeline.Serialize()) pipelines = append(pipelines, treePipeline.Serialize())
diskfile := "disk.img" diskfile := "disk.img"
imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, partitionTable, t.arch) imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, t.arch)
pipelines = append(pipelines, imagePipeline.Serialize()) pipelines = append(pipelines, imagePipeline.Serialize())
qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatVPC, nil) qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatVPC, nil)
@ -70,19 +60,14 @@ func vmdkPipelines(t *imageType, customizations *blueprint.Customizations, optio
buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey]) buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey])
pipelines = append(pipelines, buildPipeline.Serialize()) pipelines = append(pipelines, buildPipeline.Serialize())
partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, rng)
if err != nil {
return nil, err
}
treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, partitionTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pipelines = append(pipelines, treePipeline.Serialize()) pipelines = append(pipelines, treePipeline.Serialize())
diskfile := "disk.img" diskfile := "disk.img"
imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, partitionTable, t.arch) imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, t.arch)
pipelines = append(pipelines, imagePipeline.Serialize()) pipelines = append(pipelines, imagePipeline.Serialize())
qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatVMDK, osbuild.VMDKOptions{Subformat: osbuild.VMDKSubformatStreamOptimized}) qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatVMDK, osbuild.VMDKOptions{Subformat: osbuild.VMDKSubformatStreamOptimized})
@ -96,19 +81,14 @@ func openstackPipelines(t *imageType, customizations *blueprint.Customizations,
buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey]) buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey])
pipelines = append(pipelines, buildPipeline.Serialize()) pipelines = append(pipelines, buildPipeline.Serialize())
partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, rng)
if err != nil {
return nil, err
}
treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, partitionTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pipelines = append(pipelines, treePipeline.Serialize()) pipelines = append(pipelines, treePipeline.Serialize())
diskfile := "disk.img" diskfile := "disk.img"
imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, partitionTable, t.arch) imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, t.arch)
pipelines = append(pipelines, imagePipeline.Serialize()) pipelines = append(pipelines, imagePipeline.Serialize())
qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatQCOW2, nil) qemuPipeline := qemuPipeline(&buildPipeline, &imagePipeline, diskfile, t.filename, osbuild.QEMUFormatQCOW2, nil)
@ -124,18 +104,13 @@ func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations,
buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey]) buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner, repos, packageSetSpecs[buildPkgsKey])
pipelines = append(pipelines, buildPipeline.Serialize()) pipelines = append(pipelines, buildPipeline.Serialize())
partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, rng)
if err != nil {
return nil, err
}
treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, partitionTable)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pipelines = append(pipelines, treePipeline.Serialize()) pipelines = append(pipelines, treePipeline.Serialize())
imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, partitionTable, t.arch) imagePipeline := liveImagePipeline(&buildPipeline, &treePipeline, diskfile, t.arch)
pipelines = append(pipelines, imagePipeline.Serialize()) pipelines = append(pipelines, imagePipeline.Serialize())
return pipelines, nil return pipelines, nil
} }
@ -209,13 +184,21 @@ func osPipeline(buildPipeline *pipeline.BuildPipeline,
packages []rpmmd.PackageSpec, packages []rpmmd.PackageSpec,
c *blueprint.Customizations, c *blueprint.Customizations,
options distro.ImageOptions, options distro.ImageOptions,
pt *disk.PartitionTable) (pipeline.OSPipeline, error) { rng *rand.Rand) (pipeline.OSPipeline, error) {
imageConfig := t.getDefaultImageConfig() imageConfig := t.getDefaultImageConfig()
pl := pipeline.NewOSPipeline(buildPipeline, t.rpmOstree, repos, packages, c.GetKernel().Name) var pt *disk.PartitionTable
if t.bootable {
// TODO: should there always be a partition table?
var err error
pt, err = t.getPartitionTable(c.GetFilesystems(), options, rng)
if err != nil {
return pipeline.OSPipeline{}, err
}
}
pl.PartitionTable = pt pl := pipeline.NewOSPipeline(buildPipeline, t.rpmOstree, repos, packages, pt, c.GetKernel().Name)
if t.Arch().Name() == distro.S390xArchName { if t.Arch().Name() == distro.S390xArchName {
pl.BootLoader = pipeline.BOOTLOADER_ZIPL pl.BootLoader = pipeline.BOOTLOADER_ZIPL
@ -369,7 +352,7 @@ func bootISOPipeline(buildPipeline *pipeline.BuildPipeline, treePipeline *pipeli
return p return p
} }
func liveImagePipeline(buildPipeline *pipeline.BuildPipeline, treePipeline *pipeline.OSPipeline, outputFilename string, pt *disk.PartitionTable, arch *architecture) pipeline.LiveImgPipeline { func liveImagePipeline(buildPipeline *pipeline.BuildPipeline, treePipeline *pipeline.OSPipeline, outputFilename string, arch *architecture) pipeline.LiveImgPipeline {
p := pipeline.NewLiveImgPipeline(buildPipeline, treePipeline) p := pipeline.NewLiveImgPipeline(buildPipeline, treePipeline)
p.Filename = outputFilename p.Filename = outputFilename
@ -381,8 +364,6 @@ func liveImagePipeline(buildPipeline *pipeline.BuildPipeline, treePipeline *pipe
p.GRUBLegacy = arch.legacy p.GRUBLegacy = arch.legacy
} }
p.PartitionTable = *pt
return p return p
} }

View file

@ -1,17 +1,15 @@
package pipeline package pipeline
import ( import (
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/osbuild2" "github.com/osbuild/osbuild-composer/internal/osbuild2"
) )
type LiveImgPipeline struct { type LiveImgPipeline struct {
Pipeline Pipeline
PartitionTable disk.PartitionTable BootLoader BootLoader
BootLoader BootLoader GRUBLegacy string
GRUBLegacy string treePipeline *OSPipeline
treePipeline *OSPipeline Filename string
Filename string
} }
func NewLiveImgPipeline(buildPipeline *BuildPipeline, treePipeline *OSPipeline) LiveImgPipeline { func NewLiveImgPipeline(buildPipeline *BuildPipeline, treePipeline *OSPipeline) LiveImgPipeline {
@ -24,27 +22,32 @@ func NewLiveImgPipeline(buildPipeline *BuildPipeline, treePipeline *OSPipeline)
func (p LiveImgPipeline) Serialize() osbuild2.Pipeline { func (p LiveImgPipeline) Serialize() osbuild2.Pipeline {
pipeline := p.Pipeline.Serialize() pipeline := p.Pipeline.Serialize()
for _, stage := range osbuild2.GenImagePrepareStages(&p.PartitionTable, p.Filename, osbuild2.PTSfdisk) { pt := p.treePipeline.PartitionTable()
if pt == nil {
panic("no partition table in live image")
}
for _, stage := range osbuild2.GenImagePrepareStages(pt, p.Filename, osbuild2.PTSfdisk) {
pipeline.AddStage(stage) pipeline.AddStage(stage)
} }
inputName := "root-tree" inputName := "root-tree"
copyOptions, copyDevices, copyMounts := osbuild2.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.Filename, &p.PartitionTable) copyOptions, copyDevices, copyMounts := osbuild2.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.Filename, pt)
copyInputs := osbuild2.NewCopyStagePipelineTreeInputs(inputName, p.treePipeline.Name()) copyInputs := osbuild2.NewCopyStagePipelineTreeInputs(inputName, p.treePipeline.Name())
pipeline.AddStage(osbuild2.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts)) pipeline.AddStage(osbuild2.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
for _, stage := range osbuild2.GenImageFinishStages(&p.PartitionTable, p.Filename) { for _, stage := range osbuild2.GenImageFinishStages(pt, p.Filename) {
pipeline.AddStage(stage) pipeline.AddStage(stage)
} }
switch p.BootLoader { switch p.BootLoader {
case BOOTLOADER_GRUB: case BOOTLOADER_GRUB:
if p.GRUBLegacy != "" { if p.GRUBLegacy != "" {
pipeline.AddStage(osbuild2.NewGrub2InstStage(osbuild2.NewGrub2InstStageOption(p.Filename, &p.PartitionTable, p.GRUBLegacy))) pipeline.AddStage(osbuild2.NewGrub2InstStage(osbuild2.NewGrub2InstStageOption(p.Filename, pt, p.GRUBLegacy)))
} }
case BOOTLOADER_ZIPL: case BOOTLOADER_ZIPL:
loopback := osbuild2.NewLoopbackDevice(&osbuild2.LoopbackDeviceOptions{Filename: p.Filename}) loopback := osbuild2.NewLoopbackDevice(&osbuild2.LoopbackDeviceOptions{Filename: p.Filename})
pipeline.AddStage(osbuild2.NewZiplInstStage(osbuild2.NewZiplInstStageOptions(p.treePipeline.KernelVer(), &p.PartitionTable), loopback, copyDevices, copyMounts)) pipeline.AddStage(osbuild2.NewZiplInstStage(osbuild2.NewZiplInstStageOptions(p.treePipeline.KernelVer(), pt), loopback, copyDevices, copyMounts))
} }
return pipeline return pipeline

View file

@ -22,7 +22,6 @@ type OSPipeline struct {
GRUBLegacy string GRUBLegacy string
Vendor string Vendor string
GPGKeyFiles []string GPGKeyFiles []string
PartitionTable *disk.PartitionTable
Language string Language string
Keyboard *string Keyboard *string
Hostname string Hostname string
@ -55,25 +54,27 @@ type OSPipeline struct {
PwQuality *osbuild2.PwqualityConfStageOptions PwQuality *osbuild2.PwqualityConfStageOptions
WAAgentConfig *osbuild2.WAAgentConfStageOptions WAAgentConfig *osbuild2.WAAgentConfStageOptions
osTree bool osTree bool
repos []rpmmd.RepoConfig repos []rpmmd.RepoConfig
packageSpecs []rpmmd.PackageSpec packageSpecs []rpmmd.PackageSpec
kernelVer string partitionTable *disk.PartitionTable
kernelVer string
} }
func NewOSPipeline(buildPipeline *BuildPipeline, osTree bool, repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, kernelName string) OSPipeline { func NewOSPipeline(buildPipeline *BuildPipeline, osTree bool, repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, pt *disk.PartitionTable, kernelName string) OSPipeline {
name := "os" name := "os"
if osTree { if osTree {
name = "ostree-tree" name = "ostree-tree"
} }
kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packages, kernelName) kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packages, kernelName)
return OSPipeline{ return OSPipeline{
Pipeline: New(name, buildPipeline, nil), Pipeline: New(name, buildPipeline, nil),
osTree: osTree, osTree: osTree,
repos: repos, repos: repos,
packageSpecs: packages, packageSpecs: packages,
kernelVer: kernelVer, partitionTable: pt,
Hostname: "localhost.localdomain", kernelVer: kernelVer,
Hostname: "localhost.localdomain",
} }
} }
@ -81,6 +82,10 @@ func (p OSPipeline) KernelVer() string {
return p.kernelVer return p.kernelVer
} }
func (p OSPipeline) PartitionTable() *disk.PartitionTable {
return p.partitionTable
}
func (p OSPipeline) Serialize() osbuild2.Pipeline { func (p OSPipeline) Serialize() osbuild2.Pipeline {
pipeline := p.Pipeline.Serialize() pipeline := p.Pipeline.Serialize()
@ -93,7 +98,7 @@ func (p OSPipeline) Serialize() osbuild2.Pipeline {
pipeline.AddStage(osbuild2.NewRPMStage(rpmOptions, osbuild2.NewRpmStageSourceFilesInputs(p.packageSpecs))) pipeline.AddStage(osbuild2.NewRPMStage(rpmOptions, osbuild2.NewRpmStageSourceFilesInputs(p.packageSpecs)))
// If the /boot is on a separate partition, the prefix for the BLS stage must be "" // If the /boot is on a separate partition, the prefix for the BLS stage must be ""
if p.PartitionTable == nil || p.PartitionTable.FindMountable("/boot") == nil { if p.PartitionTable() == nil || p.PartitionTable().FindMountable("/boot") == nil {
pipeline.AddStage(osbuild2.NewFixBLSStage(&osbuild2.FixBLSStageOptions{})) pipeline.AddStage(osbuild2.NewFixBLSStage(&osbuild2.FixBLSStageOptions{}))
} else { } else {
pipeline.AddStage(osbuild2.NewFixBLSStage(&osbuild2.FixBLSStageOptions{Prefix: common.StringToPtr("")})) pipeline.AddStage(osbuild2.NewFixBLSStage(&osbuild2.FixBLSStageOptions{Prefix: common.StringToPtr("")}))
@ -228,17 +233,17 @@ func (p OSPipeline) Serialize() osbuild2.Pipeline {
pipeline.AddStage(osbuild2.NewWAAgentConfStage(p.WAAgentConfig)) pipeline.AddStage(osbuild2.NewWAAgentConfStage(p.WAAgentConfig))
} }
if p.PartitionTable != nil { if pt := p.PartitionTable(); pt != nil {
kernelOptions := osbuild2.GenImageKernelOptions(p.PartitionTable) kernelOptions := osbuild2.GenImageKernelOptions(p.PartitionTable())
kernelOptions = append(kernelOptions, p.KernelOptionsAppend...) kernelOptions = append(kernelOptions, p.KernelOptionsAppend...)
pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), p.PartitionTable) pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), pt)
pipeline.AddStage(osbuild2.NewFSTabStage(osbuild2.NewFSTabStageOptions(p.PartitionTable))) pipeline.AddStage(osbuild2.NewFSTabStage(osbuild2.NewFSTabStageOptions(pt)))
var bootloader *osbuild2.Stage var bootloader *osbuild2.Stage
switch p.BootLoader { switch p.BootLoader {
case BOOTLOADER_GRUB: case BOOTLOADER_GRUB:
options := osbuild2.NewGrub2StageOptionsUnified(p.PartitionTable, p.kernelVer, p.UEFI, p.GRUBLegacy, p.Vendor, false) options := osbuild2.NewGrub2StageOptionsUnified(pt, p.kernelVer, p.UEFI, p.GRUBLegacy, p.Vendor, false)
if cfg := p.Grub2Config; cfg != nil { if cfg := p.Grub2Config; cfg != nil {
// TODO: don't store Grub2Config in OSPipeline, making the overrides unnecessary // TODO: don't store Grub2Config in OSPipeline, making the overrides unnecessary
// grub2.Config.Default is owned and set by `NewGrub2StageOptionsUnified` // grub2.Config.Default is owned and set by `NewGrub2StageOptionsUnified`