- Use newer granular stages to build the bootiso tree rather than the deprecated bootiso.mono stage. - Adjust the ISOTree struct properties: add the ones needed by the new stages and remove any properties that have been moved to the new pipelines.
235 lines
6.4 KiB
Go
235 lines
6.4 KiB
Go
package manifest
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
|
|
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
|
"github.com/osbuild/osbuild-composer/internal/disk"
|
|
"github.com/osbuild/osbuild-composer/internal/distro"
|
|
"github.com/osbuild/osbuild-composer/internal/osbuild"
|
|
)
|
|
|
|
// An ISOTree represents a tree containing the anaconda installer,
|
|
// configuration in terms of a kickstart file, as well as an embedded
|
|
// payload to be installed.
|
|
type ISOTree struct {
|
|
Base
|
|
|
|
// TODO: review optional and mandatory fields and their meaning
|
|
OSName string
|
|
Release string
|
|
Users []blueprint.UserCustomization
|
|
Groups []blueprint.GroupCustomization
|
|
|
|
PartitionTable *disk.PartitionTable
|
|
|
|
anacondaPipeline *Anaconda
|
|
rootfsPipeline *ISORootfsImg
|
|
bootTreePipeline *EFIBootTree
|
|
|
|
KSPath string
|
|
isoLabel string
|
|
osTreeCommit string
|
|
osTreeURL string
|
|
osTreeRef string
|
|
}
|
|
|
|
func NewISOTree(m *Manifest,
|
|
buildPipeline *Build,
|
|
anacondaPipeline *Anaconda,
|
|
rootfsPipeline *ISORootfsImg,
|
|
bootTreePipeline *EFIBootTree,
|
|
osTreeCommit,
|
|
osTreeURL,
|
|
osTreeRef,
|
|
isoLabel string) *ISOTree {
|
|
|
|
p := &ISOTree{
|
|
Base: NewBase(m, "bootiso-tree", buildPipeline),
|
|
anacondaPipeline: anacondaPipeline,
|
|
rootfsPipeline: rootfsPipeline,
|
|
bootTreePipeline: bootTreePipeline,
|
|
isoLabel: isoLabel,
|
|
osTreeCommit: osTreeCommit,
|
|
osTreeURL: osTreeURL,
|
|
osTreeRef: osTreeRef,
|
|
}
|
|
buildPipeline.addDependent(p)
|
|
if anacondaPipeline.Base.manifest != m {
|
|
panic("anaconda pipeline from different manifest")
|
|
}
|
|
m.addPipeline(p)
|
|
return p
|
|
}
|
|
|
|
func (p *ISOTree) getOSTreeCommits() []osTreeCommit {
|
|
return []osTreeCommit{
|
|
{
|
|
checksum: p.osTreeCommit,
|
|
url: p.osTreeURL,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (p *ISOTree) getBuildPackages() []string {
|
|
packages := []string{
|
|
"rpm-ostree",
|
|
"squashfs-tools",
|
|
}
|
|
return packages
|
|
}
|
|
|
|
func (p *ISOTree) serialize() osbuild.Pipeline {
|
|
pipeline := p.Base.serialize()
|
|
|
|
ostreeRepoPath := "/ostree/repo"
|
|
kernelOpts := fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", p.isoLabel, p.KSPath)
|
|
|
|
pipeline.AddStage(osbuild.NewMkdirStage(&osbuild.MkdirStageOptions{
|
|
Paths: []osbuild.Path{
|
|
{
|
|
Path: "images",
|
|
},
|
|
{
|
|
Path: "images/pxeboot",
|
|
},
|
|
},
|
|
}))
|
|
|
|
inputName := "tree"
|
|
copyStageOptions := &osbuild.CopyStageOptions{
|
|
Paths: []osbuild.CopyStagePath{
|
|
{
|
|
From: fmt.Sprintf("input://%s/boot/vmlinuz-%s", inputName, p.anacondaPipeline.kernelVer),
|
|
To: "tree:///images/pxeboot/vmlinuz",
|
|
},
|
|
{
|
|
From: fmt.Sprintf("input://%s/boot/initramfs-%s.img", inputName, p.anacondaPipeline.kernelVer),
|
|
To: "tree:///images/pxeboot/initrd.img",
|
|
},
|
|
},
|
|
}
|
|
copyStageInputs := osbuild.NewPipelineTreeInputs(inputName, p.anacondaPipeline.Name())
|
|
copyStage := osbuild.NewCopyStageSimple(copyStageOptions, copyStageInputs)
|
|
pipeline.AddStage(copyStage)
|
|
|
|
squashfsOptions := osbuild.SquashfsStageOptions{
|
|
Filename: "images/install.img",
|
|
Compression: osbuild.FSCompression{
|
|
Method: "lz4",
|
|
},
|
|
}
|
|
squashfsStage := osbuild.NewSquashfsStage(&squashfsOptions, p.rootfsPipeline.Name())
|
|
pipeline.AddStage(squashfsStage)
|
|
|
|
isoLinuxOptions := &osbuild.ISOLinuxStageOptions{
|
|
Product: osbuild.ISOLinuxProduct{
|
|
Name: p.anacondaPipeline.product,
|
|
Version: p.anacondaPipeline.version,
|
|
},
|
|
Kernel: osbuild.ISOLinuxKernel{
|
|
Dir: "/images/pxeboot",
|
|
Opts: []string{kernelOpts},
|
|
},
|
|
}
|
|
isoLinuxStage := osbuild.NewISOLinuxStage(isoLinuxOptions, p.anacondaPipeline.Name())
|
|
pipeline.AddStage(isoLinuxStage)
|
|
|
|
filename := "images/efiboot.img"
|
|
pipeline.AddStage(osbuild.NewTruncateStage(&osbuild.TruncateStageOptions{
|
|
Filename: filename,
|
|
Size: "20MB",
|
|
}))
|
|
|
|
efibootDevice := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: filename})
|
|
for _, stage := range osbuild.GenMkfsStages(p.PartitionTable, efibootDevice) {
|
|
pipeline.AddStage(stage)
|
|
}
|
|
|
|
inputName = "root-tree"
|
|
copyInputs := osbuild.NewPipelineTreeInputs(inputName, p.bootTreePipeline.Name())
|
|
copyOptions, copyDevices, copyMounts := osbuild.GenCopyFSTreeOptions(inputName, p.bootTreePipeline.Name(), filename, p.PartitionTable)
|
|
pipeline.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts))
|
|
|
|
copyInputs = osbuild.NewPipelineTreeInputs(inputName, p.bootTreePipeline.Name())
|
|
pipeline.AddStage(osbuild.NewCopyStageSimple(
|
|
&osbuild.CopyStageOptions{
|
|
Paths: []osbuild.CopyStagePath{
|
|
{
|
|
From: fmt.Sprintf("input://%s/EFI", inputName),
|
|
To: "tree:///",
|
|
},
|
|
},
|
|
},
|
|
copyInputs,
|
|
))
|
|
|
|
kickstartOptions, err := osbuild.NewKickstartStageOptions(p.KSPath, "", p.Users, p.Groups, makeISORootPath(ostreeRepoPath), p.osTreeRef, p.OSName)
|
|
if err != nil {
|
|
panic("password encryption failed")
|
|
}
|
|
|
|
pipeline.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: ostreeRepoPath}))
|
|
pipeline.AddStage(osbuild.NewOSTreePullStage(
|
|
&osbuild.OSTreePullStageOptions{Repo: ostreeRepoPath},
|
|
osbuild.NewOstreePullStageInputs("org.osbuild.source", p.osTreeCommit, p.osTreeRef),
|
|
))
|
|
|
|
pipeline.AddStage(osbuild.NewKickstartStage(kickstartOptions))
|
|
pipeline.AddStage(osbuild.NewDiscinfoStage(&osbuild.DiscinfoStageOptions{
|
|
BaseArch: p.anacondaPipeline.platform.GetArch().String(),
|
|
Release: p.Release,
|
|
}))
|
|
|
|
return pipeline
|
|
}
|
|
|
|
func bootISOMonoStageOptions(kernelVer, arch, vendor, product, osVersion, isolabel, kspath string) *osbuild.BootISOMonoStageOptions {
|
|
comprOptions := new(osbuild.FSCompressionOptions)
|
|
if bcj := osbuild.BCJOption(arch); bcj != "" {
|
|
comprOptions.BCJ = bcj
|
|
}
|
|
var architectures []string
|
|
|
|
if arch == distro.X86_64ArchName {
|
|
architectures = []string{"X64"}
|
|
} else if arch == distro.Aarch64ArchName {
|
|
architectures = []string{"AA64"}
|
|
} else {
|
|
panic("unsupported architecture")
|
|
}
|
|
|
|
return &osbuild.BootISOMonoStageOptions{
|
|
Product: osbuild.Product{
|
|
Name: product,
|
|
Version: osVersion,
|
|
},
|
|
ISOLabel: isolabel,
|
|
Kernel: kernelVer,
|
|
KernelOpts: fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", isolabel, kspath),
|
|
EFI: osbuild.EFI{
|
|
Architectures: architectures,
|
|
Vendor: vendor,
|
|
},
|
|
ISOLinux: osbuild.ISOLinux{
|
|
Enabled: arch == distro.X86_64ArchName,
|
|
Debug: false,
|
|
},
|
|
Templates: "99-generic",
|
|
RootFS: osbuild.RootFS{
|
|
Size: 9216,
|
|
Compression: osbuild.FSCompression{
|
|
Method: "xz",
|
|
Options: comprOptions,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
//makeISORootPath return a path that can be used to address files and folders in
|
|
//the root of the iso
|
|
func makeISORootPath(p string) string {
|
|
fullpath := path.Join("/run/install/repo", p)
|
|
return fmt.Sprintf("file://%s", fullpath)
|
|
}
|