From 0b263d5478c0baf4eceff7ac59f62ec33e47d236 Mon Sep 17 00:00:00 2001 From: Achilleas Koutsou Date: Fri, 6 Jan 2023 21:33:20 +0100 Subject: [PATCH] distro/rhel8: update qcow2 and openstack to new definitions Copy osCustomizations() and liveImage() functions from RHEL 9. Delete unused functions. --- internal/distro/rhel8/images.go | 199 +++++++++++++++++++++++++++++ internal/distro/rhel8/pipelines.go | 54 -------- internal/distro/rhel8/qcow2.go | 10 +- internal/manifest/os.go | 21 ++- 4 files changed, 222 insertions(+), 62 deletions(-) create mode 100644 internal/distro/rhel8/images.go diff --git a/internal/distro/rhel8/images.go b/internal/distro/rhel8/images.go new file mode 100644 index 000000000..1c53f0366 --- /dev/null +++ b/internal/distro/rhel8/images.go @@ -0,0 +1,199 @@ +package rhel8 + +import ( + "math/rand" + + "github.com/osbuild/osbuild-composer/internal/blueprint" + "github.com/osbuild/osbuild-composer/internal/container" + "github.com/osbuild/osbuild-composer/internal/distro" + "github.com/osbuild/osbuild-composer/internal/image" + "github.com/osbuild/osbuild-composer/internal/manifest" + "github.com/osbuild/osbuild-composer/internal/osbuild" + "github.com/osbuild/osbuild-composer/internal/platform" + "github.com/osbuild/osbuild-composer/internal/rpmmd" + "github.com/osbuild/osbuild-composer/internal/users" + "github.com/osbuild/osbuild-composer/internal/workload" +) + +func osCustomizations( + t *imageType, + osPackageSet rpmmd.PackageSet, + options distro.ImageOptions, + containers []container.Spec, + c *blueprint.Customizations, +) manifest.OSCustomizations { + + imageConfig := t.getDefaultImageConfig() + + osc := manifest.OSCustomizations{} + + if t.bootable || t.rpmOstree { + osc.KernelName = c.GetKernel().Name + + var kernelOptions []string + if t.kernelOptions != "" { + kernelOptions = append(kernelOptions, t.kernelOptions) + } + if bpKernel := c.GetKernel(); bpKernel.Append != "" { + kernelOptions = append(kernelOptions, bpKernel.Append) + } + osc.KernelOptionsAppend = kernelOptions + if t.platform.GetArch() != platform.ARCH_S390X { + osc.KernelOptionsBootloader = true + } + } + + osc.ExtraBasePackages = osPackageSet.Include + osc.ExcludeBasePackages = osPackageSet.Exclude + osc.ExtraBaseRepos = osPackageSet.Repositories + + osc.Containers = containers + + osc.GPGKeyFiles = imageConfig.GPGKeyFiles + if imageConfig.ExcludeDocs != nil { + osc.ExcludeDocs = *imageConfig.ExcludeDocs + } + + if !t.bootISO { + // don't put users and groups in the payload of an installer + // add them via kickstart instead + osc.Groups = users.GroupsFromBP(c.GetGroups()) + osc.Users = users.UsersFromBP(c.GetUsers()) + } + + osc.EnabledServices = imageConfig.EnabledServices + osc.DisabledServices = imageConfig.DisabledServices + if imageConfig.DefaultTarget != nil { + osc.DefaultTarget = *imageConfig.DefaultTarget + } + + osc.Firewall = imageConfig.Firewall + if fw := c.GetFirewall(); fw != nil { + options := osbuild.FirewallStageOptions{ + Ports: fw.Ports, + } + + if fw.Services != nil { + options.EnabledServices = fw.Services.Enabled + options.DisabledServices = fw.Services.Disabled + } + if fw.Zones != nil { + for _, z := range fw.Zones { + options.Zones = append(options.Zones, osbuild.FirewallZone{ + Name: *z.Name, + Sources: z.Sources, + }) + } + } + osc.Firewall = &options + } + + language, keyboard := c.GetPrimaryLocale() + if language != nil { + osc.Language = *language + } else if imageConfig.Locale != nil { + osc.Language = *imageConfig.Locale + } + if keyboard != nil { + osc.Keyboard = keyboard + } else if imageConfig.Keyboard != nil { + osc.Keyboard = &imageConfig.Keyboard.Keymap + if imageConfig.Keyboard.X11Keymap != nil { + osc.X11KeymapLayouts = imageConfig.Keyboard.X11Keymap.Layouts + } + } + + if hostname := c.GetHostname(); hostname != nil { + osc.Hostname = *hostname + } + + timezone, ntpServers := c.GetTimezoneSettings() + if timezone != nil { + osc.Timezone = *timezone + } else if imageConfig.Timezone != nil { + osc.Timezone = *imageConfig.Timezone + } + + if len(ntpServers) > 0 { + for _, server := range ntpServers { + osc.NTPServers = append(osc.NTPServers, osbuild.ChronyConfigServer{Hostname: server}) + } + } else if imageConfig.TimeSynchronization != nil { + osc.NTPServers = imageConfig.TimeSynchronization.Servers + osc.LeapSecTZ = imageConfig.TimeSynchronization.LeapsecTz + } + + // Relabel the tree, unless the `NoSElinux` flag is explicitly set to `true` + if imageConfig.NoSElinux == nil || imageConfig.NoSElinux != nil && !*imageConfig.NoSElinux { + osc.SElinux = "targeted" + } + + if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil { + if t.rpmOstree { + panic("unexpected oscap options for ostree image type") + } + osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions( + osbuild.OscapConfig{ + Datastream: oscapConfig.DataStream, + ProfileID: oscapConfig.ProfileID, + }, + ) + } + + if t.arch.distro.isRHEL() && options.Facts != nil { + osc.FactAPIType = options.Facts.ApiType + } + + osc.Grub2Config = imageConfig.Grub2Config + osc.Sysconfig = imageConfig.Sysconfig + osc.SystemdLogind = imageConfig.SystemdLogind + osc.CloudInit = imageConfig.CloudInit + osc.Modprobe = imageConfig.Modprobe + osc.DracutConf = imageConfig.DracutConf + osc.SystemdUnit = imageConfig.SystemdUnit + osc.Authselect = imageConfig.Authselect + osc.SELinuxConfig = imageConfig.SELinuxConfig + osc.Tuned = imageConfig.Tuned + osc.Tmpfilesd = imageConfig.Tmpfilesd + osc.PamLimitsConf = imageConfig.PamLimitsConf + osc.Sysctld = imageConfig.Sysctld + osc.DNFConfig = imageConfig.DNFConfig + osc.DNFAutomaticConfig = imageConfig.DNFAutomaticConfig + osc.YUMRepos = imageConfig.YUMRepos + osc.SshdConfig = imageConfig.SshdConfig + osc.AuthConfig = imageConfig.Authconfig + osc.PwQuality = imageConfig.PwQuality + osc.RHSMConfig = imageConfig.RHSMConfig + osc.Subscription = options.Subscription + osc.WAAgentConfig = imageConfig.WAAgentConfig + osc.UdevRules = imageConfig.UdevRules + osc.GCPGuestAgentConfig = imageConfig.GCPGuestAgentConfig + + return osc +} + +func liveImage(workload workload.Workload, + t *imageType, + customizations *blueprint.Customizations, + options distro.ImageOptions, + packageSets map[string]rpmmd.PackageSet, + containers []container.Spec, + rng *rand.Rand) (image.ImageKind, error) { + + img := image.NewLiveImage() + img.Platform = t.platform + img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations) + img.Environment = t.environment + img.Workload = workload + img.Compression = t.compression + // TODO: move generation into LiveImage + pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) + if err != nil { + return nil, err + } + img.PartitionTable = pt + + img.Filename = t.Filename() + + return img, nil +} diff --git a/internal/distro/rhel8/pipelines.go b/internal/distro/rhel8/pipelines.go index 88e514a4b..4180bd295 100644 --- a/internal/distro/rhel8/pipelines.go +++ b/internal/distro/rhel8/pipelines.go @@ -16,32 +16,6 @@ import ( "github.com/osbuild/osbuild-composer/internal/users" ) -func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, containers []container.Spec, rng *rand.Rand) ([]osbuild.Pipeline, error) { - pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner.String())) - - partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) - if err != nil { - return nil, err - } - - treePipeline, err := osPipeline(t, repos, packageSetSpecs[osPkgsKey], containers, customizations, options, partitionTable) - if err != nil { - return nil, err - } - pipelines = append(pipelines, *treePipeline) - - diskfile := "disk.img" - kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packageSetSpecs[osPkgsKey], customizations.GetKernel().Name) - imagePipeline := liveImagePipeline(treePipeline.Name, diskfile, partitionTable, t.arch, kernelVer) - pipelines = append(pipelines, *imagePipeline) - - qemuPipeline := qemuPipeline(imagePipeline.Name, diskfile, t.filename, osbuild.QEMUFormatQCOW2, osbuild.QCOW2Options{Compat: "0.10"}) - pipelines = append(pipelines, *qemuPipeline) - - return pipelines, nil -} - func prependKernelCmdlineStage(pipeline *osbuild.Pipeline, t *imageType, pt *disk.PartitionTable) *osbuild.Pipeline { if t.Arch().Name() == distro.S390xArchName { rootFs := pt.FindMountable("/") @@ -82,34 +56,6 @@ func vmdkPipelines(t *imageType, customizations *blueprint.Customizations, optio return pipelines, nil } -func openstackPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, containers []container.Spec, rng *rand.Rand) ([]osbuild.Pipeline, error) { - pipelines := make([]osbuild.Pipeline, 0) - pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey], t.arch.distro.runner.String())) - - partitionTable, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng) - if err != nil { - return nil, err - } - - treePipeline, err := osPipeline(t, repos, packageSetSpecs[osPkgsKey], containers, customizations, options, partitionTable) - if err != nil { - return nil, err - } - pipelines = append(pipelines, *treePipeline) - - diskfile := "disk.img" - kernelVer := rpmmd.GetVerStrFromPackageSpecListPanic(packageSetSpecs[osPkgsKey], customizations.GetKernel().Name) - imagePipeline := liveImagePipeline(treePipeline.Name, diskfile, partitionTable, t.arch, kernelVer) - pipelines = append(pipelines, *imagePipeline) - if err != nil { - return nil, err - } - - qemuPipeline := qemuPipeline(imagePipeline.Name, diskfile, t.filename, osbuild.QEMUFormatQCOW2, nil) - pipelines = append(pipelines, *qemuPipeline) - return pipelines, nil -} - func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, containers []container.Spec, rng *rand.Rand, diskfile string) ([]osbuild.Pipeline, error) { diff --git a/internal/distro/rhel8/qcow2.go b/internal/distro/rhel8/qcow2.go index f5aa19873..a77528207 100644 --- a/internal/distro/rhel8/qcow2.go +++ b/internal/distro/rhel8/qcow2.go @@ -14,8 +14,7 @@ func qcow2ImgType(rd distribution) imageType { mimeType: "application/x-qemu-disk", kernelOptions: "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto", packageSets: map[string]packageSetFunc{ - buildPkgsKey: distroBuildPackageSet, - osPkgsKey: qcow2CommonPackageSet, + osPkgsKey: qcow2CommonPackageSet, }, packageSetChains: map[string][]string{ osPkgsKey: {osPkgsKey, blueprintPkgsKey}, @@ -25,7 +24,7 @@ func qcow2ImgType(rd distribution) imageType { }, bootable: true, defaultSize: 10 * common.GibiByte, - pipelines: qcow2Pipelines, + image: liveImage, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "qcow2"}, exports: []string{"qcow2"}, @@ -56,8 +55,7 @@ func openstackImgType() imageType { filename: "disk.qcow2", mimeType: "application/x-qemu-disk", packageSets: map[string]packageSetFunc{ - buildPkgsKey: distroBuildPackageSet, - osPkgsKey: openstackCommonPackageSet, + osPkgsKey: openstackCommonPackageSet, }, packageSetChains: map[string][]string{ osPkgsKey: {osPkgsKey, blueprintPkgsKey}, @@ -65,7 +63,7 @@ func openstackImgType() imageType { kernelOptions: "ro net.ifnames=0", bootable: true, defaultSize: 4 * common.GibiByte, - pipelines: openstackPipelines, + image: liveImage, buildPipelines: []string{"build"}, payloadPipelines: []string{"os", "image", "qcow2"}, exports: []string{"qcow2"}, diff --git a/internal/manifest/os.go b/internal/manifest/os.go index f5a3afba1..f36c824c9 100644 --- a/internal/manifest/os.go +++ b/internal/manifest/os.go @@ -50,6 +50,13 @@ type OSCustomizations struct { // KernelOptionsAppend are appended to the kernel commandline KernelOptionsAppend []string + // KernelOptionsBootloader controls whether kernel command line options + // should be specified in the bootloader configuration. Otherwise they are + // specified in /etc/kernel/cmdline (default). + // This should only be used for RHEL 8 and CentOS 8 images that use grub + // (non s390x). Newer releases (9+) should keep this disabled. + KernelOptionsBootloader bool + GPGKeyFiles []string Language string Keyboard *string @@ -489,7 +496,9 @@ func (p *OS) serialize() osbuild.Pipeline { if pt := p.PartitionTable; pt != nil { kernelOptions := osbuild.GenImageKernelOptions(p.PartitionTable) kernelOptions = append(kernelOptions, p.KernelOptionsAppend...) - pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), pt) + if !p.KernelOptionsBootloader { + pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), pt) + } pipeline.AddStage(osbuild.NewFSTabStage(osbuild.NewFSTabStageOptions(pt))) @@ -498,7 +507,8 @@ func (p *OS) serialize() osbuild.Pipeline { case platform.ARCH_S390X: bootloader = osbuild.NewZiplStage(new(osbuild.ZiplStageOptions)) default: - options := osbuild.NewGrub2StageOptionsUnified(pt, + var options *osbuild.GRUB2StageOptions + options = osbuild.NewGrub2StageOptionsUnified(pt, p.kernelVer, p.platform.GetUEFIVendor() != "", p.platform.GetBIOSPlatform(), @@ -513,6 +523,13 @@ func (p *OS) serialize() osbuild.Pipeline { options.Config = cfg } + if p.KernelOptionsBootloader { + options.WriteCmdLine = nil + if options.UEFI != nil { + options.UEFI.Unified = false + } + options.KernelOptions = strings.Join(kernelOptions, " ") + } bootloader = osbuild.NewGRUB2Stage(options) }