package rhel90 import ( "encoding/json" "errors" "fmt" "math/rand" "path" "sort" "strings" "github.com/osbuild/osbuild-composer/internal/blueprint" "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" ) const ( // package set names // build package set name buildPkgsKey = "build" // main/common os image package set name osPkgsKey = "packages" // container package set name containerPkgsKey = "container" // installer package set name installerPkgsKey = "installer" // blueprint package set name blueprintPkgsKey = "blueprint" ) var mountpointAllowList = []string{ "/", "/var", "/opt", "/srv", "/usr", "/app", "/data", "/home", } type distribution struct { name string product string osVersion string releaseVersion string modulePlatformID string vendor string ostreeRefTmpl string isolabelTmpl string runner string arches map[string]distro.Arch } // distribution objects without the arches > image types var distroMap = map[string]distribution{ "rhel-90": { name: "rhel-90", 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 { return d.name } func (d *distribution) Releasever() string { return d.releaseVersion } func (d *distribution) ModulePlatformID() string { return d.modulePlatformID } func (d *distribution) OSTreeRef() string { return d.ostreeRefTmpl } func (d *distribution) ListArches() []string { archNames := make([]string, 0, len(d.arches)) for name := range d.arches { archNames = append(archNames, name) } sort.Strings(archNames) return archNames } func (d *distribution) GetArch(name string) (distro.Arch, error) { arch, exists := d.arches[name] if !exists { return nil, errors.New("invalid architecture: " + name) } return arch, nil } func (d *distribution) addArches(arches ...architecture) { if d.arches == nil { d.arches = map[string]distro.Arch{} } // Do not make copies of architectures, as opposed to image types, // because architecture definitions are not used by more than a single // distro definition. for idx := range arches { d.arches[arches[idx].name] = &arches[idx] } } 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 legacy string bootType distro.BootType } func (a *architecture) Name() string { return a.name } func (a *architecture) ListImageTypes() []string { itNames := make([]string, 0, len(a.imageTypes)) for name := range a.imageTypes { itNames = append(itNames, name) } sort.Strings(itNames) return itNames } func (a *architecture) GetImageType(name string) (distro.ImageType, error) { t, exists := a.imageTypes[name] if !exists { aliasForName, exists := a.imageTypeAliases[name] if !exists { return nil, errors.New("invalid image type: " + name) } t, exists = a.imageTypes[aliasForName] if !exists { panic(fmt.Sprintf("image type '%s' is an alias to a non-existing image type '%s'", name, aliasForName)) } } return t, nil } func (a *architecture) addImageTypes(imageTypes ...imageType) { if a.imageTypes == nil { a.imageTypes = map[string]distro.ImageType{} } for idx := range imageTypes { it := imageTypes[idx] it.arch = a a.imageTypes[it.name] = &it for _, alias := range it.nameAliases { if a.imageTypeAliases == nil { a.imageTypeAliases = map[string]string{} } if existingAliasFor, exists := a.imageTypeAliases[alias]; exists { panic(fmt.Sprintf("image type alias '%s' for '%s' is already defined for another image type '%s'", alias, it.name, existingAliasFor)) } a.imageTypeAliases[alias] = it.name } } } func (a *architecture) Distro() distro.Distro { return a.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]packageSetFunc enabledServices []string disabledServices []string defaultTarget string kernelOptions string defaultSize uint64 buildPipelines []string payloadPipelines []string exports []string pipelines pipelinesFunc // bootISO: installable ISO bootISO bool // rpmOstree: edge/ostree rpmOstree bool // bootable image bootable bool // If set to a value, it is preferred over the architecture value bootType distro.BootType // List of valid arches for the image type basePartitionTables distro.BasePartitionTableMap } func (t *imageType) Name() string { return t.name } func (t *imageType) Arch() distro.Arch { return t.arch } func (t *imageType) Filename() string { return t.filename } func (t *imageType) MIMEType() string { return t.mimeType } func (t *imageType) OSTreeRef() string { d := t.arch.distro if t.rpmOstree { return fmt.Sprintf(d.ostreeRefTmpl, t.arch.name) } return "" } func (t *imageType) Size(size uint64) uint64 { const MegaByte = 1024 * 1024 // Microsoft Azure requires vhd images to be rounded up to the nearest MB if t.name == "vhd" && size%MegaByte != 0 { size = (size/MegaByte + 1) * MegaByte } if size == 0 { size = t.defaultSize } 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 for name := range imageSets { mergedSets[name] = t.getPackages(name) } if _, hasPackages := imageSets[osPkgsKey]; !hasPackages { // should this be possible?? mergedSets[osPkgsKey] = rpmmd.PackageSet{} } // every image type must define a 'build' package set if _, hasBuild := imageSets[buildPkgsKey]; !hasBuild { panic(fmt.Sprintf("'%s' image type has no '%s' package set defined", t.name, buildPkgsKey)) } // blueprint packages bpPackages := bp.GetPackages() timezone, _ := bp.Customizations.GetTimezoneSettings() if timezone != nil { bpPackages = append(bpPackages, "chrony") } // depsolve bp packages separately // bp packages aren't restricted by exclude lists mergedSets[blueprintPkgsKey] = rpmmd.PackageSet{Include: bpPackages} kernel := bp.Customizations.GetKernel().Name // add bp kernel to main OS package set to avoid duplicate kernels mergedSets[osPkgsKey] = mergedSets[osPkgsKey].Append(rpmmd.PackageSet{Include: []string{kernel}}) return mergedSets } func (t *imageType) BuildPipelines() []string { return t.buildPipelines } func (t *imageType) PayloadPipelines() []string { return t.payloadPipelines } func (t *imageType) Exports() []string { if len(t.exports) > 0 { return t.exports } return []string{"assembler"} } // getBootType returns the BootType which should be used for this particular // combination of architecture and image type. func (t *imageType) getBootType() distro.BootType { bootType := t.arch.bootType if t.bootType != distro.UnsetBootType { bootType = t.bootType } return bootType } func (t *imageType) supportsUEFI() bool { bootType := t.getBootType() if bootType == distro.HybridBootType || bootType == distro.UEFIBootType { return true } return false } func (t *imageType) getPartitionTable( mountpoints []blueprint.FilesystemCustomization, options distro.ImageOptions, rng *rand.Rand, ) (disk.PartitionTable, error) { archName := t.arch.Name() basePartitionTable, exists := t.basePartitionTables[archName] if !exists { return basePartitionTable, fmt.Errorf("unknown arch: " + archName) } return disk.CreatePartitionTable(mountpoints, options.Size, basePartitionTable, rng), nil } // local type for ostree commit metadata used to define commit sources type ostreeCommit struct { Checksum string URL string } func (t *imageType) Manifest(customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSpecSets map[string][]rpmmd.PackageSpec, seed int64) (distro.Manifest, error) { if err := t.checkOptions(customizations, options); err != nil { return distro.Manifest{}, err } source := rand.NewSource(seed) rng := rand.New(source) pipelines, err := t.pipelines(t, customizations, options, repos, packageSpecSets, rng) if err != nil { return distro.Manifest{}, err } // flatten spec sets for sources allPackageSpecs := make([]rpmmd.PackageSpec, 0) for _, specs := range packageSpecSets { allPackageSpecs = append(allPackageSpecs, specs...) } var commits []ostreeCommit if options.OSTree.Parent != "" && options.OSTree.URL != "" { commits = []ostreeCommit{{Checksum: options.OSTree.Parent, URL: options.OSTree.URL}} } return json.Marshal( osbuild.Manifest{ Version: "2", Pipelines: pipelines, Sources: t.sources(allPackageSpecs, commits), }, ) } func (t *imageType) sources(packages []rpmmd.PackageSpec, ostreeCommits []ostreeCommit) osbuild.Sources { sources := osbuild.Sources{} curl := &osbuild.CurlSource{ Items: make(map[string]osbuild.CurlSourceItem), } for _, pkg := range packages { item := new(osbuild.URLWithSecrets) item.URL = pkg.RemoteLocation if pkg.Secrets == "org.osbuild.rhsm" { item.Secrets = &osbuild.URLSecrets{ Name: "org.osbuild.rhsm", } } curl.Items[pkg.Checksum] = item } if len(curl.Items) > 0 { sources["org.osbuild.curl"] = curl } ostree := &osbuild.OSTreeSource{ Items: make(map[string]osbuild.OSTreeSourceItem), } for _, commit := range ostreeCommits { item := new(osbuild.OSTreeSourceItem) item.Remote.URL = commit.URL ostree.Items[commit.Checksum] = *item } if len(ostree.Items) > 0 { sources["org.osbuild.ostree"] = ostree } return sources } func isMountpointAllowed(mountpoint string) bool { for _, allowed := range mountpointAllowList { match, _ := path.Match(allowed, mountpoint) if match { return true } // ensure that only clean mountpoints // are valid if strings.Contains(mountpoint, "//") { return false } match = strings.HasPrefix(mountpoint, allowed+"/") if allowed != "/" && match { return true } } return false } // checkOptions checks the validity and compatibility of options and customizations for the image type. func (t *imageType) checkOptions(customizations *blueprint.Customizations, options distro.ImageOptions) error { if t.bootISO && t.rpmOstree { 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 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) } if customizations.GetInstallationDevice() == "" { return fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name) } } 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") } mountpoints := customizations.GetFilesystems() if mountpoints != nil && t.rpmOstree { return fmt.Errorf("Custom mountpoints are not supported for ostree types") } invalidMountpoints := []string{} for _, m := range mountpoints { if m.Mountpoint == "/usr" && m.MinSize < 2147483648 { m.MinSize = 2147483648 } if !isMountpointAllowed(m.Mountpoint) { invalidMountpoints = append(invalidMountpoints, m.Mountpoint) } } if len(invalidMountpoints) > 0 { return fmt.Errorf("The following custom mountpoints are not supported %+q", invalidMountpoints) } return nil } // New creates a new distro object, defining the supported architectures and image types func New() distro.Distro { return newDistro("rhel-90") } func NewHostDistro(name, modulePlatformID, ostreeRef string) distro.Distro { return newDistro("rhel-90") } 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 := distroMap[distroName] // Architecture definitions x86_64 := architecture{ name: distro.X86_64ArchName, distro: &rd, legacy: "i386-pc", bootType: distro.HybridBootType, } aarch64 := architecture{ name: distro.Aarch64ArchName, distro: &rd, bootType: distro.UEFIBootType, } ppc64le := architecture{ distro: &rd, name: distro.Ppc64leArchName, legacy: "powerpc-ieee1275", bootType: distro.LegacyBootType, } s390x := architecture{ distro: &rd, name: distro.S390xArchName, bootType: distro.LegacyBootType, } // Shared Services edgeServices := []string{ "NetworkManager.service", "firewalld.service", "sshd.service", } // Image Definitions edgeCommitImgType := imageType{ name: "edge-commit", nameAliases: []string{"rhel-edge-commit"}, filename: "commit.tar", mimeType: "application/x-tar", packageSets: map[string]packageSetFunc{ buildPkgsKey: edgeBuildPackageSet, osPkgsKey: edgeCommitPackageSet, }, enabledServices: edgeServices, rpmOstree: true, pipelines: edgeCommitPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"ostree-tree", "ostree-commit", "commit-archive"}, exports: []string{"commit-archive"}, } edgeOCIImgType := imageType{ name: "edge-container", nameAliases: []string{"rhel-edge-container"}, filename: "container.tar", mimeType: "application/x-tar", packageSets: map[string]packageSetFunc{ buildPkgsKey: edgeBuildPackageSet, osPkgsKey: edgeCommitPackageSet, containerPkgsKey: func(t *imageType) rpmmd.PackageSet { return rpmmd.PackageSet{ Include: []string{"nginx"}, } }, }, enabledServices: edgeServices, rpmOstree: true, bootISO: false, pipelines: edgeContainerPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"ostree-tree", "ostree-commit", "container-tree", "container"}, 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, buildPipelines: []string{"build"}, payloadPipelines: []string{"image-tree", "image", "archive"}, 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]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, osPkgsKey: edgeCommitPackageSet, installerPkgsKey: edgeInstallerPackageSet, }, enabledServices: edgeServices, rpmOstree: true, bootISO: true, pipelines: edgeInstallerPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"anaconda-tree", "bootiso-tree", "bootiso"}, exports: []string{"bootiso"}, } // edgeSimplifiedInstallerImgType := imageType{ _ = 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, buildPipelines: []string{"build"}, payloadPipelines: []string{"image-tree", "image", "archive", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"}, 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]packageSetFunc{ buildPkgsKey: distroBuildPackageSet, osPkgsKey: qcow2CommonPackageSet, }, bootable: true, defaultSize: 10 * GigaByte, pipelines: qcow2Pipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "qcow2"}, exports: []string{"qcow2"}, basePartitionTables: defaultBasePartitionTables, } vhdImgType := imageType{ name: "vhd", filename: "disk.vhd", mimeType: "application/x-vhd", packageSets: map[string]packageSetFunc{ buildPkgsKey: distroBuildPackageSet, osPkgsKey: vhdCommonPackageSet, }, enabledServices: []string{ "sshd", "waagent", }, defaultTarget: "multi-user.target", kernelOptions: "ro biosdevname=0 rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0", bootable: true, defaultSize: 4 * GigaByte, pipelines: vhdPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "vpc"}, exports: []string{"vpc"}, basePartitionTables: defaultBasePartitionTables, } vmdkImgType := imageType{ name: "vmdk", filename: "disk.vmdk", mimeType: "application/x-vmdk", packageSets: map[string]packageSetFunc{ buildPkgsKey: distroBuildPackageSet, osPkgsKey: vmdkCommonPackageSet, }, kernelOptions: "ro net.ifnames=0", bootable: true, defaultSize: 4 * GigaByte, pipelines: vmdkPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "vmdk"}, exports: []string{"vmdk"}, basePartitionTables: defaultBasePartitionTables, } openstackImgType := imageType{ name: "openstack", filename: "disk.qcow2", mimeType: "application/x-qemu-disk", packageSets: map[string]packageSetFunc{ buildPkgsKey: distroBuildPackageSet, osPkgsKey: openstackCommonPackageSet, }, kernelOptions: "ro net.ifnames=0", bootable: true, defaultSize: 4 * GigaByte, pipelines: openstackPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "qcow2"}, exports: []string{"qcow2"}, basePartitionTables: defaultBasePartitionTables, } // EC2 services ec2EnabledServices := []string{ "sshd", "NetworkManager", "nm-cloud-setup.service", "nm-cloud-setup.timer", "cloud-init", "cloud-init-local", "cloud-config", "cloud-final", "reboot.target", } amiImgTypeX86_64 := imageType{ name: "ami", filename: "image.raw", mimeType: "application/octet-stream", packageSets: map[string]packageSetFunc{ buildPkgsKey: ec2BuildPackageSet, osPkgsKey: ec2CommonPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", bootable: true, bootType: distro.LegacyBootType, defaultSize: 10 * GigaByte, pipelines: ec2Pipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image"}, exports: []string{"image"}, basePartitionTables: ec2BasePartitionTables, } amiImgTypeAarch64 := imageType{ name: "ami", filename: "image.raw", mimeType: "application/octet-stream", packageSets: map[string]packageSetFunc{ buildPkgsKey: ec2BuildPackageSet, osPkgsKey: ec2CommonPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0 crashkernel=auto", bootable: true, defaultSize: 10 * GigaByte, pipelines: ec2Pipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image"}, exports: []string{"image"}, basePartitionTables: ec2BasePartitionTables, } ec2ImgTypeX86_64 := imageType{ name: "ec2", filename: "image.raw.xz", mimeType: "application/xz", packageSets: map[string]packageSetFunc{ buildPkgsKey: ec2BuildPackageSet, osPkgsKey: rhelEc2PackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", bootable: true, bootType: distro.LegacyBootType, defaultSize: 10 * GigaByte, pipelines: rhelEc2Pipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "archive"}, exports: []string{"archive"}, basePartitionTables: ec2BasePartitionTables, } ec2ImgTypeAarch64 := imageType{ name: "ec2", filename: "image.raw.xz", mimeType: "application/xz", packageSets: map[string]packageSetFunc{ buildPkgsKey: ec2BuildPackageSet, osPkgsKey: rhelEc2PackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0 crashkernel=auto", bootable: true, defaultSize: 10 * GigaByte, pipelines: rhelEc2Pipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "archive"}, exports: []string{"archive"}, basePartitionTables: ec2BasePartitionTables, } ec2HaImgTypeX86_64 := imageType{ name: "ec2-ha", filename: "image.raw.xz", mimeType: "application/xz", packageSets: map[string]packageSetFunc{ buildPkgsKey: ec2BuildPackageSet, osPkgsKey: rhelEc2HaPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto", bootable: true, bootType: distro.LegacyBootType, defaultSize: 10 * GigaByte, pipelines: rhelEc2Pipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "archive"}, exports: []string{"archive"}, basePartitionTables: ec2BasePartitionTables, } ec2SapImgTypeX86_64 := imageType{ name: "ec2-sap", filename: "image.raw.xz", mimeType: "application/xz", packageSets: map[string]packageSetFunc{ buildPkgsKey: ec2BuildPackageSet, osPkgsKey: rhelEc2SapPackageSet, }, defaultTarget: "multi-user.target", enabledServices: ec2EnabledServices, kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto processor.max_cstate=1 intel_idle.max_cstate=1", bootable: true, bootType: distro.LegacyBootType, defaultSize: 10 * GigaByte, pipelines: rhelEc2SapPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "archive"}, exports: []string{"archive"}, basePartitionTables: ec2BasePartitionTables, } tarImgType := imageType{ name: "tar", filename: "root.tar.xz", mimeType: "application/x-tar", 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, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "root-tar"}, exports: []string{"root-tar"}, } tarInstallerImgTypeX86_64 := imageType{ name: "image-installer", filename: "installer.iso", mimeType: "application/x-iso9660-image", packageSets: map[string]packageSetFunc{ buildPkgsKey: anacondaBuildPackageSet, osPkgsKey: bareMetalPackageSet, installerPkgsKey: anacondaPackageSet, }, rpmOstree: false, bootISO: true, bootable: true, pipelines: tarInstallerPipelines, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "anaconda-tree", "bootiso-tree", "bootiso"}, exports: []string{"bootiso"}, } // NOTE: Edge simplified installer requires coreos-installer which isn't yet available in RHEL 9.0 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) 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 }