diff --git a/cmd/osbuild-playground/main.go b/cmd/osbuild-playground/main.go index 1173d6912..f28c74f28 100644 --- a/cmd/osbuild-playground/main.go +++ b/cmd/osbuild-playground/main.go @@ -49,11 +49,11 @@ func findDnfJsonBin() string { func main() { var distroArg string - flag.StringVar(&distroArg, "distro", "", "distro to build from") + flag.StringVar(&distroArg, "distro", "host", "distro to build from") var archArg string flag.StringVar(&archArg, "arch", common.CurrentArch(), "architecture to build for") var imageTypeArg string - flag.StringVar(&imageTypeArg, "type", "my-image", "image type to build") + flag.StringVar(&imageTypeArg, "type", "my-container", "image type to build") flag.Parse() // Path to options or '-' for stdin @@ -83,16 +83,16 @@ func main() { distros := distroregistry.NewDefault() var d distro.Distro - if distroArg != "" { - d = distros.GetDistro(distroArg) - if d == nil { - panic(fmt.Sprintf("distro '%s' not supported\n", distroArg)) - } - } else { + if distroArg == "host" { d = distros.FromHost() if d == nil { panic("host distro not supported") } + } else { + d = distros.GetDistro(distroArg) + if d == nil { + panic(fmt.Sprintf("distro '%s' not supported\n", distroArg)) + } } arch, err := d.GetArch(archArg) diff --git a/cmd/osbuild-playground/my-container.go b/cmd/osbuild-playground/my-container.go new file mode 100644 index 000000000..3fb9aa106 --- /dev/null +++ b/cmd/osbuild-playground/my-container.go @@ -0,0 +1,71 @@ +package main + +import ( + "github.com/osbuild/osbuild-composer/internal/manifest" + "github.com/osbuild/osbuild-composer/internal/platform" + "github.com/osbuild/osbuild-composer/internal/rpmmd" + "github.com/osbuild/osbuild-composer/internal/runner" +) + +// MyContainer contains the arguments passed in as a JSON blob. +// You can replace them with whatever you want to use to +// configure your image. In the current example they are +// unused. +type MyContainer struct { + MyOption string `json:"my_option"` +} + +// Name returns the name of the image type, used to select what kind +// of image to build. +func (img *MyContainer) Name() string { + return "my-container" +} + +// init registeres this image type +func init() { + AddImageType(&MyContainer{}) +} + +// Build your manifest by attaching pipelines to it +// +// @m is the manifest you are constructing +// @options are what was passed in on the commandline +// @repos are the default repositories for the host OS/arch +// @runner is needed by any build pipelines +// +// Return nil when you are done, or an error if something +// went wrong. Your manifest will be streamed to osbuild +// for building. +func (img *MyContainer) InstantiateManifest(m *manifest.Manifest, repos []rpmmd.RepoConfig, runner runner.Runner) error { + // Let's create a simple OCI container! + + // configure a build pipeline + build := manifest.NewBuild(m, runner, repos) + + // create a minimal non-bootable OS tree + os := manifest.NewOS(m, build, &platform.X86{}, repos) + + // create an OCI container containing the OS tree created above + manifest.NewOCIContainer(m, build, os) + + return nil +} + +// GetExports returns a list of the pipelines osbuild should export. +// These are the pipelines containing the artefact you want returned. +// +// TODO: Move this to be implemented in terms ofthe Manifest package. +// We should not need to know the pipeline names. +func (img *MyContainer) GetExports() []string { + return []string{"container"} +} + +// GetCheckpoints returns a list of the pipelines osbuild should +// checkpoint. These are the pipelines likely to be reusable in +// future runs. +// +// TODO: Move this to be implemented in terms ofthe Manifest package. +// We should not need to know the pipeline names. +func (img *MyContainer) GetCheckpoints() []string { + return []string{"build"} +} diff --git a/cmd/osbuild-playground/my-image.go b/cmd/osbuild-playground/my-image.go index b7294dff6..e87d8dba6 100644 --- a/cmd/osbuild-playground/my-image.go +++ b/cmd/osbuild-playground/my-image.go @@ -1,78 +1,62 @@ package main import ( + "math/rand" + + "github.com/osbuild/osbuild-composer/internal/disk" "github.com/osbuild/osbuild-composer/internal/manifest" "github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/runner" ) -func init() { - AddImageType(&MyImage{}) -} - -// MyImage contains the arguments passed in as a JSON blob. -// You can replace them with whatever you want to use to -// configure your image. In the current example they are -// unused. type MyImage struct { MyOption string `json:"my_option"` - Filename string `json:"filename"` } -// Name returns the name of the image type, used to select what kind -// of image to build. func (img *MyImage) Name() string { return "my-image" } -// Build your manifest by attaching pipelines to it -// -// @m is the manifest you are constructing -// @options are what was passed in on the commandline -// @repos are the default repositories for the host OS/arch -// @runner is needed by any build pipelines -// -// Return nil when you are done, or an error if something -// went wrong. Your manifest will be streamed to osbuild -// for building. +func init() { + AddImageType(&MyImage{}) +} + func (img *MyImage) InstantiateManifest(m *manifest.Manifest, repos []rpmmd.RepoConfig, runner runner.Runner) error { - // Let's create a simple OCI container! + // Let's create a simple raw image! // configure a build pipeline build := manifest.NewBuild(m, runner, repos) - // create a non-bootable OS tree containing the `core` comps group - os := manifest.NewOS(m, build, &platform.X86{}, repos) - os.ExtraBasePackages = []string{ - "@core", + // create an x86_64 platform with bios boot + platform := &platform.X86{ + BIOS: true, } - filename := "my-container.tar" - if img.Filename != "" { - filename = img.Filename + // TODO: add helper + // math/rand is good enough in this case + /* #nosec G404 */ + pt, err := disk.NewPartitionTable(&basePT, nil, 0, false, rand.New(rand.NewSource(0))) + if err != nil { + panic(err) } - // create an OCI container containing the OS tree created above - manifest.NewOCIContainer(m, build, &os.Base, "x86_64", filename) + + // create a minimal bootable OS tree + os := manifest.NewOS(m, build, platform, repos) + os.PartitionTable = pt // we need a partition table + os.KernelName = "kernel" // use the default fedora kernel + + // create a raw image containing the OS tree created above + manifest.NewRawImage(m, build, os) return nil } -// GetExports returns a list of the pipelines osbuild should export. -// These are the pipelines containing the artefact you want returned. -// -// TODO: Move this to be implemented in terms ofthe Manifest package. -// We should not need to know the pipeline names. +// TODO: make internal func (img *MyImage) GetExports() []string { - return []string{"container"} + return []string{"image"} } -// GetCheckpoints returns a list of the pipelines osbuild should -// checkpoint. These are the pipelines likely to be reusable in -// future runs. -// -// TODO: Move this to be implemented in terms ofthe Manifest package. -// We should not need to know the pipeline names. func (img *MyImage) GetCheckpoints() []string { return []string{"build"} } diff --git a/cmd/osbuild-playground/partitiontables.go b/cmd/osbuild-playground/partitiontables.go new file mode 100644 index 000000000..b55a85626 --- /dev/null +++ b/cmd/osbuild-playground/partitiontables.go @@ -0,0 +1,56 @@ +package main + +import "github.com/osbuild/osbuild-composer/internal/disk" + +var basePT = disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: "gpt", + Partitions: []disk.Partition{ + { + Size: 1048576, // 1MB + Bootable: true, + Type: disk.BIOSBootPartitionGUID, + UUID: disk.BIOSBootPartitionUUID, + }, + { + Size: 209715200, // 200 MB + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Payload: &disk.Filesystem{ + Type: "vfat", + UUID: disk.EFIFilesystemUUID, + Mountpoint: "/boot/efi", + Label: "EFI-SYSTEM", + FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", + FSTabFreq: 0, + FSTabPassNo: 2, + }, + }, + { + Size: 524288000, // 500 MB + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Payload: &disk.Filesystem{ + Type: "ext4", + Mountpoint: "/boot", + Label: "boot", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2147483648, // 2GiB + Type: disk.FilesystemDataGUID, + UUID: disk.RootPartitionUUID, + Payload: &disk.Filesystem{ + Type: "ext4", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, +} diff --git a/internal/distro/fedora/manifests.go b/internal/distro/fedora/manifests.go index 70ab50924..381e9e2d2 100644 --- a/internal/distro/fedora/manifests.go +++ b/internal/distro/fedora/manifests.go @@ -6,6 +6,7 @@ import ( "github.com/osbuild/osbuild-composer/internal/blueprint" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/manifest" + "github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/workload" ) @@ -24,8 +25,9 @@ func qcow2Manifest(m *manifest.Manifest, if err != nil { return err } - imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline, "disk.img") - qcow2Pipeline := manifest.NewQCOW2(m, buildPipeline, imagePipeline, t.filename) + imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline) + qcow2Pipeline := manifest.NewQCOW2(m, buildPipeline, imagePipeline) + qcow2Pipeline.Filename = t.filename qcow2Pipeline.Compat = "1.1" return nil @@ -45,8 +47,9 @@ func vhdManifest(m *manifest.Manifest, if err != nil { return err } - imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline, "disk.img") - manifest.NewVPC(m, buildPipeline, imagePipeline, t.filename) + imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline) + p := manifest.NewVPC(m, buildPipeline, imagePipeline) + p.Filename = t.filename return nil } @@ -65,8 +68,9 @@ func vmdkManifest(m *manifest.Manifest, if err != nil { return err } - imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline, "disk.img") - manifest.NewVMDK(m, buildPipeline, imagePipeline, t.filename) + imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline) + p := manifest.NewVMDK(m, buildPipeline, imagePipeline) + p.Filename = t.filename return nil } @@ -85,8 +89,9 @@ func openstackManifest(m *manifest.Manifest, if err != nil { return err } - imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline, "disk.img") - manifest.NewQCOW2(m, buildPipeline, imagePipeline, t.filename) + imagePipeline := manifest.NewRawImage(m, buildPipeline, treePipeline) + p := manifest.NewQCOW2(m, buildPipeline, imagePipeline) + p.Filename = t.filename return nil } @@ -106,7 +111,8 @@ func ec2CommonManifest(m *manifest.Manifest, if err != nil { return nil } - manifest.NewRawImage(m, buildPipeline, treePipeline, diskfile) + p := manifest.NewRawImage(m, buildPipeline, treePipeline) + p.Filename = diskfile return nil } @@ -137,7 +143,15 @@ func iotInstallerManifest(m *manifest.Manifest, d := t.arch.distro ksUsers := len(customizations.GetUsers())+len(customizations.GetGroups()) > 0 - anacondaTreePipeline := anacondaTreePipeline(m, buildPipeline, repos, packageSets[installerPkgsKey], t.Arch().Name(), d.product, d.osVersion, "IoT", ksUsers) + anacondaTreePipeline := anacondaTreePipeline(m, + buildPipeline, + t.platform, + repos, + packageSets[installerPkgsKey], + d.product, + d.osVersion, + "IoT", + ksUsers) isoTreePipeline := bootISOTreePipeline(m, buildPipeline, anacondaTreePipeline, options, d.vendor, d.isolabelTmpl, customizations.GetUsers(), customizations.GetGroups()) bootISOPipeline(m, buildPipeline, isoTreePipeline, t.Filename(), false) @@ -176,7 +190,8 @@ func iotCommitManifest(m *manifest.Manifest, if err != nil { return err } - manifest.NewTar(m, buildPipeline, &commitPipeline.Base, "commit-archive", t.Filename()) + p := manifest.NewTar(m, buildPipeline, &commitPipeline.Base, "commit-archive") + p.Filename = t.Filename() return nil } @@ -196,8 +211,17 @@ func iotContainerManifest(m *manifest.Manifest, nginxConfigPath := "/etc/nginx.conf" httpPort := "8080" - containerTreePipeline := containerTreePipeline(m, buildPipeline, commitPipeline, repos, packageSets[containerPkgsKey], options, customizations, nginxConfigPath, httpPort) - containerPipeline(m, buildPipeline, &containerTreePipeline.Base, t, nginxConfigPath, httpPort) + containerTreePipeline := containerTreePipeline(m, + buildPipeline, + commitPipeline, + t.platform, + repos, + packageSets[containerPkgsKey], + options, + customizations, + nginxConfigPath, + httpPort) + containerPipeline(m, buildPipeline, containerTreePipeline, t, nginxConfigPath, httpPort) return nil } @@ -216,7 +240,8 @@ func containerManifest(m *manifest.Manifest, if err != nil { return err } - manifest.NewOCIContainer(m, buildPipeline, &treePipeline.Base, t.Arch().Name(), t.Filename()) + ociPipeline := manifest.NewOCIContainer(m, buildPipeline, treePipeline) + ociPipeline.Filename = t.Filename() return nil } @@ -260,14 +285,14 @@ func osPipeline(m *manifest.Manifest, } if t.rpmOstree { - var parent *manifest.OSPipelineOSTreeParent + var parent *manifest.OSTreeParent if options.OSTree.Parent != "" && options.OSTree.URL != "" { - parent = &manifest.OSPipelineOSTreeParent{ + parent = &manifest.OSTreeParent{ Checksum: options.OSTree.Parent, URL: options.OSTree.URL, } } - pl.OSTree = &manifest.OSPipelineOSTree{ + pl.OSTree = &manifest.OSTree{ Parent: parent, } } @@ -359,13 +384,14 @@ func ostreeCommitPipeline(m *manifest.Manifest, func containerTreePipeline(m *manifest.Manifest, buildPipeline *manifest.Build, commitPipeline *manifest.OSTreeCommit, + platform platform.Platform, repos []rpmmd.RepoConfig, containerPackageSet rpmmd.PackageSet, options distro.ImageOptions, c *blueprint.Customizations, nginxConfigPath, listenPort string) *manifest.OSTreeCommitServer { - p := manifest.NewOSTreeCommitServer(m, buildPipeline, repos, commitPipeline, nginxConfigPath, listenPort) + p := manifest.NewOSTreeCommitServer(m, buildPipeline, platform, repos, commitPipeline, nginxConfigPath, listenPort) p.ExtraPackages = containerPackageSet.Include p.ExtraRepos = containerPackageSet.Repositories language, _ := c.GetPrimaryLocale() @@ -377,11 +403,12 @@ func containerTreePipeline(m *manifest.Manifest, func containerPipeline(m *manifest.Manifest, buildPipeline *manifest.Build, - treePipeline *manifest.Base, + treePipeline manifest.Tree, t *imageType, nginxConfigPath, listenPort string) *manifest.OCIContainer { - p := manifest.NewOCIContainer(m, buildPipeline, treePipeline, t.Arch().Name(), t.Filename()) + p := manifest.NewOCIContainer(m, buildPipeline, treePipeline) + p.Filename = t.Filename() p.Cmd = []string{"nginx", "-c", nginxConfigPath} p.ExposedPorts = []string{listenPort} return p @@ -389,17 +416,18 @@ func containerPipeline(m *manifest.Manifest, func anacondaTreePipeline(m *manifest.Manifest, buildPipeline *manifest.Build, + pf platform.Platform, repos []rpmmd.RepoConfig, installerPackageSet rpmmd.PackageSet, - arch, product, osVersion, variant string, + product, osVersion, variant string, users bool) *manifest.Anaconda { - p := manifest.NewAnaconda(m, buildPipeline, repos, "kernel", arch, product, osVersion) + p := manifest.NewAnaconda(m, buildPipeline, pf, repos, "kernel", product, osVersion) p.ExtraPackages = installerPackageSet.Include p.ExtraRepos = installerPackageSet.Repositories p.Users = users p.Variant = variant - p.Biosdevname = (arch == distro.X86_64ArchName) + p.Biosdevname = (pf.GetArch() == platform.ARCH_X86_64) return p } @@ -426,7 +454,8 @@ func bootISOPipeline(m *manifest.Manifest, treePipeline *manifest.ISOTree, filename string, isolinux bool) *manifest.ISO { - p := manifest.NewISO(m, buildPipeline, treePipeline, filename) + p := manifest.NewISO(m, buildPipeline, treePipeline) p.ISOLinux = isolinux + p.Filename = filename return p } diff --git a/internal/manifest/anaconda.go b/internal/manifest/anaconda.go index 2ed8c0cd0..4cc8f5664 100644 --- a/internal/manifest/anaconda.go +++ b/internal/manifest/anaconda.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/osbuild/osbuild-composer/internal/osbuild2" + "github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) @@ -29,11 +30,11 @@ type Anaconda struct { // Variant is the variant of the product being installed, if applicable. Variant string + platform platform.Platform repos []rpmmd.RepoConfig packageSpecs []rpmmd.PackageSpec kernelName string kernelVer string - arch string product string version string } @@ -46,16 +47,16 @@ type Anaconda struct { // installer for. func NewAnaconda(m *Manifest, buildPipeline *Build, + platform platform.Platform, repos []rpmmd.RepoConfig, kernelName, - arch, product, version string) *Anaconda { p := &Anaconda{ Base: NewBase(m, "anaconda-tree", buildPipeline), + platform: platform, repos: repos, kernelName: kernelName, - arch: arch, product: product, version: version, } @@ -74,9 +75,8 @@ func (p *Anaconda) anacondaBootPackageSet() []string { "efibootmgr", } - // TODO: use constants for architectures - switch p.arch { - case "x86_64": + switch p.platform.GetArch() { + case platform.ARCH_X86_64: packages = append(packages, "grub2-efi-x64", "grub2-efi-x64-cdboot", @@ -86,14 +86,14 @@ func (p *Anaconda) anacondaBootPackageSet() []string { "syslinux", "syslinux-nonlinux", ) - case "aarch64": + case platform.ARCH_AARCH64: packages = append(packages, "grub2-efi-aa64-cdboot", "grub2-efi-aa64", "shim-aa64", ) default: - panic(fmt.Sprintf("unsupported arch: %s", p.arch)) + panic(fmt.Sprintf("unsupported arch: %s", p.platform.GetArch())) } return packages @@ -148,7 +148,7 @@ func (p *Anaconda) serialize() osbuild2.Pipeline { pipeline.AddStage(osbuild2.NewRPMStage(osbuild2.NewRPMStageOptions(p.repos), osbuild2.NewRpmStageSourceFilesInputs(p.packageSpecs))) pipeline.AddStage(osbuild2.NewBuildstampStage(&osbuild2.BuildstampStageOptions{ - Arch: p.arch, + Arch: p.platform.GetArch().String(), Product: p.product, Variant: p.Variant, Version: p.version, @@ -184,7 +184,7 @@ func (p *Anaconda) serialize() osbuild2.Pipeline { pipeline.AddStage(osbuild2.NewAnacondaStage(osbuild2.NewAnacondaStageOptions(p.Users))) pipeline.AddStage(osbuild2.NewLoraxScriptStage(&osbuild2.LoraxScriptStageOptions{ Path: "99-generic/runtime-postinstall.tmpl", - BaseArch: p.arch, + BaseArch: p.platform.GetArch().String(), })) pipeline.AddStage(osbuild2.NewDracutStage(dracutStageOptions(p.kernelVer, p.Biosdevname, []string{ "anaconda", @@ -255,3 +255,7 @@ func dracutStageOptions(kernelVer string, biosdevname bool, additionalModules [] Install: []string{"/.buildstamp"}, } } + +func (p *Anaconda) GetPlatform() platform.Platform { + return p.platform +} diff --git a/internal/manifest/commit_server_tree.go b/internal/manifest/commit_server_tree.go index 0a235b405..fa9045197 100644 --- a/internal/manifest/commit_server_tree.go +++ b/internal/manifest/commit_server_tree.go @@ -5,6 +5,7 @@ import ( "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/osbuild2" + "github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) @@ -20,6 +21,7 @@ type OSTreeCommitServer struct { // TODO: should this be configurable? Language string + platform platform.Platform repos []rpmmd.RepoConfig packageSpecs []rpmmd.PackageSpec commitPipeline *OSTreeCommit @@ -34,12 +36,14 @@ type OSTreeCommitServer struct { // nginx will be listening on. func NewOSTreeCommitServer(m *Manifest, buildPipeline *Build, + platform platform.Platform, repos []rpmmd.RepoConfig, commitPipeline *OSTreeCommit, nginxConfigPath, listenPort string) *OSTreeCommitServer { p := &OSTreeCommitServer{ Base: NewBase(m, "container-tree", buildPipeline), + platform: platform, repos: repos, commitPipeline: commitPipeline, nginxConfigPath: nginxConfigPath, @@ -139,3 +143,7 @@ func chmodStageOptions(path, mode string, recursive bool) *osbuild2.ChmodStageOp }, } } + +func (p *OSTreeCommitServer) GetPlatform() platform.Platform { + return p.platform +} diff --git a/internal/manifest/iso.go b/internal/manifest/iso.go index ec19704b1..a05138a86 100644 --- a/internal/manifest/iso.go +++ b/internal/manifest/iso.go @@ -9,19 +9,18 @@ import ( type ISO struct { Base ISOLinux bool + Filename string treePipeline *ISOTree - filename string } func NewISO(m *Manifest, buildPipeline *Build, - treePipeline *ISOTree, - filename string) *ISO { + treePipeline *ISOTree) *ISO { p := &ISO{ Base: NewBase(m, "bootiso", buildPipeline), treePipeline: treePipeline, - filename: filename, + Filename: "image.iso", } buildPipeline.addDependent(p) if treePipeline.Base.manifest != m { @@ -41,8 +40,8 @@ func (p *ISO) getBuildPackages() []string { func (p *ISO) serialize() osbuild2.Pipeline { pipeline := p.Base.serialize() - pipeline.AddStage(osbuild2.NewXorrisofsStage(xorrisofsStageOptions(p.filename, p.treePipeline.isoLabel, p.ISOLinux), osbuild2.NewXorrisofsStagePipelineTreeInputs(p.treePipeline.Name()))) - pipeline.AddStage(osbuild2.NewImplantisomd5Stage(&osbuild2.Implantisomd5StageOptions{Filename: p.filename})) + pipeline.AddStage(osbuild2.NewXorrisofsStage(xorrisofsStageOptions(p.Filename, p.treePipeline.isoLabel, p.ISOLinux), osbuild2.NewXorrisofsStagePipelineTreeInputs(p.treePipeline.Name()))) + pipeline.AddStage(osbuild2.NewImplantisomd5Stage(&osbuild2.Implantisomd5StageOptions{Filename: p.Filename})) return pipeline } diff --git a/internal/manifest/iso_tree.go b/internal/manifest/iso_tree.go index 32ac36984..cdb2d9e23 100644 --- a/internal/manifest/iso_tree.go +++ b/internal/manifest/iso_tree.go @@ -36,7 +36,7 @@ func NewISOTree(m *Manifest, osTreeRef, isoLabelTmpl string) *ISOTree { // TODO: replace isoLabelTmpl with more high-level properties - isoLabel := fmt.Sprintf(isoLabelTmpl, anacondaPipeline.arch) + isoLabel := fmt.Sprintf(isoLabelTmpl, anacondaPipeline.platform.GetArch()) p := &ISOTree{ Base: NewBase(m, "bootiso-tree", buildPipeline), @@ -77,7 +77,14 @@ func (p *ISOTree) serialize() osbuild2.Pipeline { kspath := "/osbuild.ks" ostreeRepoPath := "/ostree/repo" - pipeline.AddStage(osbuild2.NewBootISOMonoStage(bootISOMonoStageOptions(p.anacondaPipeline.kernelVer, p.anacondaPipeline.arch, p.UEFIVendor, p.anacondaPipeline.product, p.anacondaPipeline.version, p.isoLabel, kspath), osbuild2.NewBootISOMonoStagePipelineTreeInputs(p.anacondaPipeline.Name()))) + pipeline.AddStage(osbuild2.NewBootISOMonoStage(bootISOMonoStageOptions(p.anacondaPipeline.kernelVer, + p.anacondaPipeline.platform.GetArch().String(), + p.UEFIVendor, + p.anacondaPipeline.product, + p.anacondaPipeline.version, + p.isoLabel, + kspath), + osbuild2.NewBootISOMonoStagePipelineTreeInputs(p.anacondaPipeline.Name()))) kickstartOptions, err := osbuild2.NewKickstartStageOptions(kspath, "", p.Users, p.Groups, makeISORootPath(ostreeRepoPath), p.osTreeRef, p.OSName) if err != nil { @@ -86,7 +93,7 @@ func (p *ISOTree) serialize() osbuild2.Pipeline { pipeline.AddStage(osbuild2.NewKickstartStage(kickstartOptions)) pipeline.AddStage(osbuild2.NewDiscinfoStage(&osbuild2.DiscinfoStageOptions{ - BaseArch: p.anacondaPipeline.arch, + BaseArch: p.anacondaPipeline.platform.GetArch().String(), Release: p.Release, })) diff --git a/internal/manifest/oci_container.go b/internal/manifest/oci_container.go index 76e4e175b..bcd46fe39 100644 --- a/internal/manifest/oci_container.go +++ b/internal/manifest/oci_container.go @@ -8,26 +8,22 @@ import ( // tree created by another Pipeline. type OCIContainer struct { Base + Filename string Cmd []string ExposedPorts []string - treePipeline *Base - architecture string - filename string + treePipeline Tree } func NewOCIContainer(m *Manifest, buildPipeline *Build, - treePipeline *Base, - architecture, - filename string) *OCIContainer { + treePipeline Tree) *OCIContainer { p := &OCIContainer{ Base: NewBase(m, "container", buildPipeline), treePipeline: treePipeline, - architecture: architecture, - filename: filename, + Filename: "oci-archive.tar", } - if treePipeline.build.Base.manifest != m { + if treePipeline.GetManifest() != m { panic("tree pipeline from different manifest") } buildPipeline.addDependent(p) @@ -39,8 +35,8 @@ func (p *OCIContainer) serialize() osbuild2.Pipeline { pipeline := p.Base.serialize() options := &osbuild2.OCIArchiveStageOptions{ - Architecture: p.architecture, - Filename: p.filename, + Architecture: p.treePipeline.GetPlatform().GetArch().String(), + Filename: p.Filename, Config: &osbuild2.OCIArchiveConfig{ Cmd: p.Cmd, ExposedPorts: p.ExposedPorts, diff --git a/internal/manifest/os.go b/internal/manifest/os.go index 374da7d4b..b759c5f12 100644 --- a/internal/manifest/os.go +++ b/internal/manifest/os.go @@ -15,11 +15,11 @@ import ( "github.com/osbuild/osbuild-composer/internal/workload" ) -type OSPipelineOSTree struct { - Parent *OSPipelineOSTreeParent +type OSTree struct { + Parent *OSTreeParent } -type OSPipelineOSTreeParent struct { +type OSTreeParent struct { Checksum string URL string } @@ -43,7 +43,7 @@ type OS struct { // Workload to install on top of the base system Workload workload.Workload // OSTree configuration, if nil the tree cannot be in an OSTree commit - OSTree *OSPipelineOSTree + OSTree *OSTree // Partition table, if nil the tree cannot be put on a partioned disk PartitionTable *disk.PartitionTable // KernelName indicates that a kernel is installed, and names the kernel @@ -471,3 +471,7 @@ func usersFirstBootOptions(usersStageOptions *osbuild2.UsersStageOptions) *osbui return options } + +func (p *OS) GetPlatform() platform.Platform { + return p.platform +} diff --git a/internal/manifest/pipeline.go b/internal/manifest/pipeline.go index 244f59152..09a1e9256 100644 --- a/internal/manifest/pipeline.go +++ b/internal/manifest/pipeline.go @@ -8,6 +8,7 @@ package manifest import ( "github.com/osbuild/osbuild-composer/internal/osbuild2" + "github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) @@ -38,6 +39,10 @@ func (p Base) Name() string { return p.name } +func (p Base) GetManifest() *Manifest { + return p.manifest +} + func (p Base) getBuildPackages() []string { return []string{} } @@ -102,3 +107,9 @@ func (p Base) serialize() osbuild2.Pipeline { } return pipeline } + +type Tree interface { + Name() string + GetManifest() *Manifest + GetPlatform() platform.Platform +} diff --git a/internal/manifest/qcow2.go b/internal/manifest/qcow2.go index 2df7dcd46..8ac0f2eb2 100644 --- a/internal/manifest/qcow2.go +++ b/internal/manifest/qcow2.go @@ -7,10 +7,10 @@ import ( // A QCOW2 turns a raw image file into qcow2 image. type QCOW2 struct { Base - Compat string + Filename string + Compat string imgPipeline *RawImage - filename string } // NewQCOW2 createsa new QCOW2 pipeline. imgPipeline is the pipeline producing the @@ -18,12 +18,11 @@ type QCOW2 struct { // of the produced qcow2 image. func NewQCOW2(m *Manifest, buildPipeline *Build, - imgPipeline *RawImage, - filename string) *QCOW2 { + imgPipeline *RawImage) *QCOW2 { p := &QCOW2{ Base: NewBase(m, "qcow2", buildPipeline), imgPipeline: imgPipeline, - filename: filename, + Filename: "image.qcow2", } if imgPipeline.Base.manifest != m { panic("live image pipeline from different manifest") @@ -37,12 +36,12 @@ func (p *QCOW2) serialize() osbuild2.Pipeline { pipeline := p.Base.serialize() pipeline.AddStage(osbuild2.NewQEMUStage( - osbuild2.NewQEMUStageOptions(p.filename, + osbuild2.NewQEMUStageOptions(p.Filename, osbuild2.QEMUFormatQCOW2, osbuild2.QCOW2Options{ Compat: p.Compat, }), - osbuild2.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.filename), + osbuild2.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.Filename), )) return pipeline diff --git a/internal/manifest/raw.go b/internal/manifest/raw.go index 9afa090e4..f8a99177d 100644 --- a/internal/manifest/raw.go +++ b/internal/manifest/raw.go @@ -10,18 +10,16 @@ import ( type RawImage struct { Base treePipeline *OS - - filename string + Filename string } func NewRawImage(m *Manifest, buildPipeline *Build, - treePipeline *OS, - filename string) *RawImage { + treePipeline *OS) *RawImage { p := &RawImage{ Base: NewBase(m, "image", buildPipeline), treePipeline: treePipeline, - filename: filename, + Filename: "disk.img", } buildPipeline.addDependent(p) if treePipeline.Base.manifest != m { @@ -43,26 +41,26 @@ func (p *RawImage) serialize() osbuild2.Pipeline { panic("no partition table in live image") } - for _, stage := range osbuild2.GenImagePrepareStages(pt, p.filename, osbuild2.PTSfdisk) { + for _, stage := range osbuild2.GenImagePrepareStages(pt, p.Filename, osbuild2.PTSfdisk) { pipeline.AddStage(stage) } inputName := "root-tree" - copyOptions, copyDevices, copyMounts := osbuild2.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.filename, pt) + copyOptions, copyDevices, copyMounts := osbuild2.GenCopyFSTreeOptions(inputName, p.treePipeline.Name(), p.Filename, pt) copyInputs := osbuild2.NewCopyStagePipelineTreeInputs(inputName, p.treePipeline.Name()) pipeline.AddStage(osbuild2.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts)) - for _, stage := range osbuild2.GenImageFinishStages(pt, p.filename) { + for _, stage := range osbuild2.GenImageFinishStages(pt, p.Filename) { pipeline.AddStage(stage) } switch p.treePipeline.platform.GetArch() { case platform.ARCH_S390X: - 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, pt), loopback, copyDevices, copyMounts)) default: if grubLegacy := p.treePipeline.platform.GetBIOSPlatform(); grubLegacy != "" { - pipeline.AddStage(osbuild2.NewGrub2InstStage(osbuild2.NewGrub2InstStageOption(p.filename, pt, grubLegacy))) + pipeline.AddStage(osbuild2.NewGrub2InstStage(osbuild2.NewGrub2InstStageOption(p.Filename, pt, grubLegacy))) } } diff --git a/internal/manifest/tar.go b/internal/manifest/tar.go index d27e9e19a..eae9edae5 100644 --- a/internal/manifest/tar.go +++ b/internal/manifest/tar.go @@ -7,8 +7,9 @@ import ( // A Tar represents the contents of another pipeline in a tar file type Tar struct { Base + Filename string + inputPipeline *Base - filename string } // NewTar creates a new TarPipeline. The inputPipeline represents the @@ -17,12 +18,11 @@ type Tar struct { func NewTar(m *Manifest, buildPipeline *Build, inputPipeline *Base, - pipelinename, - filename string) *Tar { + pipelinename string) *Tar { p := &Tar{ Base: NewBase(m, pipelinename, buildPipeline), inputPipeline: inputPipeline, - filename: filename, + Filename: "image.tar", } if inputPipeline.manifest != m { panic("tree pipeline from different manifest") @@ -39,7 +39,7 @@ func (p *Tar) serialize() osbuild2.Pipeline { tree.Type = "org.osbuild.tree" tree.Origin = "org.osbuild.pipeline" tree.References = []string{"name:" + p.inputPipeline.Name()} - tarStage := osbuild2.NewTarStage(&osbuild2.TarStageOptions{Filename: p.filename}, &osbuild2.TarStageInputs{Tree: tree}) + tarStage := osbuild2.NewTarStage(&osbuild2.TarStageOptions{Filename: p.Filename}, &osbuild2.TarStageInputs{Tree: tree}) pipeline.AddStage(tarStage) diff --git a/internal/manifest/vmdk.go b/internal/manifest/vmdk.go index 98be3274b..94981fa68 100644 --- a/internal/manifest/vmdk.go +++ b/internal/manifest/vmdk.go @@ -7,21 +7,20 @@ import ( // A VMDK turns a raw image file into vmdk image. type VMDK struct { Base + Filename string imgPipeline *RawImage - filename string } // NewVMDK creates a new VMDK pipeline. imgPipeline is the pipeline producing the // raw image. Filename is the name of the produced image. func NewVMDK(m *Manifest, buildPipeline *Build, - imgPipeline *RawImage, - filename string) *VMDK { + imgPipeline *RawImage) *VMDK { p := &VMDK{ Base: NewBase(m, "vmdk", buildPipeline), imgPipeline: imgPipeline, - filename: filename, + Filename: "image.vmdk", } if imgPipeline.Base.manifest != m { panic("live image pipeline from different manifest") @@ -35,10 +34,10 @@ func (p *VMDK) serialize() osbuild2.Pipeline { pipeline := p.Base.serialize() pipeline.AddStage(osbuild2.NewQEMUStage( - osbuild2.NewQEMUStageOptions(p.filename, osbuild2.QEMUFormatVMDK, osbuild2.VMDKOptions{ + osbuild2.NewQEMUStageOptions(p.Filename, osbuild2.QEMUFormatVMDK, osbuild2.VMDKOptions{ Subformat: osbuild2.VMDKSubformatStreamOptimized, }), - osbuild2.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.filename), + osbuild2.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.Filename), )) return pipeline diff --git a/internal/manifest/vpc.go b/internal/manifest/vpc.go index 1d4b34633..7ecc4027e 100644 --- a/internal/manifest/vpc.go +++ b/internal/manifest/vpc.go @@ -7,9 +7,9 @@ import ( // A VPC turns a raw image file into qemu-based image format, such as qcow2. type VPC struct { Base + Filename string imgPipeline *RawImage - filename string } // NewVPC createsa new Qemu pipeline. imgPipeline is the pipeline producing the @@ -17,12 +17,11 @@ type VPC struct { // of the produced image. func NewVPC(m *Manifest, buildPipeline *Build, - imgPipeline *RawImage, - filename string) *VPC { + imgPipeline *RawImage) *VPC { p := &VPC{ Base: NewBase(m, "vpc", buildPipeline), imgPipeline: imgPipeline, - filename: filename, + Filename: "image.vpc", } if imgPipeline.Base.manifest != m { panic("live image pipeline from different manifest") @@ -36,8 +35,8 @@ func (p *VPC) serialize() osbuild2.Pipeline { pipeline := p.Base.serialize() pipeline.AddStage(osbuild2.NewQEMUStage( - osbuild2.NewQEMUStageOptions(p.filename, osbuild2.QEMUFormatVPC, nil), - osbuild2.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.filename), + osbuild2.NewQEMUStageOptions(p.Filename, osbuild2.QEMUFormatVPC, nil), + osbuild2.NewQemuStagePipelineFilesInputs(p.imgPipeline.Name(), p.imgPipeline.Filename), )) return pipeline