diff --git a/cmd/osbuild-composer/config.go b/cmd/osbuild-composer/config.go index 1b1b955cd..027be77f8 100644 --- a/cmd/osbuild-composer/config.go +++ b/cmd/osbuild-composer/config.go @@ -87,6 +87,7 @@ func GetDefaultConfig() *ComposerConfigFile { ImageTypeDenyList: []string{ "ec2", "ec2-ha", + "ec2-sap", }, }, }, diff --git a/cmd/osbuild-composer/config_test.go b/cmd/osbuild-composer/config_test.go index 5f4c9dc1a..c75f73d2a 100644 --- a/cmd/osbuild-composer/config_test.go +++ b/cmd/osbuild-composer/config_test.go @@ -47,6 +47,7 @@ func TestDefaultConfig(t *testing.T) { []string{ "ec2", "ec2-ha", + "ec2-sap", }, }, }, diff --git a/docs/news/unreleased/rhel-9.0-ec2-sap-image.md b/docs/news/unreleased/rhel-9.0-ec2-sap-image.md new file mode 100644 index 000000000..8e7384808 --- /dev/null +++ b/docs/news/unreleased/rhel-9.0-ec2-sap-image.md @@ -0,0 +1,6 @@ +# Add support for official RHEL EC2 SAP image on RHEL-9.0 + +OSBuild Composer can now build the RHEL 9.0 EC2 SAP image called `ec2-sap`, +which is based on the official RHEL EC2 SAP image. The image type is not +exposed through the Weldr API, because its default package set includes the +RHUI client packages, which are not publicly available. diff --git a/internal/distro/rhel90/distro.go b/internal/distro/rhel90/distro.go index 5d915a36d..a536c6bdb 100644 --- a/internal/distro/rhel90/distro.go +++ b/internal/distro/rhel90/distro.go @@ -782,6 +782,25 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { basePartitionTables: ec2BasePartitionTables, } + ec2SapImgTypeX86_64 := imageType{ + name: "ec2-sap", + filename: "image.raw.xz", + mimeType: "application/xz", + packageSets: map[string]rpmmd.PackageSet{ + 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, + exports: []string{"archive"}, + basePartitionTables: ec2BasePartitionTables, + } + tarImgType := imageType{ name: "tar", filename: "root.tar.xz", @@ -811,7 +830,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { exports: []string{"bootiso"}, } - x86_64.addImageTypes(qcow2ImgType, vhdImgType, vmdkImgType, openstackImgType, amiImgTypeX86_64, ec2ImgTypeX86_64, ec2HaImgTypeX86_64, tarImgType, tarInstallerImgTypeX86_64, edgeCommitImgType, edgeInstallerImgType, edgeOCIImgType) + 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) ppc64le.addImageTypes(qcow2ImgType, tarImgType) s390x.addImageTypes(qcow2ImgType, tarImgType) diff --git a/internal/distro/rhel90/distro_test.go b/internal/distro/rhel90/distro_test.go index 3c1f8b8a4..e3492d39a 100644 --- a/internal/distro/rhel90/distro_test.go +++ b/internal/distro/rhel90/distro_test.go @@ -64,6 +64,14 @@ func TestFilenameFromType(t *testing.T) { mimeType: "application/xz", }, }, + { + name: "ec2-sap", + args: args{"ec2-sap"}, + want: wantResult{ + filename: "image.raw.xz", + mimeType: "application/xz", + }, + }, { name: "qcow2", args: args{"qcow2"}, @@ -261,6 +269,7 @@ func TestImageType_Name(t *testing.T) { "ami", "ec2", "ec2-ha", + "ec2-sap", "edge-commit", "edge-container", "edge-installer", @@ -443,6 +452,7 @@ func TestArchitecture_ListImageTypes(t *testing.T) { "ami", "ec2", "ec2-ha", + "ec2-sap", "edge-commit", "edge-container", "edge-installer", diff --git a/internal/distro/rhel90/package_sets.go b/internal/distro/rhel90/package_sets.go index 7843a6fd0..7290e4100 100644 --- a/internal/distro/rhel90/package_sets.go +++ b/internal/distro/rhel90/package_sets.go @@ -195,7 +195,7 @@ func ec2CommonPackageSet() rpmmd.PackageSet { "redhat-release-eula", "rsync", "tar", "qemu-guest-agent", }, Exclude: []string{ - "aic94xx-firmware", "alsa-firmware", "alsa-lib", + "aic94xx-firmware", "alsa-firmware", "alsa-tools-firmware", "biosdevname", "firewalld", "iprutils", "ivtv-firmware", "iwl1000-firmware", "iwl100-firmware", "iwl105-firmware", "iwl135-firmware", "iwl2000-firmware", "iwl2030-firmware", @@ -213,6 +213,7 @@ func ec2CommonPackageSet() rpmmd.PackageSet { func rhelEc2PackageSet() rpmmd.PackageSet { ec2PackageSet := ec2CommonPackageSet() ec2PackageSet.Include = append(ec2PackageSet.Include, "rh-amazon-rhui-client") + ec2PackageSet.Exclude = append(ec2PackageSet.Exclude, "alsa-lib") return ec2PackageSet } @@ -225,9 +226,53 @@ func rhelEc2HaPackageSet() rpmmd.PackageSet { "pcs", "rh-amazon-rhui-client-ha", ) + ec2HaPackageSet.Exclude = append(ec2HaPackageSet.Exclude, "alsa-lib") return ec2HaPackageSet } +// rhel-sap-ec2 image package set +func rhelEc2SapPackageSet() rpmmd.PackageSet { + ec2SapPackageSet := ec2CommonPackageSet() + ec2SapPackageSet.Include = append(ec2SapPackageSet.Include, + // SAP System Roles + // https://access.redhat.com/sites/default/files/attachments/rhel_system_roles_for_sap_1.pdf + "ansible-core", + "rhel-system-roles-sap", + // RHBZ#1959813 + "bind-utils", + //"compat-sap-c++-9", // not needed on RHEL-9 + "nfs-utils", + "tcsh", + // RHBZ#1959955 + "uuidd", + // RHBZ#1959923 + "cairo", + "expect", + "graphviz", + "gtk2", + "iptraf-ng", + "krb5-workstation", + "libaio", + "libatomic", + "libcanberra-gtk2", + "libicu", + //"libpng12", // not needed on RHEL-9 + "libtool-ltdl", + "lm_sensors", + "net-tools", + "numactl", + "PackageKit-gtk3-module", + "xorg-x11-xauth", + // RHBZ#1960617 + "tuned-profiles-sap-hana", + // RHBZ#1961168 + "libnsl", + // RHUI client + "rh-amazon-rhui-client-sap-bundle-e4s", + ) + return ec2SapPackageSet +} + // edge commit OS package set func edgeCommitPackageSet() rpmmd.PackageSet { return rpmmd.PackageSet{ diff --git a/internal/distro/rhel90/pipelines.go b/internal/distro/rhel90/pipelines.go index 7934257a8..ef775faa3 100644 --- a/internal/distro/rhel90/pipelines.go +++ b/internal/distro/rhel90/pipelines.go @@ -432,6 +432,146 @@ func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations, return pipelines, nil } +func ec2SapPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, + 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])) + + partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) + if err != nil { + return nil, err + } + + var treePipeline *osbuild.Pipeline + 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) + default: + return nil, fmt.Errorf("ec2SapPipelines: unsupported image architecture: %q", arch) + } + if err != nil { + return nil, err + } + + // SAP-specific configuration + treePipeline.AddStage(osbuild.NewSELinuxConfigStage(&osbuild.SELinuxConfigStageOptions{ + State: osbuild.SELinuxStatePermissive, + })) + + // RHBZ#1960617 + treePipeline.AddStage(osbuild.NewTunedStage(osbuild.NewTunedStageOptions("sap-hana"))) + + // RHBZ#1959979 + treePipeline.AddStage(osbuild.NewTmpfilesdStage(osbuild.NewTmpfilesdStageOptions("sap.conf", + []osbuild.TmpfilesdConfigLine{ + { + Type: "x", + Path: "/tmp/.sap*", + }, + { + Type: "x", + Path: "/tmp/.hdb*lock", + }, + { + Type: "x", + Path: "/tmp/.trex*lock", + }, + }, + ))) + + // RHBZ#1959963 + treePipeline.AddStage(osbuild.NewPamLimitsConfStage(osbuild.NewPamLimitsConfStageOptions("99-sap.conf", + []osbuild.PamLimitsConfigLine{ + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(65536), + }, + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(65536), + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(65536), + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(65536), + }, + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + }, + ))) + + // RHBZ#1959962 + treePipeline.AddStage(osbuild.NewSysctldStage(osbuild.NewSysctldStageOptions("sap.conf", + []osbuild.SysctldConfigLine{ + { + Key: "kernel.pid_max", + Value: "4194304", + }, + { + Key: "vm.max_map_count", + Value: "2147483647", + }, + }, + ))) + + // E4S/EUS + treePipeline.AddStage(osbuild.NewDNFConfigStage(osbuild.NewDNFConfigStageOptions( + []osbuild.DNFVariable{ + { + Name: "releasever", + Value: "9.0", + }, + }, + ))) + + 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)) + // The last stage must be the SELinux stage + treePipeline.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false))) + pipelines = append(pipelines, *treePipeline) + + imagePipeline := liveImagePipeline(treePipeline.Name, diskfile, &partitionTable, t.arch, kernelVer) + pipelines = append(pipelines, *imagePipeline) + return pipelines, nil +} + // ec2Pipelines returns pipelines which produce uncompressed EC2 images which are expected to use RHSM for content func ec2Pipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { return ec2CommonPipelines(t, customizations, options, repos, packageSetSpecs, rng, false, t.Filename()) @@ -452,6 +592,21 @@ func rhelEc2Pipelines(t *imageType, customizations *blueprint.Customizations, op return pipelines, nil } +// rhelEc2SapPipelines returns pipelines which produce XZ-compressed EC2 SAP images which are expected to use RHUI for content +func rhelEc2SapPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) { + rawImageFilename := "image.raw" + + pipelines, err := ec2SapPipelines(t, customizations, options, repos, packageSetSpecs, rng, true, rawImageFilename) + if err != nil { + return nil, err + } + + lastPipeline := pipelines[len(pipelines)-1] + pipelines = append(pipelines, *xzArchivePipeline(lastPipeline.Name, rawImageFilename, t.Filename())) + + return pipelines, nil +} + 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])) diff --git a/tools/test-case-generators/format-request-map.json b/tools/test-case-generators/format-request-map.json index 84a5be4d4..eb61e5929 100644 --- a/tools/test-case-generators/format-request-map.json +++ b/tools/test-case-generators/format-request-map.json @@ -32,6 +32,17 @@ }, "overrides": {} }, + "ec2-sap": { + "compose-request": { + "distro": "", + "arch": "", + "image-type": "ec2-sap", + "repositories": [], + "filename": "image.raw.xz", + "blueprint": {} + }, + "overrides": {} + }, "edge-commit": { "compose-request": { "distro": "",