diff --git a/internal/distro/rhel90/distro.go b/internal/distro/rhel90/distro.go index b9d8da6d5..4073563cd 100644 --- a/internal/distro/rhel90/distro.go +++ b/internal/distro/rhel90/distro.go @@ -16,33 +16,15 @@ import ( "github.com/osbuild/osbuild-composer/internal/rpmmd" ) -const defaultName = "rhel-90-ga" -const osVersion = "9.0" -const releaseVersion = "9" -const modulePlatformID = "platform:el9" -const ostreeRef = "rhel/9/%s/edge" - const ( // package set names // build package set name buildPkgsKey = "build" - // Legacy bootable image package set name - bootLegacyPkgsKey = "boot.legacy" - - // UEFI bootable image package set name - bootUEFIPkgsKey = "boot.uefi" - // main/common os image package set name osPkgsKey = "packages" - // edge os image package set name - edgePkgsKey = "edge" - - // edge build package set name - edgeBuildPkgsKey = "build.edge" - // container package set name containerPkgsKey = "container" @@ -59,10 +41,41 @@ var mountpointAllowList = []string{ type distribution struct { name string + product string + osVersion string + releaseVersion string modulePlatformID string - ostreeRef string + vendor string + ostreeRefTmpl string + isolabelTmpl string + runner string arches map[string]distro.Arch - packageSets map[string]rpmmd.PackageSet +} + +// distribution objects without the arches > image types +var distroMap = map[string]distribution{ + "rhel-90-ga": { + name: "rhel-90-ga", + product: "Red Hat Enterprise Linux", + osVersion: "9.0", + releaseVersion: "9", + modulePlatformID: "platform:el9", + vendor: "redhat", + ostreeRefTmpl: "rhel/9/%s/edge", + isolabelTmpl: "RHEL-9-0-0-BaseOS-%s", + runner: "org.osbuild.rhel90", + }, + "centos-9": { + name: "centos-9", + product: "CentOS Stream", + osVersion: "9-stream", + releaseVersion: "9", + modulePlatformID: "platform:el9", + vendor: "centos", + ostreeRefTmpl: "centos/9/%s/edge", + isolabelTmpl: "CentOS-Stream-9-%s-dvd", + runner: "org.osbuild.centos9", + }, } func (d *distribution) Name() string { @@ -70,7 +83,7 @@ func (d *distribution) Name() string { } func (d *distribution) Releasever() string { - return releaseVersion + return d.releaseVersion } func (d *distribution) ModulePlatformID() string { @@ -78,7 +91,7 @@ func (d *distribution) ModulePlatformID() string { } func (d *distribution) OSTreeRef() string { - return d.ostreeRef + return d.ostreeRefTmpl } func (d *distribution) ListArches() []string { @@ -111,12 +124,15 @@ func (d *distribution) addArches(arches ...architecture) { } } +func (d *distribution) isRHEL() bool { + return strings.HasPrefix(d.name, "rhel") +} + type architecture struct { distro *distribution name string imageTypes map[string]distro.ImageType imageTypeAliases map[string]string - packageSets map[string]rpmmd.PackageSet legacy string bootType distro.BootType } @@ -175,13 +191,15 @@ func (a *architecture) Distro() distro.Distro { type pipelinesFunc func(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) +type packageSetFunc func(t *imageType) rpmmd.PackageSet + type imageType struct { arch *architecture name string nameAliases []string filename string mimeType string - packageSets map[string]rpmmd.PackageSet + packageSets map[string]packageSetFunc enabledServices []string disabledServices []string defaultTarget string @@ -219,8 +237,9 @@ func (t *imageType) MIMEType() string { } func (t *imageType) OSTreeRef() string { + d := t.arch.distro if t.rpmOstree { - return fmt.Sprintf(ostreeRef, t.arch.name) + return fmt.Sprintf(d.ostreeRefTmpl, t.arch.name) } return "" } @@ -237,16 +256,24 @@ func (t *imageType) Size(size uint64) uint64 { return size } +func (t *imageType) getPackages(name string) rpmmd.PackageSet { + getter := t.packageSets[name] + if getter == nil { + return rpmmd.PackageSet{} + } + + return getter(t) +} + func (t *imageType) PackageSets(bp blueprint.Blueprint) map[string]rpmmd.PackageSet { // merge package sets that appear in the image type with the package sets // of the same name from the distro and arch mergedSets := make(map[string]rpmmd.PackageSet) imageSets := t.packageSets - archSets := t.arch.packageSets - distroSets := t.arch.distro.packageSets + for name := range imageSets { - mergedSets[name] = imageSets[name].Append(archSets[name]).Append(distroSets[name]) + mergedSets[name] = t.getPackages(name) } if _, hasPackages := imageSets[osPkgsKey]; !hasPackages { @@ -254,40 +281,9 @@ func (t *imageType) PackageSets(bp blueprint.Blueprint) map[string]rpmmd.Package mergedSets[osPkgsKey] = rpmmd.PackageSet{} } - // build is usually not defined on the image type - // handle it explicitly when it's not + // every image type must define a 'build' package set if _, hasBuild := imageSets[buildPkgsKey]; !hasBuild { - mergedSets[buildPkgsKey] = archSets[buildPkgsKey].Append(distroSets[buildPkgsKey]) - } - - // package sets from flags - if t.bootable { - var addLegacyBootPkg bool - var addUEFIBootPkg bool - - switch bt := t.getBootType(); bt { - case distro.LegacyBootType: - addLegacyBootPkg = true - case distro.UEFIBootType: - addUEFIBootPkg = true - case distro.HybridBootType: - addLegacyBootPkg = true - addUEFIBootPkg = true - default: - panic(fmt.Sprintf("unsupported boot type: %q", bt)) - } - - if addLegacyBootPkg { - mergedSets[osPkgsKey] = mergedSets[osPkgsKey].Append(archSets[bootLegacyPkgsKey]).Append(distroSets[bootLegacyPkgsKey]) - } - if addUEFIBootPkg { - mergedSets[osPkgsKey] = mergedSets[osPkgsKey].Append(archSets[bootUEFIPkgsKey]).Append(distroSets[bootUEFIPkgsKey]) - } - } - if t.rpmOstree { - // add ostree sets - mergedSets[buildPkgsKey] = mergedSets[buildPkgsKey].Append(archSets[edgeBuildPkgsKey]).Append(distroSets[edgeBuildPkgsKey]) - mergedSets[osPkgsKey] = mergedSets[osPkgsKey].Append(archSets[edgePkgsKey]).Append(distroSets[edgePkgsKey]) + panic(fmt.Sprintf("'%s' image type has no '%s' package set defined", t.name, buildPkgsKey)) } // blueprint packages @@ -380,7 +376,7 @@ func (t *imageType) Manifest(customizations *blueprint.Customizations, } var commits []ostreeCommit - if t.bootISO && options.OSTree.Parent != "" && options.OSTree.URL != "" { + if options.OSTree.Parent != "" && options.OSTree.URL != "" { commits = []ostreeCommit{{Checksum: options.OSTree.Parent, URL: options.OSTree.URL}} } return json.Marshal( @@ -450,11 +446,20 @@ func (t *imageType) checkOptions(customizations *blueprint.Customizations, optio if options.OSTree.Parent == "" { return fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.name) } - if customizations != nil { + + if t.name == "edge-simplified-installer" { + if err := customizations.CheckAllowed("InstallationDevice"); err != nil { + return fmt.Errorf("boot ISO image type %q contains unsupported blueprint customizations: %v", t.name, err) + } + } else if customizations != nil { return fmt.Errorf("boot ISO image type %q does not support blueprint customizations", t.name) } } + if t.name == "edge-raw-image" && options.OSTree.Parent == "" { + return fmt.Errorf("edge raw images require specifying a URL from which to retrieve the OSTree commit") + } + if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.rpmOstree { return fmt.Errorf("kernel boot parameter customizations are not supported for ostree types") } @@ -484,75 +489,55 @@ func (t *imageType) checkOptions(customizations *blueprint.Customizations, optio // New creates a new distro object, defining the supported architectures and image types func New() distro.Distro { - return newDistro(defaultName, modulePlatformID, ostreeRef) + return newDistro("rhel-90-ga") } func NewHostDistro(name, modulePlatformID, ostreeRef string) distro.Distro { - return newDistro(name, modulePlatformID, ostreeRef) + return newDistro("rhel-90-ga") } -func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { +func NewCentos() distro.Distro { + return newDistro("centos-9") +} + +func NewCentosHostDistro(name, modulePlatformID, ostreeRef string) distro.Distro { + return newDistro("centos-9") +} + +func newDistro(distroName string) distro.Distro { const GigaByte = 1024 * 1024 * 1024 - rd := &distribution{ - name: name, - modulePlatformID: modulePlatformID, - ostreeRef: ostreeRef, - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: distroBuildPackageSet(), - edgeBuildPkgsKey: edgeBuildPackageSet(), - }, - } + rd := distroMap[distroName] // Architecture definitions x86_64 := architecture{ - name: distro.X86_64ArchName, - distro: rd, - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: x8664BuildPackageSet(), - bootLegacyPkgsKey: x8664LegacyBootPackageSet(), - bootUEFIPkgsKey: x8664UEFIBootPackageSet(), - edgePkgsKey: x8664EdgeCommitPackageSet(), - }, + name: distro.X86_64ArchName, + distro: &rd, legacy: "i386-pc", bootType: distro.HybridBootType, } aarch64 := architecture{ - name: distro.Aarch64ArchName, - distro: rd, - packageSets: map[string]rpmmd.PackageSet{ - bootUEFIPkgsKey: aarch64UEFIBootPackageSet(), - edgePkgsKey: aarch64EdgeCommitPackageSet(), - }, + name: distro.Aarch64ArchName, + distro: &rd, bootType: distro.UEFIBootType, } ppc64le := architecture{ - distro: rd, - name: distro.Ppc64leArchName, - packageSets: map[string]rpmmd.PackageSet{ - bootLegacyPkgsKey: ppc64leLegacyBootPackageSet(), - buildPkgsKey: ppc64leBuildPackageSet(), - }, + distro: &rd, + name: distro.Ppc64leArchName, legacy: "powerpc-ieee1275", bootType: distro.LegacyBootType, } s390x := architecture{ - distro: rd, - name: distro.S390xArchName, - packageSets: map[string]rpmmd.PackageSet{ - bootLegacyPkgsKey: s390xLegacyBootPackageSet(), - }, + distro: &rd, + name: distro.S390xArchName, bootType: distro.LegacyBootType, } // Shared Services edgeServices := []string{ "NetworkManager.service", "firewalld.service", "sshd.service", - "greenboot-grub2-set-counter", "greenboot-grub2-set-success", "greenboot-healthcheck", - "greenboot-rpm-ostree-grub2-check-fallback", "greenboot-status", "greenboot-task-runner", - "redboot-auto-reboot", "redboot-task-runner", } // Image Definitions @@ -561,24 +546,29 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { nameAliases: []string{"rhel-edge-commit"}, filename: "commit.tar", mimeType: "application/x-tar", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: edgeBuildPackageSet(), - osPkgsKey: edgeCommitPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: edgeBuildPackageSet, + osPkgsKey: edgeCommitPackageSet, }, enabledServices: edgeServices, rpmOstree: true, pipelines: edgeCommitPipelines, exports: []string{"commit-archive"}, } + edgeOCIImgType := imageType{ name: "edge-container", nameAliases: []string{"rhel-edge-container"}, filename: "container.tar", mimeType: "application/x-tar", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: edgeBuildPackageSet(), - osPkgsKey: edgeCommitPackageSet(), - containerPkgsKey: {Include: []string{"httpd"}}, + packageSets: map[string]packageSetFunc{ + buildPkgsKey: edgeBuildPackageSet, + osPkgsKey: edgeCommitPackageSet, + containerPkgsKey: func(t *imageType) rpmmd.PackageSet { + return rpmmd.PackageSet{ + Include: []string{"nginx"}, + } + }, }, enabledServices: edgeServices, rpmOstree: true, @@ -586,12 +576,30 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { pipelines: edgeContainerPipelines, exports: []string{containerPkgsKey}, } + + edgeRawImgType := imageType{ + name: "edge-raw-image", + nameAliases: []string{"rhel-edge-raw-image"}, + filename: "image.raw.xz", + mimeType: "application/xz", + packageSets: map[string]packageSetFunc{ + buildPkgsKey: edgeRawImageBuildPackageSet, + }, + defaultSize: 10 * GigaByte, + rpmOstree: true, + bootable: true, + bootISO: false, + pipelines: edgeRawImagePipelines, + exports: []string{"archive"}, + basePartitionTables: edgeBasePartitionTables, + } + edgeInstallerImgType := imageType{ name: "edge-installer", nameAliases: []string{"rhel-edge-installer"}, filename: "installer.iso", mimeType: "application/x-iso9660-image", - packageSets: map[string]rpmmd.PackageSet{ + packageSets: map[string]packageSetFunc{ // TODO: non-arch-specific package set handling for installers // This image type requires build packages for installers and // ostree/edge. For now we only have x86-64 installer build @@ -599,9 +607,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { // for other architectures, this will need to be moved to the // architecture and the merging will happen in the PackageSets() // method like the other sets. - buildPkgsKey: x8664InstallerBuildPackageSet().Append(edgeBuildPackageSet()), - osPkgsKey: edgeCommitPackageSet(), - installerPkgsKey: edgeInstallerPackageSet(), + buildPkgsKey: edgeInstallerBuildPackageSet, + osPkgsKey: edgeCommitPackageSet, + installerPkgsKey: edgeInstallerPackageSet, }, enabledServices: edgeServices, rpmOstree: true, @@ -610,14 +618,41 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { exports: []string{"bootiso"}, } + edgeSimplifiedInstallerImgType := imageType{ + name: "edge-simplified-installer", + nameAliases: []string{"rhel-edge-simplified-installer"}, + filename: "simplified-installer.iso", + mimeType: "application/x-iso9660-image", + packageSets: map[string]packageSetFunc{ + // TODO: non-arch-specific package set handling for installers + // This image type requires build packages for installers and + // ostree/edge. For now we only have x86-64 installer build + // package sets defined. When we add installer build package sets + // for other architectures, this will need to be moved to the + // architecture and the merging will happen in the PackageSets() + // method like the other sets. + buildPkgsKey: edgeInstallerBuildPackageSet, + installerPkgsKey: edgeSimplifiedInstallerPackageSet, + }, + enabledServices: edgeServices, + defaultSize: 10 * GigaByte, + rpmOstree: true, + bootable: true, + bootISO: true, + pipelines: edgeSimplifiedInstallerPipelines, + exports: []string{"bootiso"}, + basePartitionTables: edgeBasePartitionTables, + } + qcow2ImgType := imageType{ name: "qcow2", filename: "disk.qcow2", mimeType: "application/x-qemu-disk", defaultTarget: "multi-user.target", kernelOptions: "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto", - packageSets: map[string]rpmmd.PackageSet{ - osPkgsKey: qcow2CommonPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: distroBuildPackageSet, + osPkgsKey: qcow2CommonPackageSet, }, bootable: true, defaultSize: 10 * GigaByte, @@ -630,8 +665,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "vhd", filename: "disk.vhd", mimeType: "application/x-vhd", - packageSets: map[string]rpmmd.PackageSet{ - osPkgsKey: vhdCommonPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: distroBuildPackageSet, + osPkgsKey: vhdCommonPackageSet, }, enabledServices: []string{ "sshd", @@ -650,8 +686,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "vmdk", filename: "disk.vmdk", mimeType: "application/x-vmdk", - packageSets: map[string]rpmmd.PackageSet{ - osPkgsKey: vmdkCommonPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: distroBuildPackageSet, + osPkgsKey: vmdkCommonPackageSet, }, kernelOptions: "ro net.ifnames=0", bootable: true, @@ -665,8 +702,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "openstack", filename: "disk.qcow2", mimeType: "application/x-qemu-disk", - packageSets: map[string]rpmmd.PackageSet{ - osPkgsKey: openstackCommonPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: distroBuildPackageSet, + osPkgsKey: openstackCommonPackageSet, }, kernelOptions: "ro net.ifnames=0", bootable: true, @@ -693,9 +731,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "ami", filename: "image.raw", mimeType: "application/octet-stream", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: ec2BuildPackageSet(), - osPkgsKey: ec2CommonPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: ec2BuildPackageSet, + osPkgsKey: ec2CommonPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, @@ -712,9 +750,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "ami", filename: "image.raw", mimeType: "application/octet-stream", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: ec2BuildPackageSet(), - osPkgsKey: ec2CommonPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: ec2BuildPackageSet, + osPkgsKey: ec2CommonPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, @@ -730,9 +768,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "ec2", filename: "image.raw.xz", mimeType: "application/xz", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: ec2BuildPackageSet(), - osPkgsKey: rhelEc2PackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: ec2BuildPackageSet, + osPkgsKey: rhelEc2PackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, @@ -749,9 +787,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "ec2", filename: "image.raw.xz", mimeType: "application/xz", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: ec2BuildPackageSet(), - osPkgsKey: rhelEc2PackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: ec2BuildPackageSet, + osPkgsKey: rhelEc2PackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, @@ -767,9 +805,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "ec2-ha", filename: "image.raw.xz", mimeType: "application/xz", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: ec2BuildPackageSet(), - osPkgsKey: rhelEc2HaPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: ec2BuildPackageSet, + osPkgsKey: rhelEc2HaPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, @@ -786,9 +824,9 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "ec2-sap", filename: "image.raw.xz", mimeType: "application/xz", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: ec2BuildPackageSet(), - osPkgsKey: rhelEc2SapPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: ec2BuildPackageSet, + osPkgsKey: rhelEc2SapPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, @@ -805,10 +843,13 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "tar", filename: "root.tar.xz", mimeType: "application/x-tar", - packageSets: map[string]rpmmd.PackageSet{ - osPkgsKey: { - Include: []string{"policycoreutils", "selinux-policy-targeted"}, - Exclude: []string{"rng-tools"}, + packageSets: map[string]packageSetFunc{ + buildPkgsKey: distroBuildPackageSet, + osPkgsKey: func(t *imageType) rpmmd.PackageSet { + return rpmmd.PackageSet{ + Include: []string{"policycoreutils", "selinux-policy-targeted"}, + Exclude: []string{"rng-tools"}, + } }, }, pipelines: tarPipelines, @@ -818,10 +859,10 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { name: "image-installer", filename: "installer.iso", mimeType: "application/x-iso9660-image", - packageSets: map[string]rpmmd.PackageSet{ - buildPkgsKey: x8664InstallerBuildPackageSet(), - osPkgsKey: bareMetalPackageSet(), - installerPkgsKey: installerPackageSet(), + packageSets: map[string]packageSetFunc{ + buildPkgsKey: anacondaBuildPackageSet, + osPkgsKey: bareMetalPackageSet, + installerPkgsKey: anacondaPackageSet, }, rpmOstree: false, bootISO: true, @@ -830,11 +871,19 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { exports: []string{"bootiso"}, } - x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, ec2SapImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType) - aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, ec2ImgTypeAarch64, tarImgType, edgeCommitImgType, edgeOCIImgType) + x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType) + aarch64.addImageTypes(qcow2ImgType, openstackImgType, amiImgTypeAarch64, tarImgType, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType, edgeRawImgType, edgeSimplifiedInstallerImgType) ppc64le.addImageTypes(qcow2ImgType, tarImgType) s390x.addImageTypes(qcow2ImgType, tarImgType) - rd.addArches(x86_64, aarch64, ppc64le, s390x) - return rd + if rd.isRHEL() { + // add ec2 image types to RHEL distro only + x86_64.addImageTypes(ec2ImgTypeX86_64, ec2HaImgTypeX86_64, ec2SapImgTypeX86_64) + aarch64.addImageTypes(ec2ImgTypeAarch64) + + // add s390x to RHEL distro only + rd.addArches(s390x) + } + rd.addArches(x86_64, aarch64, ppc64le) + return &rd } diff --git a/internal/distro/rhel90/package_sets.go b/internal/distro/rhel90/package_sets.go index 7290e4100..15093c456 100644 --- a/internal/distro/rhel90/package_sets.go +++ b/internal/distro/rhel90/package_sets.go @@ -2,13 +2,18 @@ package rhel90 // This file defines package sets that are used by more than one image type. -import "github.com/osbuild/osbuild-composer/internal/rpmmd" +import ( + "fmt" + + "github.com/osbuild/osbuild-composer/internal/distro" + "github.com/osbuild/osbuild-composer/internal/rpmmd" +) // BUILD PACKAGE SETS // distro-wide build package set -func distroBuildPackageSet() rpmmd.PackageSet { - return rpmmd.PackageSet{ +func distroBuildPackageSet(t *imageType) rpmmd.PackageSet { + ps := rpmmd.PackageSet{ Include: []string{ "dnf", "dosfstools", "e2fsprogs", "glibc", "lorax-templates-generic", "lorax-templates-rhel", "policycoreutils", @@ -16,70 +21,210 @@ func distroBuildPackageSet() rpmmd.PackageSet { "tar", "xfsprogs", "xz", }, } + + switch t.arch.Name() { + + case distro.X86_64ArchName: + ps = ps.Append(x8664BuildPackageSet(t)) + + case distro.Ppc64leArchName: + ps = ps.Append(ppc64leBuildPackageSet(t)) + } + + return ps } // x86_64 build package set -func x8664BuildPackageSet() rpmmd.PackageSet { +func x8664BuildPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{"grub2-pc"}, } } // ppc64le build package set -func ppc64leBuildPackageSet() rpmmd.PackageSet { +func ppc64leBuildPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{"grub2-ppc64le", "grub2-ppc64le-modules"}, } } // common ec2 image build package set -func ec2BuildPackageSet() rpmmd.PackageSet { - return rpmmd.PackageSet{ - Include: []string{"python3-pyyaml"}, - } +func ec2BuildPackageSet(t *imageType) rpmmd.PackageSet { + return distroBuildPackageSet(t).Append( + rpmmd.PackageSet{ + Include: []string{"python3-pyyaml"}, + }) } // common edge image build package set -func edgeBuildPackageSet() rpmmd.PackageSet { - return rpmmd.PackageSet{ - Include: []string{"rpm-ostree"}, - Exclude: nil, - } +func edgeBuildPackageSet(t *imageType) rpmmd.PackageSet { + return distroBuildPackageSet(t).Append( + rpmmd.PackageSet{ + Include: []string{"rpm-ostree"}, + Exclude: nil, + }) } -// x86_64 installer ISO build package set -// TODO: separate into common installer and arch specific sets -func x8664InstallerBuildPackageSet() rpmmd.PackageSet { - return rpmmd.PackageSet{ +func edgeRawImageBuildPackageSet(t *imageType) rpmmd.PackageSet { + return edgeBuildPackageSet(t).Append( + bootPackageSet(t), + ) +} + +// installer boot package sets, needed for booting and +// also in the build host + +func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet { + ps := rpmmd.PackageSet{} + + grubCommon := rpmmd.PackageSet{ Include: []string{ - "efibootmgr", "grub2-efi-ia32-cdboot", - "grub2-efi-x64", "grub2-efi-x64-cdboot", "grub2-pc", - "grub2-pc-modules", "grub2-tools", "grub2-tools-efi", - "grub2-tools-extra", "grub2-tools-minimal", "isomd5sum", - "rpm-ostree", "shim-ia32", "shim-x64", "squashfs-tools", - "syslinux", "syslinux-nonlinux", "xorriso", + "grub2-tools", + "grub2-tools-extra", + "grub2-tools-minimal", }, } + + efiCommon := rpmmd.PackageSet{ + Include: []string{ + "efibootmgr", + }, + } + + switch t.arch.Name() { + case distro.X86_64ArchName: + ps = ps.Append(grubCommon) + ps = ps.Append(efiCommon) + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "grub2-efi-ia32-cdboot", + "grub2-efi-x64", + "grub2-efi-x64-cdboot", + "grub2-pc", + "grub2-pc-modules", + "shim-ia32", + "shim-x64", + "syslinux", + "syslinux-nonlinux", + }, + }) + case distro.Aarch64ArchName: + ps = ps.Append(grubCommon) + ps = ps.Append(efiCommon) + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "grub2-efi-aa64-cdboot", + "grub2-efi-aa64", + "shim-aa64", + }, + }) + + default: + panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name())) + } + + return ps +} + +func installerBuildPackageSet(t *imageType) rpmmd.PackageSet { + return distroBuildPackageSet(t).Append( + rpmmd.PackageSet{ + Include: []string{ + "isomd5sum", + "xorriso", + }, + }) +} + +func anacondaBuildPackageSet(t *imageType) rpmmd.PackageSet { + ps := rpmmd.PackageSet{ + Include: []string{ + "squashfs-tools", + }, + } + + ps = ps.Append(installerBuildPackageSet(t)) + ps = ps.Append(anacondaBootPackageSet(t)) + + return ps +} + +func edgeInstallerBuildPackageSet(t *imageType) rpmmd.PackageSet { + return anacondaBuildPackageSet(t).Append( + edgeBuildPackageSet(t), + ) } // BOOT PACKAGE SETS +func bootPackageSet(t *imageType) rpmmd.PackageSet { + if !t.bootable { + return rpmmd.PackageSet{} + } + + var addLegacyBootPkg bool + var addUEFIBootPkg bool + + switch bt := t.getBootType(); bt { + case distro.LegacyBootType: + addLegacyBootPkg = true + case distro.UEFIBootType: + addUEFIBootPkg = true + case distro.HybridBootType: + addLegacyBootPkg = true + addUEFIBootPkg = true + default: + panic(fmt.Sprintf("unsupported boot type: %q", bt)) + } + + ps := rpmmd.PackageSet{} + + switch t.arch.Name() { + case distro.X86_64ArchName: + if addLegacyBootPkg { + ps = ps.Append(x8664LegacyBootPackageSet(t)) + } + if addUEFIBootPkg { + ps = ps.Append(x8664UEFIBootPackageSet(t)) + } + + case distro.Aarch64ArchName: + ps = ps.Append(aarch64UEFIBootPackageSet(t)) + + case distro.Ppc64leArchName: + ps = ps.Append(ppc64leLegacyBootPackageSet(t)) + + case distro.S390xArchName: + ps = ps.Append(s390xLegacyBootPackageSet(t)) + + default: + panic(fmt.Sprintf("unsupported boot arch: %s", t.arch.Name())) + } + + return ps +} + // x86_64 Legacy arch-specific boot package set -func x8664LegacyBootPackageSet() rpmmd.PackageSet { +func x8664LegacyBootPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{"dracut-config-generic", "grub2-pc"}, } } // x86_64 UEFI arch-specific boot package set -func x8664UEFIBootPackageSet() rpmmd.PackageSet { +func x8664UEFIBootPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ - Include: []string{"dracut-config-generic", "grub2-efi-x64", "shim-x64"}, + Include: []string{ + "dracut-config-generic", + "efibootmgr", + "grub2-efi-x64", + "shim-x64", + }, } } // aarch64 UEFI arch-specific boot package set -func aarch64UEFIBootPackageSet() rpmmd.PackageSet { +func aarch64UEFIBootPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ "dracut-config-generic", "efibootmgr", "grub2-efi-aa64", @@ -89,7 +234,7 @@ func aarch64UEFIBootPackageSet() rpmmd.PackageSet { } // ppc64le Legacy arch-specific boot package set -func ppc64leLegacyBootPackageSet() rpmmd.PackageSet { +func ppc64leLegacyBootPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ "dracut-config-generic", "powerpc-utils", "grub2-ppc64le", @@ -99,7 +244,7 @@ func ppc64leLegacyBootPackageSet() rpmmd.PackageSet { } // s390x Legacy arch-specific boot package set -func s390xLegacyBootPackageSet() rpmmd.PackageSet { +func s390xLegacyBootPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{"dracut-config-generic", "s390utils-base"}, } @@ -107,14 +252,14 @@ func s390xLegacyBootPackageSet() rpmmd.PackageSet { // OS package sets -func qcow2CommonPackageSet() rpmmd.PackageSet { +func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ "@core", "authselect-compat", "chrony", "cloud-init", "cloud-utils-growpart", "cockpit-system", "cockpit-ws", "dnf", "dnf-utils", "dosfstools", - "insights-client", "NetworkManager", "nfs-utils", - "oddjob", "oddjob-mkhomedir", "psmisc", "python3-jsonschema", + "NetworkManager", "nfs-utils", "oddjob", + "oddjob-mkhomedir", "psmisc", "python3-jsonschema", "qemu-guest-agent", "redhat-release", "redhat-release-eula", "rsync", "subscription-manager-cockpit", "tar", "tcpdump", "yum", }, @@ -126,17 +271,17 @@ func qcow2CommonPackageSet() rpmmd.PackageSet { "iwl100-firmware", "iwl1000-firmware", "iwl105-firmware", "iwl135-firmware", "iwl2000-firmware", "iwl2030-firmware", "iwl3160-firmware", "iwl3945-firmware", "iwl4965-firmware", - "iwl5000-firmware", "iwl5150-firmware", "iwl6000-firmware", + "iwl5000-firmware", "iwl5150-firmware", "iwl6000g2a-firmware", "iwl6000g2b-firmware", "iwl6050-firmware", "iwl7260-firmware", "langpacks-*", "langpacks-en", "langpacks-en", "libertas-sd8686-firmware", "libertas-sd8787-firmware", "libertas-usb8388-firmware", "nss", "plymouth", "rng-tools", "udisks2", }, - } + }.Append(bootPackageSet(t)).Append(distroSpecificPackageSet(t)) } -func vhdCommonPackageSet() rpmmd.PackageSet { +func vhdCommonPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ // Defaults @@ -152,10 +297,10 @@ func vhdCommonPackageSet() rpmmd.PackageSet { Exclude: []string{ "dracut-config-rescue", "rng-tools", }, - } + }.Append(bootPackageSet(t)) } -func vmdkCommonPackageSet() rpmmd.PackageSet { +func vmdkCommonPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ "@core", "chrony", "firewalld", "langpacks-en", "open-vm-tools", @@ -164,11 +309,11 @@ func vmdkCommonPackageSet() rpmmd.PackageSet { Exclude: []string{ "dracut-config-rescue", "rng-tools", }, - } + }.Append(bootPackageSet(t)) } -func openstackCommonPackageSet() rpmmd.PackageSet { +func openstackCommonPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ // Defaults @@ -181,18 +326,19 @@ func openstackCommonPackageSet() rpmmd.PackageSet { Exclude: []string{ "dracut-config-rescue", "rng-tools", }, - } + }.Append(bootPackageSet(t)) } -func ec2CommonPackageSet() rpmmd.PackageSet { +func ec2CommonPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ - "@core", "authselect-compat", "chrony", "cloud-init", "cloud-utils-growpart", - "dhcp-client", "yum-utils", "dracut-config-generic", "gdisk", - "grub2", "insights-client", "langpacks-en", "NetworkManager", - "NetworkManager-cloud-setup", "redhat-release", - "redhat-release-eula", "rsync", "tar", "qemu-guest-agent", + "@core", "authselect-compat", "chrony", "cloud-init", + "cloud-utils-growpart", "dhcp-client", "yum-utils", + "dracut-config-generic", "gdisk", "grub2", + "langpacks-en", "NetworkManager", "NetworkManager-cloud-setup", + "redhat-release", "redhat-release-eula", "rsync", "tar", + "qemu-guest-agent", }, Exclude: []string{ "aic94xx-firmware", "alsa-firmware", @@ -200,26 +346,26 @@ func ec2CommonPackageSet() rpmmd.PackageSet { "iwl1000-firmware", "iwl100-firmware", "iwl105-firmware", "iwl135-firmware", "iwl2000-firmware", "iwl2030-firmware", "iwl3160-firmware", "iwl3945-firmware", "iwl4965-firmware", - "iwl5000-firmware", "iwl5150-firmware", "iwl6000-firmware", + "iwl5000-firmware", "iwl5150-firmware", "iwl6000g2a-firmware", "iwl6000g2b-firmware", "iwl6050-firmware", "iwl7260-firmware", "libertas-sd8686-firmware", "libertas-sd8787-firmware", "libertas-usb8388-firmware", "plymouth", }, - } + }.Append(bootPackageSet(t)).Append(distroSpecificPackageSet(t)) } // rhel-ec2 image package set -func rhelEc2PackageSet() rpmmd.PackageSet { - ec2PackageSet := ec2CommonPackageSet() +func rhelEc2PackageSet(t *imageType) rpmmd.PackageSet { + ec2PackageSet := ec2CommonPackageSet(t) ec2PackageSet.Include = append(ec2PackageSet.Include, "rh-amazon-rhui-client") ec2PackageSet.Exclude = append(ec2PackageSet.Exclude, "alsa-lib") return ec2PackageSet } // rhel-ha-ec2 image package set -func rhelEc2HaPackageSet() rpmmd.PackageSet { - ec2HaPackageSet := ec2CommonPackageSet() +func rhelEc2HaPackageSet(t *imageType) rpmmd.PackageSet { + ec2HaPackageSet := ec2CommonPackageSet(t) ec2HaPackageSet.Include = append(ec2HaPackageSet.Include, "fence-agents-all", "pacemaker", @@ -231,8 +377,8 @@ func rhelEc2HaPackageSet() rpmmd.PackageSet { } // rhel-sap-ec2 image package set -func rhelEc2SapPackageSet() rpmmd.PackageSet { - ec2SapPackageSet := ec2CommonPackageSet() +func rhelEc2SapPackageSet(t *imageType) rpmmd.PackageSet { + ec2SapPackageSet := ec2CommonPackageSet(t) ec2SapPackageSet.Include = append(ec2SapPackageSet.Include, // SAP System Roles // https://access.redhat.com/sites/default/files/attachments/rhel_system_roles_for_sap_1.pdf @@ -240,7 +386,7 @@ func rhelEc2SapPackageSet() rpmmd.PackageSet { "rhel-system-roles-sap", // RHBZ#1959813 "bind-utils", - //"compat-sap-c++-9", // not needed on RHEL-9 + "compat-sap-c++-9", "nfs-utils", "tcsh", // RHBZ#1959955 @@ -256,7 +402,6 @@ func rhelEc2SapPackageSet() rpmmd.PackageSet { "libatomic", "libcanberra-gtk2", "libicu", - //"libpng12", // not needed on RHEL-9 "libtool-ltdl", "lm_sensors", "net-tools", @@ -274,8 +419,8 @@ func rhelEc2SapPackageSet() rpmmd.PackageSet { } // edge commit OS package set -func edgeCommitPackageSet() rpmmd.PackageSet { - return rpmmd.PackageSet{ +func edgeCommitPackageSet(t *imageType) rpmmd.PackageSet { + ps := rpmmd.PackageSet{ Include: []string{ "redhat-release", "glibc", "glibc-minimal-langpack", "nss-altfiles", "dracut-config-generic", "dracut-network", @@ -289,7 +434,7 @@ func edgeCommitPackageSet() rpmmd.PackageSet { "hostname", "iproute", "iputils", "openssh-clients", "procps-ng", "rootfiles", "openssh-server", "passwd", "policycoreutils", "policycoreutils-python-utils", "selinux-policy-targeted", - "setools-console", "less", "tar", "rsync", "fwupd", "usbguard", + "setools-console", "less", "tar", "rsync", "usbguard", "bash-completion", "tmux", "ima-evm-utils", "audit", "podman", "container-selinux", "skopeo", "criu", "slirp4netns", "fuse-overlayfs", "clevis", "clevis-dracut", "clevis-luks", @@ -298,9 +443,22 @@ func edgeCommitPackageSet() rpmmd.PackageSet { }, Exclude: []string{"rng-tools"}, } + + ps = ps.Append(bootPackageSet(t)) + + switch t.arch.Name() { + case distro.X86_64ArchName: + ps = ps.Append(x8664EdgeCommitPackageSet(t)) + + case distro.Aarch64ArchName: + ps = ps.Append(aarch64EdgeCommitPackageSet(t)) + } + + return ps + } -func x8664EdgeCommitPackageSet() rpmmd.PackageSet { +func x8664EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ "grub2", "grub2-efi-x64", "efibootmgr", "shim-x64", @@ -314,138 +472,227 @@ func x8664EdgeCommitPackageSet() rpmmd.PackageSet { } } -func aarch64EdgeCommitPackageSet() rpmmd.PackageSet { +func aarch64EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{"grub2-efi-aa64", "efibootmgr", "shim-aa64", "iwl7260-firmware"}, Exclude: nil, } } -// INSTALLER PACKAGE SET -func installerPackageSet() rpmmd.PackageSet { - // TODO: simplify - return rpmmd.PackageSet{ - Include: []string{ - "aajohan-comfortaa-fonts", "abattis-cantarell-fonts", - "alsa-firmware", "alsa-tools-firmware", "anaconda", - "anaconda-dracut", "anaconda-install-env-deps", "anaconda-widgets", - "audit", "bind-utils", "biosdevname", "bitmap-fangsongti-fonts", - "bzip2", "cryptsetup", "curl", "dbus-x11", "dejavu-sans-fonts", - "dejavu-sans-mono-fonts", "device-mapper-persistent-data", - "dmidecode", "dnf", "dracut-config-generic", "dracut-network", - /*"dump",*/ "efibootmgr", "ethtool", "ftp", "gdb-gdbserver", "gdisk", - /*"gfs2-utils",*/ "glibc-all-langpacks", "gnome-kiosk", - "google-noto-sans-cjk-ttc-fonts", "grub2-efi-ia32-cdboot", - "grub2-efi-x64-cdboot", "grub2-tools", "grub2-tools-efi", - "grub2-tools-extra", "grub2-tools-minimal", "grubby", - "gsettings-desktop-schemas", "hdparm", "hexedit", "hostname", - "initscripts", "ipmitool", "iwl1000-firmware", "iwl100-firmware", - "iwl105-firmware", "iwl135-firmware", "iwl2000-firmware", - "iwl2030-firmware", "iwl3160-firmware", /*"iwl3945-firmware",*/ - /*"iwl4965-firmware",*/ "iwl5000-firmware", "iwl5150-firmware", - /*"iwl6000-firmware",*/ "iwl6000g2a-firmware", "iwl6000g2b-firmware", - "iwl6050-firmware", "iwl7260-firmware", "jomolhari-fonts", - "kacst-farsi-fonts", "kacst-qurn-fonts", "kbd", "kbd-misc", - "kdump-anaconda-addon", "kernel", "khmeros-base-fonts", "less", - "libblockdev-lvm-dbus", /*"libertas-sd8686-firmware",*/ - /*"libertas-sd8787-firmware",*/ /*"libertas-usb8388-firmware",*/ - /*"libertas-usb8388-olpc-firmware",*/ "libibverbs", - "libreport-plugin-bugzilla", "libreport-plugin-reportuploader", - /*"libreport-rhel-anaconda-bugzilla",*/ "librsvg2", "linux-firmware", - "lklug-fonts", "lohit-assamese-fonts", "lohit-bengali-fonts", - "lohit-devanagari-fonts", "lohit-gujarati-fonts", - "lohit-gurmukhi-fonts", "lohit-kannada-fonts", "lohit-odia-fonts", - "lohit-tamil-fonts", "lohit-telugu-fonts", "lsof", "madan-fonts", - "memtest86+" /*"metacity",*/, "mtr", "mt-st", "net-tools", "nfs-utils", - "nmap-ncat", "nm-connection-editor", "nss-tools", - "openssh-clients", "openssh-server", "oscap-anaconda-addon", - "ostree", "pciutils", "perl-interpreter", "pigz", "plymouth", - "prefixdevname", "python3-pyatspi", "rdma-core", - "redhat-release-eula", "rng-tools", "rpcbind", "rpm-ostree", - "rsync", "rsyslog", "selinux-policy-targeted", "sg3_utils", - "shim-ia32", "shim-x64", "sil-abyssinica-fonts", - "sil-padauk-fonts", "sil-scheherazade-fonts", "smartmontools", - "smc-meera-fonts", "spice-vdagent", "strace", "syslinux", - "systemd" /*"system-storage-manager",*/, "tar", - "thai-scalable-waree-fonts", "tigervnc-server-minimal", - "tigervnc-server-module", "udisks2", "udisks2-iscsi", "usbutils", - "vim-minimal", "volume_key", "wget", "xfsdump", "xfsprogs", - "xorg-x11-drivers", "xorg-x11-fonts-misc", "xorg-x11-server-utils", - "xorg-x11-server-Xorg", "xorg-x11-xauth", "xz", - }, - } -} - -func edgeInstallerPackageSet() rpmmd.PackageSet { - return rpmmd.PackageSet{ - Include: []string{ - "aajohan-comfortaa-fonts", "abattis-cantarell-fonts", - "alsa-firmware", "alsa-tools-firmware", "anaconda", - "anaconda-dracut", "anaconda-install-env-deps", "anaconda-widgets", - "audit", "bind-utils", "biosdevname", "bitmap-fangsongti-fonts", - "bzip2", "cryptsetup", "curl", "dbus-x11", "dejavu-sans-fonts", - "dejavu-sans-mono-fonts", "device-mapper-persistent-data", - "dmidecode", "dnf", "dracut-config-generic", "dracut-network", - /*"dump",*/ "efibootmgr", "ethtool", "ftp", "gdb-gdbserver", "gdisk", - /*"gfs2-utils",*/ "glibc-all-langpacks", "gnome-kiosk", - "google-noto-sans-cjk-ttc-fonts", "grub2-efi-ia32-cdboot", - "grub2-efi-x64-cdboot", "grub2-tools", "grub2-tools-efi", - "grub2-tools-extra", "grub2-tools-minimal", "grubby", - "gsettings-desktop-schemas", "hdparm", "hexedit", "hostname", - "initscripts", "ipmitool", "iwl1000-firmware", "iwl100-firmware", - "iwl105-firmware", "iwl135-firmware", "iwl2000-firmware", - "iwl2030-firmware", "iwl3160-firmware", /*"iwl3945-firmware",*/ - /*"iwl4965-firmware",*/ "iwl5000-firmware", "iwl5150-firmware", - "iwl6000g2a-firmware", "iwl6000g2b-firmware", - "iwl6050-firmware", "iwl7260-firmware", "jomolhari-fonts", - "kacst-farsi-fonts", "kacst-qurn-fonts", "kbd", "kbd-misc", - "kdump-anaconda-addon", "kernel", "khmeros-base-fonts", "less", - "libblockdev-lvm-dbus", /*"libertas-sd8686-firmware",*/ - /*"libertas-sd8787-firmware",*/ /*"libertas-usb8388-firmware",*/ - /*"libertas-usb8388-olpc-firmware",*/ "libibverbs", - "libreport-plugin-bugzilla", "libreport-plugin-reportuploader", - /*"libreport-rhel-anaconda-bugzilla",*/ "librsvg2", "linux-firmware", - "lklug-fonts", "lohit-assamese-fonts", "lohit-bengali-fonts", - "lohit-devanagari-fonts", "lohit-gujarati-fonts", - "lohit-gurmukhi-fonts", "lohit-kannada-fonts", "lohit-odia-fonts", - "lohit-tamil-fonts", "lohit-telugu-fonts", "lsof", "madan-fonts", - "memtest86+" /*"metacity",*/, "mtr", "mt-st", "net-tools", "nfs-utils", - "nmap-ncat", "nm-connection-editor", "nss-tools", - "openssh-clients", "openssh-server", "oscap-anaconda-addon", - "ostree", "pciutils", "perl-interpreter", "pigz", "plymouth", - "prefixdevname", "python3-pyatspi", "rdma-core", - "redhat-release-eula", "rng-tools", "rpcbind", "rpm-ostree", - "rsync", "rsyslog", "selinux-policy-targeted", "sg3_utils", - "shim-ia32", "shim-x64", "sil-abyssinica-fonts", - "sil-padauk-fonts", "sil-scheherazade-fonts", "smartmontools", - "smc-meera-fonts", "spice-vdagent", "strace", "syslinux", - "systemd" /*"system-storage-manager",*/, "tar", - "thai-scalable-waree-fonts", "tigervnc-server-minimal", - "tigervnc-server-module", "udisks2", "udisks2-iscsi", "usbutils", - "vim-minimal", "volume_key", "wget", "xfsdump", "xfsprogs", - "xorg-x11-drivers", "xorg-x11-fonts-misc", "xorg-x11-server-utils", - "xorg-x11-server-Xorg", "xorg-x11-xauth", "xz", - }, - Exclude: nil, - } -} - -func bareMetalPackageSet() rpmmd.PackageSet { +func bareMetalPackageSet(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{ "authselect-compat", "chrony", "cockpit-system", "cockpit-ws", "@core", "dhcp-client", "dnf", "dnf-utils", "dosfstools", - "insights-client", "iwl1000-firmware", "iwl100-firmware", + "iwl1000-firmware", "iwl100-firmware", "iwl105-firmware", + "iwl135-firmware", "iwl2000-firmware", "iwl2030-firmware", + "iwl3160-firmware", "iwl3945-firmware", "iwl4965-firmware", + "iwl5000-firmware", "iwl5150-firmware", + "iwl6000g2a-firmware", "iwl6000g2b-firmware", "iwl6050-firmware", + "iwl7260-firmware", "lvm2", "net-tools", "NetworkManager", + "nfs-utils", "oddjob", "oddjob-mkhomedir", "policycoreutils", + "psmisc", "python3-jsonschema", "qemu-guest-agent", + "redhat-release", "redhat-release-eula", "rsync", + "selinux-policy-targeted", "subscription-manager-cockpit", "tar", + "tcpdump", "yum", + }, + Exclude: nil, + }.Append(bootPackageSet(t)).Append(distroBuildPackageSet(t)) +} + +// packages that are only in some (sub)-distributions +func distroSpecificPackageSet(t *imageType) rpmmd.PackageSet { + if t.arch.distro.isRHEL() { + return rpmmd.PackageSet{ + Include: []string{"insights-client"}, + } + } + return rpmmd.PackageSet{} +} + +// INSTALLER PACKAGE SET + +func installerPackageSet(t *imageType) rpmmd.PackageSet { + ps := rpmmd.PackageSet{ + Include: []string{ + "anaconda-dracut", + "curl", + "dracut-config-generic", + "dracut-network", + "hostname", + "iwl100-firmware", + "iwl1000-firmware", + "iwl105-firmware", + "iwl135-firmware", + "iwl2000-firmware", + "iwl2030-firmware", + "iwl3160-firmware", + "iwl5000-firmware", + "iwl5150-firmware", + "iwl6050-firmware", + "iwl7260-firmware", + "kernel", + "less", + "nfs-utils", + "openssh-clients", + "ostree", + "plymouth", + "prefixdevname", + "rng-tools", + "rpcbind", + "selinux-policy-targeted", + "systemd", + "tar", + "xfsprogs", + "xz", + }, + } + + switch t.arch.Name() { + case distro.X86_64ArchName: + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "biosdevname", + }, + }) + } + + return ps +} + +func anacondaPackageSet(t *imageType) rpmmd.PackageSet { + + // common installer packages + ps := installerPackageSet(t) + + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "aajohan-comfortaa-fonts", "abattis-cantarell-fonts", + "alsa-firmware", "alsa-tools-firmware", "anaconda", + "anaconda-dracut", "anaconda-install-env-deps", "anaconda-widgets", + "audit", "bind-utils", "biosdevname", "bitmap-fangsongti-fonts", + "bzip2", "cryptsetup", "curl", "dbus-x11", "dejavu-sans-fonts", + "dejavu-sans-mono-fonts", "device-mapper-persistent-data", + "dmidecode", "dnf", "dracut-config-generic", "dracut-network", + "efibootmgr", "ethtool", "ftp", "gdb-gdbserver", "gdisk", + "glibc-all-langpacks", "gnome-kiosk", + "google-noto-sans-cjk-ttc-fonts", "grub2-efi-ia32-cdboot", + "grub2-efi-x64-cdboot", "grub2-tools", "grub2-tools-efi", + "grub2-tools-extra", "grub2-tools-minimal", "grubby", + "gsettings-desktop-schemas", "hdparm", "hexedit", "hostname", + "initscripts", "ipmitool", "iwl1000-firmware", "iwl100-firmware", "iwl105-firmware", "iwl135-firmware", "iwl2000-firmware", "iwl2030-firmware", "iwl3160-firmware", "iwl5000-firmware", "iwl5150-firmware", "iwl6000g2a-firmware", "iwl6000g2b-firmware", - "iwl6050-firmware", "iwl7260-firmware", "lvm2", "net-tools", - "NetworkManager", "nfs-utils", "oddjob", "oddjob-mkhomedir", - "policycoreutils", "psmisc", "python3-jsonschema", - "qemu-guest-agent", "redhat-release", "redhat-release-eula", - "rsync", "selinux-policy-targeted", "subscription-manager-cockpit", - "tar", "tcpdump", "yum", + "iwl6050-firmware", "iwl7260-firmware", "jomolhari-fonts", + "kacst-farsi-fonts", "kacst-qurn-fonts", "kbd", "kbd-misc", + "kdump-anaconda-addon", "kernel", "khmeros-base-fonts", "less", + "libblockdev-lvm-dbus", "libibverbs", "libreport-plugin-bugzilla", + "libreport-plugin-reportuploader", "librsvg2", "linux-firmware", + "lklug-fonts", "lohit-assamese-fonts", "lohit-bengali-fonts", + "lohit-devanagari-fonts", "lohit-gujarati-fonts", + "lohit-gurmukhi-fonts", "lohit-kannada-fonts", "lohit-odia-fonts", + "lohit-tamil-fonts", "lohit-telugu-fonts", "lsof", "madan-fonts", + "memtest86+", "mtr", "mt-st", "net-tools", "nfs-utils", + "nmap-ncat", "nm-connection-editor", "nss-tools", + "openssh-clients", "openssh-server", "oscap-anaconda-addon", + "ostree", "pciutils", "perl-interpreter", "pigz", "plymouth", + "prefixdevname", "python3-pyatspi", "rdma-core", + "redhat-release-eula", "rng-tools", "rpcbind", "rpm-ostree", + "rsync", "rsyslog", "selinux-policy-targeted", "sg3_utils", + "shim-ia32", "shim-x64", "sil-abyssinica-fonts", + "sil-padauk-fonts", "sil-scheherazade-fonts", "smartmontools", + "smc-meera-fonts", "spice-vdagent", "strace", "syslinux", "systemd", + "tar", "thai-scalable-waree-fonts", "tigervnc-server-minimal", + "tigervnc-server-module", "udisks2", "udisks2-iscsi", "usbutils", + "vim-minimal", "volume_key", "wget", "xfsdump", "xfsprogs", + "xorg-x11-drivers", "xorg-x11-fonts-misc", "xorg-x11-server-utils", + "xorg-x11-server-Xorg", "xorg-x11-xauth", "xz", + }, + }) + + ps = ps.Append(anacondaBootPackageSet(t)) + + switch t.arch.Name() { + case distro.X86_64ArchName: + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "biosdevname", + "dmidecode", + "memtest86+", + }, + }) + + case distro.Aarch64ArchName: + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "dmidecode", + }, + }) + + default: + panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name())) + } + + return ps +} + +func edgeInstallerPackageSet(t *imageType) rpmmd.PackageSet { + return anacondaPackageSet(t) +} + +func edgeSimplifiedInstallerPackageSet(t *imageType) rpmmd.PackageSet { + // common installer packages + ps := installerPackageSet(t) + + ps = ps.Append(rpmmd.PackageSet{ + Include: []string{ + "attr", + "basesystem", + "binutils", + "bsdtar", + "cloud-utils-growpart", + "coreos-installer", + "coreos-installer-bootinfra", + "coreutils", + "device-mapper-multipath", + "dnsmasq", + "dosfstools", + "dracut-live", + "e2fsprogs", + "fcoe-utils", + "gzip", + "ima-evm-utils", + "iproute", + "iptables", + "iputils", + "iscsi-initiator-utils", + "keyutils", + "lldpad", + "lvm2", + "passwd", + "policycoreutils", + "policycoreutils-python-utils", + "procps-ng", + "rootfiles", + "setools-console", + "sudo", + "traceroute", + "util-linux", }, Exclude: nil, + }) + + switch t.arch.Name() { + + case distro.X86_64ArchName: + ps = ps.Append(x8664EdgeCommitPackageSet(t)) + case distro.Aarch64ArchName: + ps = ps.Append(aarch64EdgeCommitPackageSet(t)) + + default: + panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name())) } + + return ps } diff --git a/internal/distro/rhel90/partition_tables.go b/internal/distro/rhel90/partition_tables.go index 461a33846..e5010b94a 100644 --- a/internal/distro/rhel90/partition_tables.go +++ b/internal/distro/rhel90/partition_tables.go @@ -181,3 +181,101 @@ var ec2BasePartitionTables = distro.BasePartitionTableMap{ }, }, } +var edgeBasePartitionTables = distro.BasePartitionTableMap{ + distro.X86_64ArchName: disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: "gpt", + Partitions: []disk.Partition{ + { + Size: 2048, // 2MB + Bootable: true, + Type: disk.BIOSBootPartitionGUID, + UUID: disk.BIOSBootPartitionUUID, + }, + { + Size: 260096, // 127 MB + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Filesystem: &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: 786432, // 384 MB + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Filesystem: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + Label: "boot", + FSTabOptions: "defaults", + FSTabFreq: 1, + FSTabPassNo: 1, + }, + }, + { + Type: disk.FilesystemDataGUID, + UUID: disk.RootPartitionUUID, + Filesystem: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, + distro.Aarch64ArchName: disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: "gpt", + Partitions: []disk.Partition{ + { + Size: 260096, // 127 MB + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Filesystem: &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: 786432, // 384 MB + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Filesystem: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + Label: "boot", + FSTabOptions: "defaults", + FSTabFreq: 1, + FSTabPassNo: 1, + }, + }, + { + Type: disk.FilesystemDataGUID, + UUID: disk.RootPartitionUUID, + Filesystem: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, +} diff --git a/internal/distro/rhel90/pipelines.go b/internal/distro/rhel90/pipelines.go index ef775faa3..6c45eb2e3 100644 --- a/internal/distro/rhel90/pipelines.go +++ b/internal/distro/rhel90/pipelines.go @@ -3,20 +3,21 @@ package rhel90 import ( "fmt" "math/rand" + "path" + "path/filepath" "strings" "github.com/osbuild/osbuild-composer/internal/blueprint" "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/disk" "github.com/osbuild/osbuild-composer/internal/distro" - "github.com/osbuild/osbuild-composer/internal/osbuild2" osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := osPipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { @@ -43,9 +44,10 @@ func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, opti }, })) } + treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2())) kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name()) - treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer)) + treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer, false, false)) treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) pipelines = append(pipelines, *treePipeline) @@ -68,7 +70,7 @@ func prependKernelCmdlineStage(pipeline *osbuild.Pipeline, t *imageType, pt *dis func vhdPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := osPipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { return nil, err @@ -82,7 +84,7 @@ func vhdPipelines(t *imageType, customizations *blueprint.Customizations, option treePipeline = prependKernelCmdlineStage(treePipeline, t, &partitionTable) treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2())) kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name()) - treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer)) + treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer, false, false)) treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) pipelines = append(pipelines, *treePipeline) @@ -100,7 +102,7 @@ func vhdPipelines(t *imageType, customizations *blueprint.Customizations, option func vmdkPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := osPipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { return nil, err @@ -114,7 +116,7 @@ func vmdkPipelines(t *imageType, customizations *blueprint.Customizations, optio treePipeline = prependKernelCmdlineStage(treePipeline, t, &partitionTable) treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2())) kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name()) - treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer)) + treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer, false, false)) treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) pipelines = append(pipelines, *treePipeline) @@ -132,7 +134,7 @@ func vmdkPipelines(t *imageType, customizations *blueprint.Customizations, optio func openstackPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := osPipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { return nil, err @@ -142,10 +144,11 @@ func openstackPipelines(t *imageType, customizations *blueprint.Customizations, if err != nil { return nil, err } + treePipeline = prependKernelCmdlineStage(treePipeline, t, &partitionTable) treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2())) kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name()) - treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer)) + treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer, false, false)) treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) pipelines = append(pipelines, *treePipeline) @@ -171,9 +174,17 @@ func openstackPipelines(t *imageType, customizations *blueprint.Customizations, // Note: the caller of this function has to append the `osbuild.NewSELinuxStage(selinuxStageOptions(false))` stage // as the last one to the returned pipeline. The stage is not appended on purpose, to allow caller to append // any additional stages to the pipeline, but before the SELinuxStage, which must be always the last one. -func ec2BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, bpPackages []rpmmd.PackageSpec, - c *blueprint.Customizations, options distro.ImageOptions, enabledServices, disabledServices []string, - defaultTarget string, withRHUI bool, pt *disk.PartitionTable) (*osbuild.Pipeline, error) { +func ec2BaseTreePipeline( + repos []rpmmd.RepoConfig, + packages []rpmmd.PackageSpec, + bpPackages []rpmmd.PackageSpec, + c *blueprint.Customizations, + options distro.ImageOptions, + enabledServices, disabledServices []string, + defaultTarget string, + withRHUI, isRHEL bool, + pt *disk.PartitionTable) (*osbuild.Pipeline, error) { + p := new(osbuild.Pipeline) p.Name = "os" p.Build = "name:build" @@ -312,7 +323,7 @@ func ec2BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, }, })) - // RHBZ#1822853 + // RHBZ#1822863 p.AddStage(osbuild.NewSystemdUnitStage(&osbuild.SystemdUnitStageOptions{ Unit: "nm-cloud-setup.service", Dropin: "10-rh-enable-for-ec2.conf", @@ -327,42 +338,44 @@ func ec2BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, Profile: "sssd", })) - if options.Subscription != nil { - commands := []string{ - fmt.Sprintf("/usr/sbin/subscription-manager register --org=%s --activationkey=%s --serverurl %s --baseurl %s", options.Subscription.Organization, options.Subscription.ActivationKey, options.Subscription.ServerUrl, options.Subscription.BaseUrl), - } - if options.Subscription.Insights { - commands = append(commands, "/usr/bin/insights-client --register") - } - - p.AddStage(osbuild.NewFirstBootStage(&osbuild.FirstBootStageOptions{ - Commands: commands, - WaitForNetwork: true, - })) - } else { - // The EC2 images should keep the RHSM DNF plugins enabled (RHBZ#1996670) - rhsmStageOptions := &osbuild.RHSMStageOptions{ - // RHBZ#1932802 - SubMan: &osbuild.RHSMStageOptionsSubMan{ - Rhsmcertd: &osbuild.SubManConfigRHSMCERTDSection{ - AutoRegistration: common.BoolToPtr(true), - }, - }, - } - - // Disable RHSM redhat.repo management only if the image uses RHUI - // for content. Otherwise subscribing the system manually after booting - // it would result in empty redhat.repo. Without RHUI, such system - // would have no way to get Red Hat content, but enable the repo - // management manually, which would be very confusing. - // RHBZ#1932802 - if withRHUI { - rhsmStageOptions.SubMan.Rhsm = &osbuild.SubManConfigRHSMSection{ - ManageRepos: common.BoolToPtr(false), + if isRHEL { + if options.Subscription != nil { + commands := []string{ + fmt.Sprintf("/usr/sbin/subscription-manager register --org=%s --activationkey=%s --serverurl %s --baseurl %s", options.Subscription.Organization, options.Subscription.ActivationKey, options.Subscription.ServerUrl, options.Subscription.BaseUrl), + } + if options.Subscription.Insights { + commands = append(commands, "/usr/bin/insights-client --register") } - } - p.AddStage(osbuild.NewRHSMStage(rhsmStageOptions)) + p.AddStage(osbuild.NewFirstBootStage(&osbuild.FirstBootStageOptions{ + Commands: commands, + WaitForNetwork: true, + })) + } else { + // The EC2 images should keep the RHSM DNF plugins enabled (RHBZ#1996670) + rhsmStageOptions := &osbuild.RHSMStageOptions{ + // RHBZ#1932802 + SubMan: &osbuild.RHSMStageOptionsSubMan{ + Rhsmcertd: &osbuild.SubManConfigRHSMCERTDSection{ + AutoRegistration: common.BoolToPtr(true), + }, + }, + } + + // Disable RHSM redhat.repo management only if the image uses RHUI + // for content. Otherwise subscribing the system manually after booting + // it would result in empty redhat.repo. Without RHUI, such system + // would have no way to get Red Hat content, but enable the repo + // management manually, which would be very confusing. + // RHBZ#1932802 + if withRHUI { + rhsmStageOptions.SubMan.Rhsm = &osbuild.SubManConfigRHSMSection{ + ManageRepos: common.BoolToPtr(false), + } + } + + p.AddStage(osbuild.NewRHSMStage(rhsmStageOptions)) + } } return p, nil @@ -370,9 +383,9 @@ func ec2BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, func ec2X86_64BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, bpPackages []rpmmd.PackageSpec, c *blueprint.Customizations, options distro.ImageOptions, enabledServices, disabledServices []string, - defaultTarget string, withRHUI bool, pt *disk.PartitionTable) (*osbuild.Pipeline, error) { + defaultTarget string, withRHUI, isRHEL bool, pt *disk.PartitionTable) (*osbuild.Pipeline, error) { - treePipeline, err := ec2BaseTreePipeline(repos, packages, bpPackages, c, options, enabledServices, disabledServices, defaultTarget, withRHUI, pt) + treePipeline, err := ec2BaseTreePipeline(repos, packages, bpPackages, c, options, enabledServices, disabledServices, defaultTarget, withRHUI, isRHEL, pt) if err != nil { return nil, err } @@ -397,7 +410,7 @@ func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand, withRHUI bool, diskfile string) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) if err != nil { @@ -408,10 +421,10 @@ func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations, switch arch := t.arch.Name(); arch { // rhel-ec2-x86_64, rhel-ha-ec2 case distro.X86_64ArchName: - treePipeline, err = ec2X86_64BaseTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget, withRHUI, &partitionTable) + treePipeline, err = ec2X86_64BaseTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget, withRHUI, t.arch.distro.isRHEL(), &partitionTable) // rhel-ec2-aarch64 case distro.Aarch64ArchName: - treePipeline, err = ec2BaseTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget, withRHUI, &partitionTable) + treePipeline, err = ec2BaseTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget, withRHUI, t.arch.distro.isRHEL(), &partitionTable) default: return nil, fmt.Errorf("ec2CommonPipelines: unsupported image architecture: %q", arch) } @@ -422,7 +435,7 @@ func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations, treePipeline = prependKernelCmdlineStage(treePipeline, t, &partitionTable) treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2())) kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name()) - treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer)) + treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer, false, false)) // The last stage must be the SELinux stage treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) pipelines = append(pipelines, *treePipeline) @@ -436,7 +449,7 @@ func ec2SapPipelines(t *imageType, customizations *blueprint.Customizations, opt repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand, withRHUI bool, diskfile string) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) if err != nil { @@ -447,7 +460,7 @@ func ec2SapPipelines(t *imageType, customizations *blueprint.Customizations, opt switch arch := t.arch.Name(); arch { // rhel-sap-ec2 case distro.X86_64ArchName: - treePipeline, err = ec2X86_64BaseTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget, withRHUI, &partitionTable) + treePipeline, err = ec2X86_64BaseTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget, withRHUI, t.arch.distro.isRHEL(), &partitionTable) default: return nil, fmt.Errorf("ec2SapPipelines: unsupported image architecture: %q", arch) } @@ -554,7 +567,7 @@ func ec2SapPipelines(t *imageType, customizations *blueprint.Customizations, opt []osbuild.DNFVariable{ { Name: "releasever", - Value: "9.0", + Value: t.arch.distro.osVersion, }, }, ))) @@ -562,7 +575,7 @@ func ec2SapPipelines(t *imageType, customizations *blueprint.Customizations, opt treePipeline = prependKernelCmdlineStage(treePipeline, t, &partitionTable) treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2())) kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name()) - treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer)) + treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer, false, false)) // The last stage must be the SELinux stage treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) pipelines = append(pipelines, *treePipeline) @@ -609,7 +622,7 @@ func rhelEc2SapPipelines(t *imageType, customizations *blueprint.Customizations, func tarPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := osPipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { @@ -626,21 +639,33 @@ func tarPipelines(t *imageType, customizations *blueprint.Customizations, option return pipelines, nil } +//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) +} + func edgeInstallerPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) installerPackages := packageSetSpecs[installerPkgsKey] - kernelVer := kernelVerStr(installerPackages, "kernel", t.Arch().Name()) + d := t.arch.distro + archName := t.arch.name + kernelVer := kernelVerStr(installerPackages, "kernel", archName) ostreeRepoPath := "/ostree/repo" - pipelines = append(pipelines, *anacondaTreePipeline(repos, installerPackages, kernelVer, t.Arch().Name(), ostreePayloadStages(options, ostreeRepoPath))) - pipelines = append(pipelines, *bootISOTreePipeline(kernelVer, t.Arch().Name(), ostreeKickstartStageOptions(fmt.Sprintf("file://%s", ostreeRepoPath), options.OSTree.Ref))) - pipelines = append(pipelines, *bootISOPipeline(t.Filename(), t.Arch().Name())) + payloadStages := ostreePayloadStages(options, ostreeRepoPath) + kickstartOptions := ostreeKickstartStageOptions(makeISORootPath(ostreeRepoPath), options.OSTree.Ref) + pipelines = append(pipelines, *anacondaTreePipeline(repos, installerPackages, kernelVer, archName, d.product, d.osVersion, "edge")) + isolabel := fmt.Sprintf(d.isolabelTmpl, archName) + pipelines = append(pipelines, *bootISOTreePipeline(kernelVer, archName, d.vendor, d.product, d.osVersion, isolabel, kickstartOptions, payloadStages)) + pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, archName, false)) return pipelines, nil } func tarInstallerPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := osPipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { @@ -664,15 +689,19 @@ func tarInstallerPipelines(t *imageType, customizations *blueprint.Customization tarPath := "/liveimg.tar" tarPayloadStages := []*osbuild.Stage{tarStage("os", tarPath)} - pipelines = append(pipelines, *anacondaTreePipeline(repos, installerPackages, kernelVer, t.Arch().Name(), tarPayloadStages)) - pipelines = append(pipelines, *bootISOTreePipeline(kernelVer, t.Arch().Name(), tarKickstartStageOptions(fmt.Sprintf("file://%s", tarPath)))) - pipelines = append(pipelines, *bootISOPipeline(t.Filename(), t.Arch().Name())) + kickstartOptions := tarKickstartStageOptions(makeISORootPath(tarPath)) + archName := t.arch.name + d := t.arch.distro + pipelines = append(pipelines, *anacondaTreePipeline(repos, installerPackages, kernelVer, archName, d.product, d.osVersion, "BaseOS")) + isolabel := fmt.Sprintf(d.isolabelTmpl, archName) + pipelines = append(pipelines, *bootISOTreePipeline(kernelVer, archName, d.vendor, d.product, d.osVersion, isolabel, kickstartOptions, tarPayloadStages)) + pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, t.Arch().Name(), true)) return pipelines, nil } func edgeCorePipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec) ([]osbuild.Pipeline, error) { pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey])) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) treePipeline, err := ostreeTreePipeline(repos, packageSetSpecs[osPkgsKey], packageSetSpecs[blueprintPkgsKey], customizations, options, t.enabledServices, t.disabledServices, t.defaultTarget) if err != nil { @@ -680,7 +709,7 @@ func edgeCorePipelines(t *imageType, customizations *blueprint.Customizations, o } pipelines = append(pipelines, *treePipeline) - pipelines = append(pipelines, *ostreeCommitPipeline(options)) + pipelines = append(pipelines, *ostreeCommitPipeline(options, t.arch.distro.osVersion)) return pipelines, nil } @@ -704,15 +733,60 @@ func edgeContainerPipelines(t *imageType, customizations *blueprint.Customizatio if err != nil { return nil, err } - pipelines = append(pipelines, *containerTreePipeline(repos, packageSetSpecs[containerPkgsKey], options, customizations)) - pipelines = append(pipelines, *containerPipeline(t)) + + nginxConfigPath := "/etc/nginx.conf" + httpPort := "8080" + pipelines = append(pipelines, *containerTreePipeline(repos, packageSetSpecs[containerPkgsKey], options, customizations, nginxConfigPath, httpPort)) + pipelines = append(pipelines, *containerPipeline(t, nginxConfigPath, httpPort)) return pipelines, nil } -func buildPipeline(repos []rpmmd.RepoConfig, buildPackageSpecs []rpmmd.PackageSpec) *osbuild.Pipeline { +func edgeImagePipelines(t *imageType, filename string, options distro.ImageOptions, rng *rand.Rand) ([]osbuild.Pipeline, string, error) { + pipelines := make([]osbuild.Pipeline, 0) + ostreeRepoPath := "/ostree/repo" + imgName := "image.raw" + + partitionTable, err := t.getPartitionTable(nil, options, rng) + if err != nil { + return nil, "", err + } + + // prepare ostree deployment tree + treePipeline := ostreeDeployPipeline(t, &partitionTable, ostreeRepoPath, nil, "", rng, options) + pipelines = append(pipelines, *treePipeline) + + // make raw image from tree + imagePipeline := liveImagePipeline(treePipeline.Name, imgName, &partitionTable, t.arch, "") + pipelines = append(pipelines, *imagePipeline) + + // compress image + xzPipeline := xzArchivePipeline(imagePipeline.Name, imgName, filename) + pipelines = append(pipelines, *xzPipeline) + + return pipelines, xzPipeline.Name, nil +} + +func edgeRawImagePipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { + pipelines := make([]osbuild.Pipeline, 0) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) + + imgName := t.filename + + // create the raw image + imagePipelines, _, err := edgeImagePipelines(t, imgName, options, rng) + if err != nil { + return nil, err + } + + pipelines = append(pipelines, imagePipelines...) + + return pipelines, nil +} + +func buildPipeline(repos []rpmmd.RepoConfig, buildPackageSpecs []rpmmd.PackageSpec, runner string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "build" - p.Runner = "org.osbuild.rhel90" + p.Runner = runner p.AddStage(osbuild.NewRPMStage(rpmStageOptions(repos), rpmStageInputs(buildPackageSpecs))) p.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(true))) return p @@ -804,6 +878,11 @@ func ostreeTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, p.Build = "name:build" packages = append(packages, bpPackages...) + + if options.OSTree.Parent != "" && options.OSTree.URL != "" { + p.AddStage(osbuild.NewOSTreePasswdStage("org.osbuild.source", options.OSTree.Parent)) + } + p.AddStage(osbuild.NewRPMStage(rpmStageOptions(repos), rpmStageInputs(packages))) p.AddStage(osbuild.NewFixBLSStage(&osbuild.FixBLSStageOptions{})) language, keyboard := c.GetPrimaryLocale() @@ -887,7 +966,7 @@ func ostreeTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, })) return p, nil } -func ostreeCommitPipeline(options distro.ImageOptions) *osbuild.Pipeline { +func ostreeCommitPipeline(options distro.ImageOptions, osVersion string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "ostree-commit" p.Build = "name:build" @@ -917,7 +996,7 @@ func tarStage(source, filename string) *osbuild.Stage { return osbuild.NewTarStage(&osbuild.TarStageOptions{Filename: filename}, &osbuild.TarStageInputs{Tree: tree}) } -func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations) *osbuild.Pipeline { +func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations, nginxConfigPath, listenPort string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "container-tree" p.Build = "name:build" @@ -928,16 +1007,25 @@ func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpe } else { p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US"})) } - p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: "/var/www/html/repo"})) + + htmlRoot := "/usr/share/nginx/html" + repoPath := filepath.Join(htmlRoot, "repo") + p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: repoPath})) p.AddStage(osbuild.NewOSTreePullStage( - &osbuild.OSTreePullStageOptions{Repo: "/var/www/html/repo"}, + &osbuild.OSTreePullStageOptions{Repo: repoPath}, ostreePullStageInputs("org.osbuild.pipeline", "name:ostree-commit", options.OSTree.Ref), )) + + // make nginx log directory world writeable, otherwise nginx can't start in + // an unprivileged container + p.AddStage(osbuild.NewChmodStage(chmodStageOptions("/var/log/nginx", "o+w", true))) + + p.AddStage(osbuild.NewNginxConfigStage(nginxConfigStageOptions(nginxConfigPath, htmlRoot, listenPort))) return p } -func containerPipeline(t *imageType) *osbuild.Pipeline { +func containerPipeline(t *imageType, nginxConfigPath, listenPort string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "container" p.Build = "name:build" @@ -945,8 +1033,8 @@ func containerPipeline(t *imageType) *osbuild.Pipeline { Architecture: t.arch.Name(), Filename: t.Filename(), Config: &osbuild.OCIArchiveConfig{ - Cmd: []string{"httpd", "-D", "FOREGROUND"}, - ExposedPorts: []string{"80"}, + Cmd: []string{"nginx", "-c", nginxConfigPath}, + ExposedPorts: []string{listenPort}, }, } baseInput := new(osbuild.OCIArchiveStageInput) @@ -971,15 +1059,230 @@ func ostreePayloadStages(options distro.ImageOptions, ostreeRepoPath string) []* return stages } -func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, kernelVer string, arch string, payloadStages []*osbuild.Stage) *osbuild.Pipeline { +func edgeSimplifiedInstallerPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { + pipelines := make([]osbuild.Pipeline, 0) + pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner)) + installerPackages := packageSetSpecs[installerPkgsKey] + kernelVer := kernelVerStr(installerPackages, "kernel", t.Arch().Name()) + imgName := "disk.img.xz" + installDevice := customizations.GetInstallationDevice() + + // create the raw image + imagePipelines, imgPipelineName, err := edgeImagePipelines(t, imgName, options, rng) + if err != nil { + return nil, err + } + + pipelines = append(pipelines, imagePipelines...) + + // create boot ISO with raw image + d := t.arch.distro + archName := t.arch.name + installerTreePipeline := simplifiedInstallerTreePipeline(repos, installerPackages, kernelVer, archName, d.product, d.osVersion, "edge") + isolabel := fmt.Sprintf(d.isolabelTmpl, archName) + efibootTreePipeline := simplifiedInstallerEFIBootTreePipeline(installDevice, kernelVer, archName, d.vendor, d.product, d.osVersion, isolabel) + bootISOTreePipeline := simplifiedInstallerBootISOTreePipeline(imgPipelineName, kernelVer) + + pipelines = append(pipelines, *installerTreePipeline, *efibootTreePipeline, *bootISOTreePipeline) + pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, t.Arch().Name(), false)) + + return pipelines, nil +} + +func simplifiedInstallerBootISOTreePipeline(archivePipelineName, kver string) *osbuild.Pipeline { + p := new(osbuild.Pipeline) + p.Name = "bootiso-tree" + p.Build = "name:build" + + p.AddStage(osbuild.NewCopyStageSimple( + &osbuild.CopyStageOptions{ + Paths: []osbuild.CopyStagePath{ + { + From: "input://file/disk.img.xz", + To: "tree:///disk.img.xz", + }, + }, + }, + osbuild.NewFilesInputs(osbuild.NewFilesInputReferencesPipeline(archivePipelineName, "disk.img.xz")), + )) + + p.AddStage(osbuild.NewMkdirStage( + &osbuild.MkdirStageOptions{ + Paths: []osbuild.Path{ + { + Path: "images", + }, + { + Path: "images/pxeboot", + }, + }, + }, + )) + + var sectorSize uint64 = 512 + pt := disk.PartitionTable{ + Size: 20971520, + Partitions: []disk.Partition{ + { + Start: 0, + Size: 20971520 / sectorSize, + Filesystem: &disk.Filesystem{ + Type: "vfat", + Mountpoint: "/", + }, + }, + }, + } + + filename := "images/efiboot.img" + loopback := osbuild.NewLoopbackDevice(&osbuild.LoopbackDeviceOptions{Filename: filename}) + p.AddStage(osbuild.NewTruncateStage(&osbuild.TruncateStageOptions{Filename: filename, Size: fmt.Sprintf("%d", pt.Size)})) + + for _, stage := range mkfsStages(&pt, loopback) { + p.AddStage(stage) + } + + inputName := "root-tree" + copyInputs := copyPipelineTreeInputs(inputName, "efiboot-tree") + copyOptions, copyDevices, copyMounts := copyFSTreeOptions(inputName, "efiboot-tree", &pt, loopback) + p.AddStage(osbuild.NewCopyStage(copyOptions, copyInputs, copyDevices, copyMounts)) + + inputName = "coi" + copyInputs = copyPipelineTreeInputs(inputName, "coi-tree") + p.AddStage(osbuild.NewCopyStageSimple( + &osbuild.CopyStageOptions{ + Paths: []osbuild.CopyStagePath{ + { + From: fmt.Sprintf("input://%s/boot/vmlinuz-%s", inputName, kver), + To: "tree:///images/pxeboot/vmlinuz", + }, + { + From: fmt.Sprintf("input://%s/boot/initramfs-%s.img", inputName, kver), + To: "tree:///images/pxeboot/initrd.img", + }, + }, + }, + copyInputs, + )) + + inputName = "efi-tree" + copyInputs = copyPipelineTreeInputs(inputName, "efiboot-tree") + p.AddStage(osbuild.NewCopyStageSimple( + &osbuild.CopyStageOptions{ + Paths: []osbuild.CopyStagePath{ + { + From: fmt.Sprintf("input://%s/EFI", inputName), + To: "tree:///", + }, + }, + }, + copyInputs, + )) + + return p +} + +func simplifiedInstallerEFIBootTreePipeline(installDevice, kernelVer, arch, vendor, product, osVersion, isolabel string) *osbuild.Pipeline { + p := new(osbuild.Pipeline) + p.Name = "efiboot-tree" + p.Build = "name:build" + p.AddStage(osbuild.NewGrubISOStage(grubISOStageOptions(installDevice, kernelVer, arch, vendor, product, osVersion, isolabel))) + return p +} + +func simplifiedInstallerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, kernelVer, arch, product, osVersion, variant string) *osbuild.Pipeline { + p := new(osbuild.Pipeline) + p.Name = "coi-tree" + p.Build = "name:build" + p.AddStage(osbuild.NewRPMStage(rpmStageOptions(repos), rpmStageInputs(packages))) + p.AddStage(osbuild.NewBuildstampStage(buildStampStageOptions(arch, product, osVersion, variant))) + p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US.UTF-8"})) + p.AddStage(osbuild.NewSystemdStage(systemdStageOptions([]string{"coreos-installer"}, nil, nil, ""))) + p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer, arch, []string{"rdcore"}))) + + return p +} + +func ostreeDeployPipeline( + t *imageType, + pt *disk.PartitionTable, + repoPath string, + kernel *blueprint.KernelCustomization, + kernelVer string, + rng *rand.Rand, + options distro.ImageOptions, +) *osbuild.Pipeline { + + p := new(osbuild.Pipeline) + p.Name = "image-tree" + p.Build = "name:build" + osname := "redhat" + + p.AddStage(osbuild.OSTreeInitFsStage()) + p.AddStage(osbuild.NewOSTreePullStage( + &osbuild.OSTreePullStageOptions{Repo: repoPath}, + ostreePullStageInputs("org.osbuild.source", options.OSTree.Parent, options.OSTree.Ref), + )) + p.AddStage(osbuild.NewOSTreeOsInitStage( + &osbuild.OSTreeOsInitStageOptions{ + OSName: osname, + }, + )) + p.AddStage(osbuild.NewOSTreeConfigStage(ostreeConfigStageOptions(repoPath, true))) + p.AddStage(osbuild.NewMkdirStage(efiMkdirStageOptions())) + p.AddStage(osbuild.NewOSTreeDeployStage( + &osbuild.OSTreeDeployStageOptions{ + OsName: osname, + Ref: options.OSTree.Ref, + Mounts: []string{"/boot", "/boot/efi"}, + Rootfs: osbuild.Rootfs{ + Label: "root", + }, + KernelOpts: []string{ + "console=tty0", + "console=ttyS0", + }, + }, + )) + p.AddStage(osbuild.NewOSTreeFillvarStage( + &osbuild.OSTreeFillvarStageOptions{ + Deployment: osbuild.OSTreeDeployment{ + OSName: osname, + Ref: options.OSTree.Ref, + }, + }, + )) + + fstabOptions := pt.FSTabStageOptionsV2() + fstabOptions.OSTree = &osbuild.OSTreeFstab{ + Deployment: osbuild.OSTreeDeployment{ + OSName: osname, + Ref: options.OSTree.Ref, + }, + } + p.AddStage(osbuild.NewFSTabStage(fstabOptions)) + + // TODO: Add users? + + p.AddStage(bootloaderConfigStage(t, *pt, kernel, kernelVer, true, true)) + + p.AddStage(osbuild.NewOSTreeSelinuxStage( + &osbuild.OSTreeSelinuxStageOptions{ + Deployment: osbuild.OSTreeDeployment{ + OSName: osname, + Ref: options.OSTree.Ref, + }, + }, + )) + return p +} + +func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, kernelVer, arch, product, osVersion, variant string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "anaconda-tree" p.Build = "name:build" p.AddStage(osbuild.NewRPMStage(rpmStageOptions(repos), rpmStageInputs(packages))) - for _, stage := range payloadStages { - p.AddStage(stage) - } - p.AddStage(osbuild.NewBuildstampStage(buildStampStageOptions(arch))) + p.AddStage(osbuild.NewBuildstampStage(buildStampStageOptions(arch, product, osVersion, variant))) p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US.UTF-8"})) rootPassword := "" @@ -1009,28 +1312,34 @@ func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec p.AddStage(osbuild.NewUsersStage(usersStageOptions)) p.AddStage(osbuild.NewAnacondaStage(anacondaStageOptions())) p.AddStage(osbuild.NewLoraxScriptStage(loraxScriptStageOptions(arch))) - p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer))) + p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer, arch, []string{ + "anaconda", + }))) return p } -func bootISOTreePipeline(kernelVer string, arch string, ksOptions *osbuild.KickstartStageOptions) *osbuild.Pipeline { +func bootISOTreePipeline(kernelVer, arch, vendor, product, osVersion, isolabel string, ksOptions *osbuild.KickstartStageOptions, payloadStages []*osbuild.Stage) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "bootiso-tree" p.Build = "name:build" - p.AddStage(osbuild.NewBootISOMonoStage(bootISOMonoStageOptions(kernelVer, arch), bootISOMonoStageInputs())) + p.AddStage(osbuild.NewBootISOMonoStage(bootISOMonoStageOptions(kernelVer, arch, vendor, product, osVersion, isolabel), bootISOMonoStageInputs())) p.AddStage(osbuild.NewKickstartStage(ksOptions)) p.AddStage(osbuild.NewDiscinfoStage(discinfoStageOptions(arch))) + for _, stage := range payloadStages { + p.AddStage(stage) + } + return p } -func bootISOPipeline(filename string, arch string) *osbuild.Pipeline { +func bootISOPipeline(filename, isolabel, arch string, isolinux bool) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "bootiso" p.Build = "name:build" - p.AddStage(osbuild.NewXorrisofsStage(xorrisofsStageOptions(filename, arch), xorrisofsStageInputs())) + p.AddStage(osbuild.NewXorrisofsStage(xorrisofsStageOptions(filename, isolabel, arch, isolinux), xorrisofsStageInputs("bootiso-tree"))) p.AddStage(osbuild.NewImplantisomd5Stage(&osbuild.Implantisomd5StageOptions{Filename: filename})) return p @@ -1073,8 +1382,8 @@ func xzArchivePipeline(inputPipelineName, inputFilename, outputFilename string) // mkfsStages generates a list of org.osbuild.mkfs.* stages based on a // partition table description for a single device node -func mkfsStages(pt *disk.PartitionTable, device *osbuild.Device) []*osbuild2.Stage { - stages := make([]*osbuild2.Stage, 0, len(pt.Partitions)) +func mkfsStages(pt *disk.PartitionTable, device *osbuild.Device) []*osbuild.Stage { + stages := make([]*osbuild.Stage, 0, len(pt.Partitions)) // assume loopback device for simplicity since it's the only one currently supported // panic if the conversion fails @@ -1138,7 +1447,7 @@ func qemuPipeline(inputPipelineName, inputFilename, outputFilename, format, qcow return p } -func bootloaderConfigStage(t *imageType, partitionTable disk.PartitionTable, kernel *blueprint.KernelCustomization, kernelVer string) *osbuild.Stage { +func bootloaderConfigStage(t *imageType, partitionTable disk.PartitionTable, kernel *blueprint.KernelCustomization, kernelVer string, install, greenboot bool) *osbuild.Stage { if t.arch.name == distro.S390xArchName { return osbuild.NewZiplStage(new(osbuild.ZiplStageOptions)) } @@ -1146,7 +1455,11 @@ func bootloaderConfigStage(t *imageType, partitionTable disk.PartitionTable, ker kernelOptions := t.kernelOptions uefi := t.supportsUEFI() legacy := t.arch.legacy - return osbuild.NewGRUB2Stage(grub2StageOptions(partitionTable.RootPartition(), partitionTable.BootPartition(), kernelOptions, kernel, kernelVer, uefi, legacy)) + + options := grub2StageOptions(partitionTable.RootPartition(), partitionTable.BootPartition(), kernelOptions, kernel, kernelVer, uefi, legacy, t.arch.distro.vendor, install) + options.Greenboot = greenboot + + return osbuild.NewGRUB2Stage(options) } func bootloaderInstStage(filename string, pt *disk.PartitionTable, arch *architecture, kernelVer string, devices *osbuild.Devices, mounts *osbuild.Mounts, disk *osbuild.Device) *osbuild.Stage { diff --git a/internal/distro/rhel90/stage_inputs.go b/internal/distro/rhel90/stage_inputs.go index b96b513c2..c1b27e311 100644 --- a/internal/distro/rhel90/stage_inputs.go +++ b/internal/distro/rhel90/stage_inputs.go @@ -42,16 +42,16 @@ func ostreePullStageInputs(origin, source, commitRef string) *osbuild.OSTreePull return &osbuild.OSTreePullStageInputs{Commits: pullStageInput} } -func xorrisofsStageInputs() *osbuild.XorrisofsStageInputs { +func xorrisofsStageInputs(pipeline string) *osbuild.XorrisofsStageInputs { input := new(osbuild.XorrisofsStageInput) input.Type = "org.osbuild.tree" input.Origin = "org.osbuild.pipeline" - input.References = osbuild.XorrisofsStageReferences{"name:bootiso-tree"} + input.References = osbuild.XorrisofsStageReferences{"name:" + pipeline} return &osbuild.XorrisofsStageInputs{Tree: input} } func copyPipelineTreeInputs(name, inputPipeline string) *osbuild.CopyStageInputs { - inputName := "root-tree" + inputName := name treeInput := osbuild.CopyStageInput{} treeInput.Type = "org.osbuild.tree" treeInput.Origin = "org.osbuild.pipeline" diff --git a/internal/distro/rhel90/stage_options.go b/internal/distro/rhel90/stage_options.go index 7456136fc..0e2a88da2 100644 --- a/internal/distro/rhel90/stage_options.go +++ b/internal/distro/rhel90/stage_options.go @@ -2,14 +2,17 @@ package rhel90 import ( "fmt" + "os" "path/filepath" "sort" "github.com/google/uuid" "github.com/osbuild/osbuild-composer/internal/blueprint" + "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/crypt" "github.com/osbuild/osbuild-composer/internal/disk" + "github.com/osbuild/osbuild-composer/internal/distro" osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) @@ -144,12 +147,12 @@ func systemdStageOptions(enabledServices, disabledServices []string, s *blueprin } } -func buildStampStageOptions(arch string) *osbuild.BuildstampStageOptions { +func buildStampStageOptions(arch, product, osVersion, variant string) *osbuild.BuildstampStageOptions { return &osbuild.BuildstampStageOptions{ Arch: arch, - Product: "Red Hat Enterprise Linux", + Product: product, Version: osVersion, - Variant: "edge", + Variant: variant, Final: true, } } @@ -171,7 +174,7 @@ func loraxScriptStageOptions(arch string) *osbuild.LoraxScriptStageOptions { } } -func dracutStageOptions(kernelVer string) *osbuild.DracutStageOptions { +func dracutStageOptions(kernelVer, arch string, additionalModules []string) *osbuild.DracutStageOptions { kernel := []string{kernelVer} modules := []string{ "bash", @@ -192,7 +195,6 @@ func dracutStageOptions(kernelVer string) *osbuild.DracutStageOptions { "plymouth", "prefixdevname", "prefixdevname-tools", - "anaconda", "crypt", "dm", "dmsquash-live", @@ -214,7 +216,6 @@ func dracutStageOptions(kernelVer string) *osbuild.DracutStageOptions { "rootfs-block", "terminfo", "udev-rules", - "biosdevname", "dracut-systemd", "pollcdrom", "usrmount", @@ -224,6 +225,12 @@ func dracutStageOptions(kernelVer string) *osbuild.DracutStageOptions { "shutdown", "uefi-lib", } + + if arch == distro.X86_64ArchName { + modules = append(modules, "biosdevname") + } + + modules = append(modules, additionalModules...) return &osbuild.DracutStageOptions{ Kernel: kernel, Modules: modules, @@ -252,29 +259,35 @@ func ostreeKickstartStageOptions(ostreeURL, ostreeRef string) *osbuild.Kickstart } } -func bootISOMonoStageOptions(kernelVer string, arch string) *osbuild.BootISOMonoStageOptions { +func bootISOMonoStageOptions(kernelVer, arch, vendor, product, osVersion, isolabel string) *osbuild.BootISOMonoStageOptions { comprOptions := new(osbuild.FSCompressionOptions) if bcj := osbuild.BCJOption(arch); bcj != "" { comprOptions.BCJ = bcj } - isolabel := fmt.Sprintf("RHEL-9-0-0-BaseOS-%s", arch) + var architectures []string + + if arch == distro.X86_64ArchName { + architectures = []string{"IA32", "X64"} + } else if arch == distro.Aarch64ArchName { + architectures = []string{"AA64"} + } else { + panic("unsupported architecture") + } + return &osbuild.BootISOMonoStageOptions{ Product: osbuild.Product{ - Name: "Red Hat Enterprise Linux", + Name: product, Version: osVersion, }, ISOLabel: isolabel, Kernel: kernelVer, KernelOpts: fmt.Sprintf("inst.ks=hd:LABEL=%s:%s", isolabel, kspath), EFI: osbuild.EFI{ - Architectures: []string{ - "IA32", - "X64", - }, - Vendor: "redhat", + Architectures: architectures, + Vendor: vendor, }, ISOLinux: osbuild.ISOLinux{ - Enabled: true, + Enabled: arch == distro.X86_64ArchName, Debug: false, }, Templates: "80-rhel", @@ -288,6 +301,40 @@ func bootISOMonoStageOptions(kernelVer string, arch string) *osbuild.BootISOMono } } +func grubISOStageOptions(installDevice, kernelVer, arch, vendor, product, osVersion, isolabel string) *osbuild.GrubISOStageOptions { + var architectures []string + + if arch == "x86_64" { + architectures = []string{"IA32", "X64"} + } else if arch == "aarch64" { + architectures = []string{"AA64"} + } else { + panic("unsupported architecture") + } + + return &osbuild.GrubISOStageOptions{ + Product: osbuild.Product{ + Name: product, + Version: osVersion, + }, + ISOLabel: isolabel, + Kernel: osbuild.ISOKernel{ + Dir: "/images/pxeboot", + Opts: []string{"rd.neednet=1", + "console=tty0", + "console=ttyS0", + "systemd.log_target=console", + "systemd.journald.forward_to_console=1", + "edge.liveiso=" + isolabel, + "coreos.inst.install_dev=" + installDevice, + "coreos.inst.image_file=/run/media/iso/disk.img.xz", + "coreos.inst.insecure"}, + }, + Architectures: architectures, + Vendor: vendor, + } +} + func discinfoStageOptions(arch string) *osbuild.DiscinfoStageOptions { return &osbuild.DiscinfoStageOptions{ BaseArch: arch, @@ -295,22 +342,35 @@ func discinfoStageOptions(arch string) *osbuild.DiscinfoStageOptions { } } -func xorrisofsStageOptions(filename string, arch string) *osbuild.XorrisofsStageOptions { - return &osbuild.XorrisofsStageOptions{ +func xorrisofsStageOptions(filename, isolabel, arch string, isolinux bool) *osbuild.XorrisofsStageOptions { + options := &osbuild.XorrisofsStageOptions{ Filename: filename, - VolID: fmt.Sprintf("RHEL-9-0-0-BaseOS-%s", arch), + VolID: fmt.Sprintf(isolabel, arch), SysID: "LINUX", - Boot: &osbuild.XorrisofsBoot{ + EFI: "images/efiboot.img", + } + + if isolinux { + options.Boot = &osbuild.XorrisofsBoot{ Image: "isolinux/isolinux.bin", Catalog: "isolinux/boot.cat", - }, - EFI: "images/efiboot.img", - IsohybridMBR: "/usr/share/syslinux/isohdpfx.bin", + } + + options.IsohybridMBR = "/usr/share/syslinux/isohdpfx.bin" } + + return options } -func grub2StageOptions(rootPartition *disk.Partition, bootPartition *disk.Partition, kernelOptions string, - kernel *blueprint.KernelCustomization, kernelVer string, uefi bool, legacy string) *osbuild.GRUB2StageOptions { +func grub2StageOptions(rootPartition *disk.Partition, + bootPartition *disk.Partition, + kernelOptions string, + kernel *blueprint.KernelCustomization, + kernelVer string, + uefi bool, + legacy string, + vendor string, + install bool) *osbuild.GRUB2StageOptions { if rootPartition == nil { panic("root partition must be defined for grub2 stage, this is a programming error") } @@ -328,7 +388,8 @@ func grub2StageOptions(rootPartition *disk.Partition, bootPartition *disk.Partit if uefi { stageOptions.UEFI = &osbuild.GRUB2UEFI{ - Vendor: "redhat", + Vendor: vendor, + Install: install, Unified: legacy == "", // force unified grub scheme for pure efi systems } } @@ -446,6 +507,11 @@ func grub2InstStageOptions(filename string, pt *disk.PartitionTable, platform st if bootPartIndex == -1 { panic("failed to find boot or root partition for grub2.inst stage") } + bootPart := pt.Partitions[bootPartIndex] + prefixPath := "/boot/grub2" + if bootPart.Filesystem.Mountpoint == "/boot" { + prefixPath = "/grub2" + } core := osbuild.CoreMkImage{ Type: "mkimage", PartLabel: pt.Type, @@ -456,7 +522,7 @@ func grub2InstStageOptions(filename string, pt *disk.PartitionTable, platform st Type: "partition", PartLabel: pt.Type, Number: uint(bootPartIndex), - Path: "/boot/grub2", + Path: prefixPath, } return &osbuild.Grub2InstStageOptions{ @@ -512,3 +578,48 @@ func kernelCmdlineStageOptions(rootUUID string, kernelOptions string) *osbuild.K KernelOpts: kernelOptions, } } + +func nginxConfigStageOptions(path, htmlRoot, listen string) *osbuild.NginxConfigStageOptions { + // configure nginx to work in an unprivileged container + cfg := &osbuild.NginxConfig{ + Listen: listen, + Root: htmlRoot, + Daemon: common.BoolToPtr(false), + PID: "/tmp/nginx.pid", + } + return &osbuild.NginxConfigStageOptions{ + Path: path, + Config: cfg, + } +} + +func chmodStageOptions(path, mode string, recursive bool) *osbuild.ChmodStageOptions { + return &osbuild.ChmodStageOptions{ + Items: map[string]osbuild.ChmodStagePathOptions{ + path: {Mode: mode, Recursive: recursive}, + }, + } +} + +func ostreeConfigStageOptions(repo string, readOnly bool) *osbuild.OSTreeConfigStageOptions { + return &osbuild.OSTreeConfigStageOptions{ + Repo: repo, + Config: &osbuild.OSTreeConfig{ + Sysroot: &osbuild.SysrootOptions{ + ReadOnly: common.BoolToPtr(readOnly), + Bootloader: "none", + }, + }, + } +} + +func efiMkdirStageOptions() *osbuild.MkdirStageOptions { + return &osbuild.MkdirStageOptions{ + Paths: []osbuild.Path{ + { + Path: "/boot/efi", + Mode: os.FileMode(0700), + }, + }, + } +} diff --git a/internal/distroregistry/distroregistry.go b/internal/distroregistry/distroregistry.go index f5e88785c..731a6577c 100644 --- a/internal/distroregistry/distroregistry.go +++ b/internal/distroregistry/distroregistry.go @@ -30,6 +30,7 @@ var supportedDistros = []supportedDistro{ {rhel90beta.New, rhel90beta.NewHostDistro}, {rhel90beta.NewRHEL90, rhel90beta.NewHostDistro}, {rhel90.New, rhel90.NewHostDistro}, + {rhel90.NewCentos, rhel90.NewCentosHostDistro}, } type supportedDistro struct {