deps: update images to v0.54.0

Update images dependency and adjust import paths for distro package
changes.

Signed-off-by: Achilleas Koutsou <achilleas@koutsou.net>
This commit is contained in:
Achilleas Koutsou 2024-04-10 23:33:18 +02:00 committed by Sanne Raymaekers
parent 356a222b83
commit 809f2544ad
81 changed files with 6722 additions and 5341 deletions

View file

@ -19,6 +19,9 @@ const (
AnssiBp28High Profile = "xccdf_org.ssgproject.content_profile_anssi_bp28_high"
AnssiBp28Intermediary Profile = "xccdf_org.ssgproject.content_profile_anssi_bp28_intermediary"
AnssiBp28Minimal Profile = "xccdf_org.ssgproject.content_profile_anssi_bp28_minimal"
CcnAdvanced Profile = "xccdf_org.ssgproject.content_profile_ccn_advanced"
CcnBasic Profile = "xccdf_org.ssgproject.content_profile_ccn_basic"
CcnIntermediate Profile = "xccdf_org.ssgproject.content_profile_ccn_intermediate"
Cis Profile = "xccdf_org.ssgproject.content_profile_cis"
CisServerL1 Profile = "xccdf_org.ssgproject.content_profile_cis_server_l1"
CisWorkstationL1 Profile = "xccdf_org.ssgproject.content_profile_cis_workstation_l1"

View file

@ -39,6 +39,9 @@ const (
// Added kernel command line options for ami, qcow2, openstack, vhd and vmdk types
cloudKernelOptions = "ro no_timer_check console=ttyS0,115200n8 biosdevname=0 net.ifnames=0"
// Added kernel command line options for iot-raw-image and iot-qcow2-image types
ostreeDeploymentKernelOptions = "modprobe.blacklist=vc4 rw coreos.no_persist_ip"
// location for saving openscap remediation data
oscapDataDir = "/oscap_data"
)
@ -201,6 +204,13 @@ var (
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: iotServices,
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
Locale: common.ToPtr("C.UTF-8"),
OSTreeConfSysrootReadOnly: common.ToPtr(true),
LockRootUser: common.ToPtr(true),
IgnitionPlatform: common.ToPtr("metal"),
},
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
@ -212,6 +222,7 @@ var (
payloadPipelines: []string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
basePartitionTables: iotSimplifiedInstallerPartitionTables,
kernelOptions: ostreeDeploymentKernelOptions,
}
iotRawImgType = imageType{
@ -222,7 +233,13 @@ var (
mimeType: "application/xz",
packageSets: map[string]packageSetFunc{},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
Locale: common.ToPtr("C.UTF-8"),
OSTreeConfSysrootReadOnly: common.ToPtr(true),
LockRootUser: common.ToPtr(true),
IgnitionPlatform: common.ToPtr("metal"),
},
defaultSize: 4 * common.GibiByte,
rpmOstree: true,
@ -232,6 +249,7 @@ var (
payloadPipelines: []string{"ostree-deployment", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: iotBasePartitionTables,
kernelOptions: ostreeDeploymentKernelOptions,
// Passing an empty map into the required partition sizes disables the
// default partition sizes normally set so our `basePartitionTables` can
@ -245,7 +263,13 @@ var (
mimeType: "application/x-qemu-disk",
packageSets: map[string]packageSetFunc{},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
Locale: common.ToPtr("C.UTF-8"),
OSTreeConfSysrootReadOnly: common.ToPtr(true),
LockRootUser: common.ToPtr(true),
IgnitionPlatform: common.ToPtr("qemu"),
},
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
@ -255,6 +279,7 @@ var (
payloadPipelines: []string{"ostree-deployment", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: iotBasePartitionTables,
kernelOptions: ostreeDeploymentKernelOptions,
}
qcow2ImgType = imageType{
@ -413,8 +438,9 @@ type distribution struct {
// Fedora based OS image configuration defaults
var defaultDistroImageConfig = &distro.ImageConfig{
Timezone: common.ToPtr("UTC"),
Locale: common.ToPtr("en_US"),
Timezone: common.ToPtr("UTC"),
Locale: common.ToPtr("en_US"),
DefaultOSCAPDatastream: common.ToPtr(oscap.DefaultFedoraDatastream()),
}
func getISOLabelFunc(variant string) isoLabelFunc {

View file

@ -18,7 +18,6 @@ import (
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/ostree"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/rpmmd"
)
@ -28,7 +27,7 @@ func osCustomizations(
t *imageType,
osPackageSet rpmmd.PackageSet,
containers []container.SourceSpec,
c *blueprint.Customizations) manifest.OSCustomizations {
c *blueprint.Customizations) (manifest.OSCustomizations, error) {
imageConfig := t.getDefaultImageConfig()
@ -193,7 +192,10 @@ func osCustomizations(
var datastream = oscapConfig.DataStream
if datastream == "" {
datastream = oscap.DefaultFedoraDatastream()
if imageConfig.DefaultOSCAPDatastream == nil {
return manifest.OSCustomizations{}, fmt.Errorf("No OSCAP datastream specified and the distro does not have any default set")
}
datastream = *imageConfig.DefaultOSCAPDatastream
}
oscapStageOptions := osbuild.OscapConfig{
@ -256,7 +258,80 @@ func osCustomizations(
osc.Files = append(osc.Files, imageConfig.Files...)
osc.Directories = append(osc.Directories, imageConfig.Directories...)
return osc
return osc, nil
}
func ostreeDeploymentCustomizations(
t *imageType,
c *blueprint.Customizations) (manifest.OSTreeDeploymentCustomizations, error) {
if !t.rpmOstree || !t.bootable {
return manifest.OSTreeDeploymentCustomizations{}, fmt.Errorf("ostree deployment customizations are only supported for bootable rpm-ostree images")
}
imageConfig := t.getDefaultImageConfig()
deploymentConf := manifest.OSTreeDeploymentCustomizations{}
var kernelOptions []string
if t.kernelOptions != "" {
kernelOptions = append(kernelOptions, t.kernelOptions)
}
if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append)
}
if imageConfig.IgnitionPlatform != nil {
deploymentConf.IgnitionPlatform = *imageConfig.IgnitionPlatform
}
switch deploymentConf.IgnitionPlatform {
case "metal":
if bpIgnition := c.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
kernelOptions = append(kernelOptions, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}
}
deploymentConf.KernelOptionsAppend = kernelOptions
deploymentConf.FIPS = c.GetFIPS()
deploymentConf.Users = users.UsersFromBP(c.GetUsers())
deploymentConf.Groups = users.GroupsFromBP(c.GetGroups())
var err error
deploymentConf.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(c.GetDirectories())
if err != nil {
return manifest.OSTreeDeploymentCustomizations{}, err
}
deploymentConf.Files, err = blueprint.FileCustomizationsToFsNodeFiles(c.GetFiles())
if err != nil {
return manifest.OSTreeDeploymentCustomizations{}, err
}
language, keyboard := c.GetPrimaryLocale()
if language != nil {
deploymentConf.Locale = *language
} else if imageConfig.Locale != nil {
deploymentConf.Locale = *imageConfig.Locale
}
if keyboard != nil {
deploymentConf.Keyboard = *keyboard
} else if imageConfig.Keyboard != nil {
deploymentConf.Keyboard = imageConfig.Keyboard.Keymap
}
if imageConfig.OSTreeConfSysrootReadOnly != nil {
deploymentConf.SysrootReadOnly = *imageConfig.OSTreeConfSysrootReadOnly
}
if imageConfig.LockRootUser != nil {
deploymentConf.LockRoot = *imageConfig.LockRootUser
}
for _, fs := range c.GetFilesystems() {
deploymentConf.CustomFileSystems = append(deploymentConf.CustomFileSystems, fs.Mountpoint)
}
return deploymentConf, nil
}
// IMAGES
@ -271,7 +346,13 @@ func diskImage(workload workload.Workload,
img := image.NewDiskImage()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
if err != nil {
return nil, err
}
img.Environment = t.environment
img.Workload = workload
img.Compression = t.compression
@ -301,7 +382,13 @@ func containerImage(workload workload.Workload,
img := image.NewBaseContainer()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
if err != nil {
return nil, err
}
img.Environment = t.environment
img.Workload = workload
@ -373,7 +460,13 @@ func imageInstallerImage(workload workload.Workload,
img.Platform = t.platform
img.Workload = workload
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
if err != nil {
return nil, err
}
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
@ -394,7 +487,6 @@ func imageInstallerImage(workload workload.Workload,
img.Preview = common.VersionGreaterThanOrEqual(img.OSVersion, VERSION_BRANCHED)
var err error
img.ISOLabel, err = t.ISOLabel()
if err != nil {
return nil, err
@ -419,7 +511,12 @@ func iotCommitImage(workload workload.Workload,
d := t.arch.distro
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
if err != nil {
return nil, err
}
// see https://github.com/ostreedev/ostree/issues/2840
img.OSCustomizations.Presets = []osbuild.Preset{
@ -461,7 +558,13 @@ func bootableContainerImage(workload workload.Workload,
d := t.arch.distro
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
if err != nil {
return nil, err
}
img.Environment = t.environment
img.Workload = workload
img.OSTreeParent = parentCommit
@ -485,7 +588,12 @@ func iotContainerImage(workload workload.Workload,
img := image.NewOSTreeContainer(commitRef)
d := t.arch.distro
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
if err != nil {
return nil, err
}
// see https://github.com/ostreedev/ostree/issues/2840
img.OSCustomizations.Presets = []osbuild.Preset{
@ -589,25 +697,11 @@ func iotImage(workload workload.Workload,
img := image.NewOSTreeDiskImageFromCommit(commit)
customizations := bp.Customizations
img.FIPS = customizations.GetFIPS()
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(customizations.GetDirectories())
deploymentConfig, err := ostreeDeploymentCustomizations(t, customizations)
if err != nil {
return nil, err
}
img.Files, err = blueprint.FileCustomizationsToFsNodeFiles(customizations.GetFiles())
if err != nil {
return nil, err
}
img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
img.Keyboard = "us"
img.Locale = "C.UTF-8"
img.SysrootReadOnly = true
img.KernelOptionsAppend = append(img.KernelOptionsAppend, "rw")
img.OSTreeDeploymentCustomizations = deploymentConfig
img.Platform = t.platform
img.Workload = workload
@ -616,22 +710,6 @@ func iotImage(workload workload.Workload,
Name: "fedora-iot",
}
img.OSName = "fedora-iot"
img.LockRoot = true
img.KernelOptionsAppend = append(img.KernelOptionsAppend, "coreos.no_persist_ip")
switch img.Platform.GetImageFormat() {
case platform.FORMAT_RAW:
img.IgnitionPlatform = "metal"
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
img.KernelOptionsAppend = append(img.KernelOptionsAppend, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}
case platform.FORMAT_QCOW2:
img.IgnitionPlatform = "qemu"
}
if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" {
img.KernelOptionsAppend = append(img.KernelOptionsAppend, kopts.Append)
}
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
@ -661,15 +739,11 @@ func iotSimplifiedInstallerImage(workload workload.Workload,
rawImg := image.NewOSTreeDiskImageFromCommit(commit)
customizations := bp.Customizations
rawImg.FIPS = customizations.GetFIPS()
rawImg.Users = users.UsersFromBP(customizations.GetUsers())
rawImg.Groups = users.GroupsFromBP(customizations.GetGroups())
rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
rawImg.Keyboard = "us"
rawImg.Locale = "C.UTF-8"
rawImg.SysrootReadOnly = true
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "rw")
deploymentConfig, err := ostreeDeploymentCustomizations(t, customizations)
if err != nil {
return nil, err
}
rawImg.OSTreeDeploymentCustomizations = deploymentConfig
rawImg.Platform = t.platform
rawImg.Workload = workload
@ -677,13 +751,6 @@ func iotSimplifiedInstallerImage(workload workload.Workload,
Name: "fedora-iot",
}
rawImg.OSName = "fedora"
rawImg.LockRoot = true
rawImg.IgnitionPlatform = "metal"
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "coreos.no_persist_ip")
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
@ -694,10 +761,6 @@ func iotSimplifiedInstallerImage(workload workload.Workload,
rawImg.Filename = t.Filename()
if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" {
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, kopts.Append)
}
img := image.NewOSTreeSimplifiedInstaller(rawImg, customizations.InstallationDevice)
img.ExtraBasePackages = packageSets[installerPkgsKey]
// img.Workload = workload

View file

@ -389,12 +389,20 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return nil, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
dcp := policies.CustomDirectoriesPolicies
fcp := policies.CustomFilesPolicies
if t.rpmOstree {
dcp = policies.OstreeCustomDirectoriesPolicies
fcp = policies.OstreeCustomFilesPolicies
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
if err != nil {
return nil, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
if err != nil {
return nil, err
}

View file

@ -3,22 +3,29 @@ package distro
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"path"
"strings"
)
// variable so that it can be overridden in tests
var getHostDistroNameTree = "/"
// GetHostDistroName returns the name of the host distribution, such as
// "fedora-32" or "rhel-8.2". It does so by reading the /etc/os-release file.
func GetHostDistroName() (string, error) {
f, err := os.Open("/etc/os-release")
osrelease, err := ReadOSReleaseFromTree(getHostDistroNameTree)
if err != nil {
return "", err
return "", fmt.Errorf("cannot get the host distro name: %w", err)
}
defer f.Close()
osrelease, err := readOSRelease(f)
if err != nil {
return "", err
if _, ok := osrelease["ID"]; !ok {
return "", errors.New("cannot get the host distro name: missing ID field in os-release")
}
if _, ok := osrelease["VERSION_ID"]; !ok {
return "", errors.New("cannot get the host distro name: missing VERSION_ID field in os-release")
}
name := osrelease["ID"] + "-" + osrelease["VERSION_ID"]
@ -48,3 +55,25 @@ func readOSRelease(r io.Reader) (map[string]string, error) {
return osrelease, nil
}
// ReadOSReleaseFromTree reads the os-release file from the given root directory.
//
// According to os-release(5), the os-release file should be located in either /etc/os-release or /usr/lib/os-release,
// so both locations are tried, with the former taking precedence.
func ReadOSReleaseFromTree(root string) (map[string]string, error) {
locations := []string{
"etc/os-release",
"usr/lib/os-release",
}
var errs []string
for _, location := range locations {
f, err := os.Open(path.Join(root, location))
if err == nil {
defer f.Close()
return readOSRelease(f)
}
errs = append(errs, fmt.Sprintf("cannot read %s: %v", location, err))
}
return nil, fmt.Errorf("failed to read os-release:\n%s", strings.Join(errs, "\n"))
}

View file

@ -10,7 +10,7 @@ import (
"github.com/osbuild/images/pkg/subscription"
)
// ImageConfig represents a (default) configuration applied to the image
// ImageConfig represents a (default) configuration applied to the image payload.
type ImageConfig struct {
Timezone *string
TimeSynchronization *osbuild.ChronyStageOptions
@ -67,6 +67,29 @@ type ImageConfig struct {
Files []*fsnode.File
Directories []*fsnode.Directory
// KernelOptionsBootloader controls whether kernel command line options
// should be specified in the bootloader grubenv configuration. Otherwise
// they are specified in /etc/kernel/cmdline (default).
//
// This should only be used for old distros that use grub and it is
// applied on all architectures, except for s390x.
KernelOptionsBootloader *bool
// The default OSCAP datastream to use for the image as a fallback,
// if no datastream value is provided by the user.
DefaultOSCAPDatastream *string
// OSTree specific configuration
// Read only sysroot and boot
OSTreeConfSysrootReadOnly *bool
// Lock the root account in the deployment unless the user defined root
// user options in the build configuration.
LockRootUser *bool
IgnitionPlatform *string
}
// InheritFrom inherits unset values from the provided parent configuration and

View file

@ -0,0 +1,9 @@
package distro
// InstallerConfig represents a configuration for the installer
// part of an Installer image type.
type InstallerConfig struct {
// Additional dracut modules and drivers to enable
AdditionalDracutModules []string
AdditionalDrivers []string
}

View file

@ -1,26 +1,31 @@
package rhel8
package rhel
import (
"errors"
"fmt"
"sort"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/platform"
)
type architecture struct {
distro *distribution
name string
type Architecture struct {
distro *Distribution
arch arch.Arch
imageTypes map[string]distro.ImageType
imageTypeAliases map[string]string
}
func (a *architecture) Name() string {
return a.name
func (a *Architecture) Name() string {
return a.arch.String()
}
func (a *architecture) ListImageTypes() []string {
func (a *Architecture) Distro() distro.Distro {
return a.distro
}
func (a *Architecture) ListImageTypes() []string {
itNames := make([]string, 0, len(a.imageTypes))
for name := range a.imageTypes {
itNames = append(itNames, name)
@ -29,7 +34,7 @@ func (a *architecture) ListImageTypes() []string {
return itNames
}
func (a *architecture) GetImageType(name string) (distro.ImageType, error) {
func (a *Architecture) GetImageType(name string) (distro.ImageType, error) {
t, exists := a.imageTypes[name]
if !exists {
aliasForName, exists := a.imageTypeAliases[name]
@ -44,19 +49,16 @@ func (a *architecture) GetImageType(name string) (distro.ImageType, error) {
return t, nil
}
func (a *architecture) addImageTypes(platform platform.Platform, imageTypes ...imageType) {
func (a *Architecture) AddImageTypes(platform platform.Platform, imageTypes ...*ImageType) {
if a.imageTypes == nil {
a.imageTypes = map[string]distro.ImageType{}
}
for idx := range imageTypes {
it := imageTypes[idx]
if _, e := a.imageTypes[it.name]; e {
panic("already added: " + it.name)
}
it.arch = a
it.platform = platform
a.imageTypes[it.name] = &it
for _, alias := range it.nameAliases {
a.imageTypes[it.name] = it
for _, alias := range it.NameAliases {
if a.imageTypeAliases == nil {
a.imageTypeAliases = map[string]string{}
}
@ -68,6 +70,9 @@ func (a *architecture) addImageTypes(platform platform.Platform, imageTypes ...i
}
}
func (a *architecture) Distro() distro.Distro {
return a.distro
func NewArchitecture(distro *Distribution, arch arch.Arch) *Architecture {
return &Architecture{
distro: distro,
arch: arch,
}
}

View file

@ -0,0 +1,8 @@
package rhel
const (
// location for saving openscap remediation data
oscapDataDir = "/oscap_data"
UEFIVendor = "redhat"
)

View file

@ -0,0 +1,141 @@
package rhel
import (
"errors"
"fmt"
"sort"
"strings"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/runner"
)
// DefaultDistroImageConfigFunc is a function that returns the default image
// configuration for a distribution.
type DefaultDistroImageConfigFunc func(d *Distribution) *distro.ImageConfig
type Distribution struct {
name string
product string
osVersion string
releaseVersion string
modulePlatformID string
vendor string
ostreeRefTmpl string
runner runner.Runner
arches map[string]distro.Arch
DefaultImageConfig DefaultDistroImageConfigFunc
// distro specific function to check options per image type
CheckOptions CheckOptionsFunc
}
func (d *Distribution) Name() string {
return d.name
}
func (d *Distribution) Releasever() string {
return d.releaseVersion
}
func (d *Distribution) OsVersion() string {
return d.osVersion
}
func (d *Distribution) Product() string {
return d.product
}
func (d *Distribution) ModulePlatformID() string {
return d.modulePlatformID
}
func (d *Distribution) OSTreeRef() string {
return d.ostreeRefTmpl
}
func (d *Distribution) Vendor() string {
return d.vendor
}
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")
}
func (d *Distribution) GetDefaultImageConfig() *distro.ImageConfig {
if d.DefaultImageConfig == nil {
return nil
}
return d.DefaultImageConfig(d)
}
func NewDistribution(name string, major, minor int) (*Distribution, error) {
var rd *Distribution
switch name {
case "rhel":
if minor == -1 {
return nil, errors.New("RHEL requires a minor version")
}
rd = &Distribution{
name: fmt.Sprintf("rhel-%d.%d", major, minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("%d.%d", major, minor),
releaseVersion: fmt.Sprintf("%d", major),
modulePlatformID: fmt.Sprintf("platform:el%d", major),
vendor: "redhat",
ostreeRefTmpl: fmt.Sprintf("rhel/%d/%%s/edge", major),
runner: &runner.RHEL{Major: uint64(major), Minor: uint64(minor)},
}
case "centos":
if minor != -1 {
return nil, fmt.Errorf("CentOS does not have minor versions, but got %d", minor)
}
rd = &Distribution{
name: fmt.Sprintf("centos-%d", major),
product: "CentOS Stream",
osVersion: fmt.Sprintf("%d-stream", major),
releaseVersion: fmt.Sprintf("%d", major),
modulePlatformID: fmt.Sprintf("platform:el%d", major),
vendor: "centos",
ostreeRefTmpl: fmt.Sprintf("centos/%d/%%s/edge", major),
runner: &runner.CentOS{Version: uint64(major)},
}
default:
return nil, fmt.Errorf("unknown distro name: %s", name)
}
return rd, nil
}

View file

@ -1,11 +1,10 @@
package rhel8
package rhel
import (
"fmt"
"math/rand"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/fdo"
@ -22,30 +21,30 @@ import (
)
func osCustomizations(
t *imageType,
t *ImageType,
osPackageSet rpmmd.PackageSet,
options distro.ImageOptions,
containers []container.SourceSpec,
c *blueprint.Customizations,
) manifest.OSCustomizations {
) (manifest.OSCustomizations, error) {
imageConfig := t.getDefaultImageConfig()
osc := manifest.OSCustomizations{}
if t.bootable || t.rpmOstree {
if t.Bootable || t.RPMOSTree {
osc.KernelName = c.GetKernel().Name
var kernelOptions []string
if t.kernelOptions != "" {
kernelOptions = append(kernelOptions, t.kernelOptions)
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() != arch.ARCH_S390X {
osc.KernelOptionsBootloader = true
if imageConfig.KernelOptionsBootloader != nil {
osc.KernelOptionsBootloader = *imageConfig.KernelOptionsBootloader
}
}
@ -62,7 +61,7 @@ func osCustomizations(
osc.ExcludeDocs = *imageConfig.ExcludeDocs
}
if !t.bootISO {
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())
@ -137,7 +136,7 @@ func osCustomizations(
osc.SElinux = "targeted"
}
if t.arch.distro.isRHEL() && options.Facts != nil {
if t.IsRHEL() && options.Facts != nil {
osc.FactAPIType = &options.Facts.APIType
}
@ -160,7 +159,7 @@ func osCustomizations(
// deployment, rather than the commit. Therefore the containers need to be
// stored in a different location, like `/usr/share`, and the container
// storage engine configured accordingly.
if t.rpmOstree && len(containers) > 0 {
if t.RPMOSTree && len(containers) > 0 {
storagePath := "/usr/share/containers/storage"
osc.ContainersStorage = &storagePath
}
@ -199,7 +198,7 @@ func osCustomizations(
}
if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil {
if t.rpmOstree {
if t.RPMOSTree {
panic("unexpected oscap options for ostree image type")
}
@ -214,7 +213,10 @@ func osCustomizations(
var datastream = oscapConfig.DataStream
if datastream == "" {
datastream = oscap.DefaultRHEL8Datastream(t.arch.distro.isRHEL())
if imageConfig.DefaultOSCAPDatastream == nil {
return manifest.OSCustomizations{}, fmt.Errorf("No OSCAP datastream specified and the distro does not have any default set")
}
datastream = *imageConfig.DefaultOSCAPDatastream
}
oscapStageOptions := osbuild.OscapConfig{
@ -283,11 +285,85 @@ func osCustomizations(
osc.Files = append(osc.Files, imageConfig.Files...)
osc.Directories = append(osc.Directories, imageConfig.Directories...)
return osc
return osc, nil
}
func diskImage(workload workload.Workload,
t *imageType,
func ostreeDeploymentCustomizations(
t *ImageType,
c *blueprint.Customizations) (manifest.OSTreeDeploymentCustomizations, error) {
if !t.RPMOSTree || !t.Bootable {
return manifest.OSTreeDeploymentCustomizations{}, fmt.Errorf("ostree deployment customizations are only supported for bootable rpm-ostree images")
}
imageConfig := t.getDefaultImageConfig()
deploymentConf := manifest.OSTreeDeploymentCustomizations{}
var kernelOptions []string
if t.KernelOptions != "" {
kernelOptions = append(kernelOptions, t.KernelOptions)
}
if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append)
}
if imageConfig.IgnitionPlatform != nil {
deploymentConf.IgnitionPlatform = *imageConfig.IgnitionPlatform
}
switch deploymentConf.IgnitionPlatform {
case "metal":
if bpIgnition := c.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
kernelOptions = append(kernelOptions, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}
}
deploymentConf.KernelOptionsAppend = kernelOptions
deploymentConf.FIPS = c.GetFIPS()
deploymentConf.Users = users.UsersFromBP(c.GetUsers())
deploymentConf.Groups = users.GroupsFromBP(c.GetGroups())
var err error
deploymentConf.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(c.GetDirectories())
if err != nil {
return manifest.OSTreeDeploymentCustomizations{}, err
}
deploymentConf.Files, err = blueprint.FileCustomizationsToFsNodeFiles(c.GetFiles())
if err != nil {
return manifest.OSTreeDeploymentCustomizations{}, err
}
language, keyboard := c.GetPrimaryLocale()
if language != nil {
deploymentConf.Locale = *language
} else if imageConfig.Locale != nil {
deploymentConf.Locale = *imageConfig.Locale
}
if keyboard != nil {
deploymentConf.Keyboard = *keyboard
} else if imageConfig.Keyboard != nil {
deploymentConf.Keyboard = imageConfig.Keyboard.Keymap
}
if imageConfig.OSTreeConfSysrootReadOnly != nil {
deploymentConf.SysrootReadOnly = *imageConfig.OSTreeConfSysrootReadOnly
}
if imageConfig.LockRootUser != nil {
deploymentConf.LockRoot = *imageConfig.LockRootUser
}
for _, fs := range c.GetFilesystems() {
deploymentConf.CustomFileSystems = append(deploymentConf.CustomFileSystems, fs.Mountpoint)
}
return deploymentConf, nil
}
func DiskImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
@ -296,12 +372,18 @@ func diskImage(workload workload.Workload,
img := image.NewDiskImage()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[OSPkgsKey], options, containers, customizations)
if err != nil {
return nil, err
}
img.Environment = t.Environment
img.Workload = workload
img.Compression = t.compression
img.Compression = t.Compression
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
@ -312,75 +394,8 @@ func diskImage(workload workload.Workload,
return img, nil
}
func imageInstallerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewAnacondaTarInstaller()
img.Platform = t.platform
img.Workload = workload
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.AdditionalDracutModules = []string{"prefixdevname", "prefixdevname-tools"}
img.AdditionalAnacondaModules = []string{"org.fedoraproject.Anaconda.Modules.Users"}
if instCust := customizations.GetInstaller(); instCust != nil {
img.NoPasswd = instCust.SudoNopasswd
img.UnattendedKickstart = instCust.Unattended
}
img.SquashfsCompression = "xz"
// put the kickstart file in the root of the iso
img.ISORootKickstart = true
var err error
img.ISOLabel, err = t.ISOLabel()
if err != nil {
return nil, err
}
d := t.arch.distro
img.Product = d.product
img.OSName = "redhat"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.Filename = t.Filename()
return img, nil
}
func tarImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewArchive()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
img.Workload = workload
img.Filename = t.Filename()
return img, nil
}
func edgeCommitImage(workload workload.Workload,
t *imageType,
func EdgeCommitImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
@ -391,18 +406,24 @@ func edgeCommitImage(workload workload.Workload,
img := image.NewOSTreeArchive(commitRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[OSPkgsKey], options, containers, customizations)
if err != nil {
return nil, err
}
img.Environment = t.Environment
img.Workload = workload
img.OSTreeParent = parentCommit
img.OSVersion = t.arch.distro.osVersion
img.OSVersion = t.Arch().Distro().OsVersion()
img.Filename = t.Filename()
return img, nil
}
func edgeContainerImage(workload workload.Workload,
t *imageType,
func EdgeContainerImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
@ -413,28 +434,32 @@ func edgeContainerImage(workload workload.Workload,
img := image.NewOSTreeContainer(commitRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[OSPkgsKey], options, containers, customizations)
if err != nil {
return nil, err
}
img.ContainerLanguage = img.OSCustomizations.Language
img.Environment = t.environment
img.Environment = t.Environment
img.Workload = workload
img.OSTreeParent = parentCommit
img.OSVersion = t.arch.distro.osVersion
img.ExtraContainerPackages = packageSets[containerPkgsKey]
img.OSVersion = t.Arch().Distro().OsVersion()
img.ExtraContainerPackages = packageSets[ContainerPkgsKey]
img.Filename = t.Filename()
return img, nil
}
func edgeInstallerImage(workload workload.Workload,
t *imageType,
func EdgeInstallerImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
d := t.arch.distro
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
if err != nil {
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
@ -443,7 +468,7 @@ func edgeInstallerImage(workload workload.Workload,
img := image.NewAnacondaOSTreeInstaller(commit)
img.Platform = t.platform
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.ExtraBasePackages = packageSets[InstallerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
@ -458,7 +483,16 @@ func edgeInstallerImage(workload workload.Workload,
}
img.SquashfsCompression = "xz"
img.AdditionalDracutModules = []string{"prefixdevname", "prefixdevname-tools"}
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = installerConfig.AdditionalDracutModules
img.AdditionalDrivers = installerConfig.AdditionalDrivers
}
if len(img.Users)+len(img.Groups) > 0 {
// only enable the users module if needed
@ -470,11 +504,11 @@ func edgeInstallerImage(workload workload.Workload,
return nil, err
}
img.Product = d.product
img.Product = t.Arch().Distro().Product()
img.Variant = "edge"
img.OSName = "rhel"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.OSVersion = t.Arch().Distro().OsVersion()
img.Release = fmt.Sprintf("%s %s", t.Arch().Distro().Product(), t.Arch().Distro().OsVersion())
img.FIPS = customizations.GetFIPS()
img.Filename = t.Filename()
@ -482,8 +516,8 @@ func edgeInstallerImage(workload workload.Workload,
return img, nil
}
func edgeRawImage(workload workload.Workload,
t *imageType,
func EdgeRawImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
@ -494,17 +528,13 @@ func edgeRawImage(workload workload.Workload,
if err != nil {
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
}
img := image.NewOSTreeDiskImageFromCommit(commit)
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.FIPS = customizations.GetFIPS()
img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
// TODO: move to image config
img.Keyboard = "us"
img.Locale = "C.UTF-8"
deploymentConfig, err := ostreeDeploymentCustomizations(t, customizations)
if err != nil {
return nil, err
}
img.OSTreeDeploymentCustomizations = deploymentConfig
img.Platform = t.platform
img.Workload = workload
@ -514,23 +544,22 @@ func edgeRawImage(workload workload.Workload,
ContentURL: options.OSTree.ContentURL,
}
img.OSName = "redhat"
img.LockRoot = true
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
img.PartitionTable = pt
img.Filename = t.Filename()
img.Compression = t.compression
img.Compression = t.Compression
return img, nil
}
func edgeSimplifiedInstallerImage(workload workload.Workload,
t *imageType,
func EdgeSimplifiedInstallerImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
@ -541,16 +570,13 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
if err != nil {
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
}
rawImg := image.NewOSTreeDiskImageFromCommit(commit)
rawImg.Users = users.UsersFromBP(customizations.GetUsers())
rawImg.Groups = users.GroupsFromBP(customizations.GetGroups())
rawImg.FIPS = customizations.GetFIPS()
rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
rawImg.Keyboard = "us"
rawImg.Locale = "C.UTF-8"
deploymentConfig, err := ostreeDeploymentCustomizations(t, customizations)
if err != nil {
return nil, err
}
rawImg.OSTreeDeploymentCustomizations = deploymentConfig
rawImg.Platform = t.platform
rawImg.Workload = workload
@ -560,10 +586,9 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
ContentURL: options.OSTree.ContentURL,
}
rawImg.OSName = "redhat"
rawImg.LockRoot = true
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
@ -572,7 +597,7 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
rawImg.Filename = t.Filename()
img := image.NewOSTreeSimplifiedInstaller(rawImg, customizations.InstallationDevice)
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.ExtraBasePackages = packageSets[InstallerPkgsKey]
// img.Workload = workload
img.Platform = t.platform
img.Filename = t.Filename()
@ -581,9 +606,6 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
}
// ignition configs from blueprint
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil {
if bpIgnition.FirstBoot != nil {
img.IgnitionFirstBoot = ignition.FirstbootOptionsFromBP(*bpIgnition.FirstBoot)
}
if bpIgnition.Embedded != nil {
var err error
img.IgnitionEmbedded, err = ignition.EmbeddedOptionsFromBP(*bpIgnition.Embedded)
@ -603,11 +625,106 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
img.Variant = "edge"
img.OSName = "redhat"
img.OSVersion = d.osVersion
img.AdditionalDracutModules = []string{"prefixdevname", "prefixdevname-tools"}
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = installerConfig.AdditionalDracutModules
}
return img, nil
}
func ImageInstallerImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewAnacondaTarInstaller()
img.Platform = t.platform
img.Workload = workload
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[OSPkgsKey], options, containers, customizations)
if err != nil {
return nil, err
}
img.ExtraBasePackages = packageSets[InstallerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = installerConfig.AdditionalDracutModules
img.AdditionalDrivers = installerConfig.AdditionalDrivers
}
img.AdditionalAnacondaModules = []string{"org.fedoraproject.Anaconda.Modules.Users"}
if instCust := customizations.GetInstaller(); instCust != nil {
img.NoPasswd = instCust.SudoNopasswd
img.UnattendedKickstart = instCust.Unattended
}
img.SquashfsCompression = "xz"
// put the kickstart file in the root of the iso
img.ISORootKickstart = true
img.ISOLabel, err = t.ISOLabel()
if err != nil {
return nil, err
}
d := t.arch.distro
img.Product = d.product
img.OSName = "redhat"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.Filename = t.Filename()
return img, nil
}
func TarImage(workload workload.Workload,
t *ImageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewArchive()
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[OSPkgsKey], options, containers, customizations)
if err != nil {
return nil, err
}
img.Environment = t.Environment
img.Workload = workload
img.Filename = t.Filename()
return img, nil
}
// Create an ostree SourceSpec to define an ostree parent commit using the user
// options and the default ref for the image type. Additionally returns the
// ref to be used for the new commit to be created.
@ -663,13 +780,3 @@ func makeOSTreePayloadCommit(options *ostree.ImageOptions, defaultRef string) (o
RHSM: options.RHSM,
}, nil
}
// initialSetupKickstart returns the File configuration for a kickstart file
// that's required to enable initial-setup to run on first boot.
func initialSetupKickstart() *fsnode.File {
file, err := fsnode.NewFile("/root/anaconda-ks.cfg", nil, "root", "root", []byte("# Run initial-setup on first boot\n# Created by osbuild\nfirstboot --reconfig\nlang en_US.UTF-8\n"))
if err != nil {
panic(err)
}
return file
}

View file

@ -0,0 +1,352 @@
package rhel
import (
"fmt"
"math/rand"
"golang.org/x/exp/slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/rpmmd"
)
const (
// package set names
// build package set name
BuildPkgsKey = "build"
// main/common os image package set name
OSPkgsKey = "os"
// container package set name
ContainerPkgsKey = "container"
// installer package set name
InstallerPkgsKey = "installer"
// blueprint package set name
BlueprintPkgsKey = "blueprint"
)
type ImageFunc func(workload workload.Workload, t *ImageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error)
type PackageSetFunc func(t *ImageType) rpmmd.PackageSet
type BasePartitionTableFunc func(t *ImageType) (disk.PartitionTable, bool)
type ISOLabelFunc func(t *ImageType) string
type CheckOptionsFunc func(t *ImageType, bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error)
type ImageType struct {
// properties, which are part of the distro.ImageType interface or are used by all images
name string
filename string
mimeType string
packageSets map[string]PackageSetFunc
buildPipelines []string
payloadPipelines []string
exports []string
image ImageFunc
// properties which can't be set when defining the image type
arch *Architecture
platform platform.Platform
Environment environment.Environment
Workload workload.Workload
NameAliases []string
Compression string // TODO: remove from image definition and make it a transport option
DefaultImageConfig *distro.ImageConfig
DefaultInstallerConfig *distro.InstallerConfig
KernelOptions string
DefaultSize uint64
// bootISO: installable ISO
BootISO bool
// rpmOstree: edge/ostree
RPMOSTree bool
// bootable image
Bootable bool
// List of valid arches for the image type
BasePartitionTables BasePartitionTableFunc
// Optional list of unsupported partitioning modes
UnsupportedPartitioningModes []disk.PartitioningMode
ISOLabelFn ISOLabelFunc
}
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 ""
}
// IsRHEL returns true if the image type is part of a RHEL distribution
//
// This is a convenience method, because external packages can't get the
// information from t.Arch().Distro(), since the distro.Distro interface
// does not have this method. And since the distro.Distro interface is
// distro-agnostic, it does not make much sense to have a method like this
// in the interface.
func (t *ImageType) IsRHEL() bool {
return t.arch.distro.IsRHEL()
}
func (t *ImageType) ISOLabel() (string, error) {
if !t.BootISO {
return "", fmt.Errorf("image type %q is not an ISO", t.name)
}
if t.ISOLabelFn != nil {
return t.ISOLabelFn(t), nil
}
return "", nil
}
func (t *ImageType) Size(size uint64) uint64 {
// Microsoft Azure requires vhd images to be rounded up to the nearest MB
if t.name == "vhd" && size%common.MebiByte != 0 {
size = (size/common.MebiByte + 1) * common.MebiByte
}
if size == 0 {
size = t.DefaultSize
}
return size
}
func (t *ImageType) BuildPipelines() []string {
return t.buildPipelines
}
func (t *ImageType) PayloadPipelines() []string {
return t.payloadPipelines
}
func (t *ImageType) PayloadPackageSets() []string {
return []string{BlueprintPkgsKey}
}
func (t *ImageType) PackageSetsChains() map[string][]string {
return nil
}
func (t *ImageType) Exports() []string {
if len(t.exports) > 0 {
return t.exports
}
return []string{"assembler"}
}
func (t *ImageType) BootMode() distro.BootMode {
if t.platform.GetUEFIVendor() != "" && t.platform.GetBIOSPlatform() != "" {
return distro.BOOT_HYBRID
} else if t.platform.GetUEFIVendor() != "" {
return distro.BOOT_UEFI
} else if t.platform.GetBIOSPlatform() != "" || t.platform.GetZiplSupport() {
return distro.BOOT_LEGACY
}
return distro.BOOT_NONE
}
func (t *ImageType) GetPartitionTable(
mountpoints []blueprint.FilesystemCustomization,
options distro.ImageOptions,
rng *rand.Rand,
) (*disk.PartitionTable, error) {
archName := t.arch.Name()
basePartitionTable, exists := t.BasePartitionTables(t)
if !exists {
return nil, fmt.Errorf("no partition table defined for architecture %q for image type %q", archName, t.Name())
}
imageSize := t.Size(options.Size)
return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, options.PartitioningMode, nil, rng)
}
func (t *ImageType) getDefaultImageConfig() *distro.ImageConfig {
// ensure that image always returns non-nil default config
imageConfig := t.DefaultImageConfig
if imageConfig == nil {
imageConfig = &distro.ImageConfig{}
}
return imageConfig.InheritFrom(t.arch.distro.GetDefaultImageConfig())
}
func (t *ImageType) getDefaultInstallerConfig() (*distro.InstallerConfig, error) {
if !t.BootISO {
return nil, fmt.Errorf("image type %q is not an ISO", t.name)
}
return t.DefaultInstallerConfig, nil
}
func (t *ImageType) PartitionType() string {
basePartitionTable, exists := t.BasePartitionTables(t)
if !exists {
return ""
}
return basePartitionTable.Type
}
func (t *ImageType) Manifest(bp *blueprint.Blueprint,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
seed int64) (*manifest.Manifest, []string, error) {
if t.Workload != nil {
// For now, if an image type defines its own workload, don't allow any
// user customizations.
// Soon we will have more workflows and each will define its allowed
// set of customizations. The current set of customizations defined in
// the blueprint spec corresponds to the Custom workflow.
if bp.Customizations != nil {
return nil, nil, fmt.Errorf(distro.NoCustomizationsAllowedError, t.Name())
}
}
warnings, err := t.checkOptions(bp, options)
if err != nil {
return nil, nil, err
}
// merge package sets that appear in the image type with the package sets
// of the same name from the distro and arch
staticPackageSets := make(map[string]rpmmd.PackageSet)
for name, getter := range t.packageSets {
staticPackageSets[name] = getter(t)
}
// amend with repository information and collect payload repos
payloadRepos := make([]rpmmd.RepoConfig, 0)
for _, repo := range repos {
if len(repo.PackageSets) > 0 {
// only apply the repo to the listed package sets
for _, psName := range repo.PackageSets {
if slices.Contains(t.PayloadPackageSets(), psName) {
payloadRepos = append(payloadRepos, repo)
}
ps := staticPackageSets[psName]
ps.Repositories = append(ps.Repositories, repo)
staticPackageSets[psName] = ps
}
}
}
w := t.Workload
if w == nil {
cw := &workload.Custom{
BaseWorkload: workload.BaseWorkload{
Repos: payloadRepos,
},
Packages: bp.GetPackagesEx(false),
}
if services := bp.Customizations.GetServices(); services != nil {
cw.Services = services.Enabled
cw.DisabledServices = services.Disabled
}
w = cw
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
Local: cont.LocalStorage,
}
}
source := rand.NewSource(seed)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(source)
img, err := t.image(w, t, bp.Customizations, options, staticPackageSets, containerSources, rng)
if err != nil {
return nil, nil, err
}
mf := manifest.New()
switch t.Arch().Distro().Releasever() {
case "8":
mf.Distro = manifest.DISTRO_EL8
case "9":
mf.Distro = manifest.DISTRO_EL9
case "10":
mf.Distro = manifest.DISTRO_EL10
default:
return nil, nil, fmt.Errorf("unsupported distro release version: %s", t.Arch().Distro().Releasever())
}
_, err = img.InstantiateManifest(&mf, repos, t.arch.distro.runner, rng)
if err != nil {
return nil, nil, err
}
return &mf, warnings, err
}
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func (t *ImageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
if t.arch.distro.CheckOptions != nil {
return t.arch.distro.CheckOptions(t, bp, options)
}
return nil, nil
}
func NewImageType(
name, filename, mimeType string,
pkgSets map[string]PackageSetFunc,
imgFunc ImageFunc,
buildPipelines, payloadPipelines, exports []string,
) *ImageType {
return &ImageType{
name: name,
filename: filename,
mimeType: mimeType,
packageSets: pkgSets,
image: imgFunc,
buildPipelines: buildPipelines,
payloadPipelines: payloadPipelines,
exports: exports,
}
}

View file

@ -0,0 +1,286 @@
package rhel10
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
// TODO: move these to the EC2 environment
const amiKernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295"
// default EC2 images config (common for all architectures)
func baseEc2ImageConfig() *distro.ImageConfig {
return &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
Timezone: common.ToPtr("UTC"),
TimeSynchronization: &osbuild.ChronyStageOptions{
Servers: []osbuild.ChronyConfigServer{
{
Hostname: "169.254.169.123",
Prefer: common.ToPtr(true),
Iburst: common.ToPtr(true),
Minpoll: common.ToPtr(4),
Maxpoll: common.ToPtr(4),
},
},
// empty string will remove any occurrences of the option from the configuration
LeapsecTz: common.ToPtr(""),
},
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
X11Keymap: &osbuild.X11KeymapOptions{
Layouts: []string{"us"},
},
},
EnabledServices: []string{
"sshd",
"NetworkManager",
"nm-cloud-setup.service",
"nm-cloud-setup.timer",
"cloud-init",
"cloud-init-local",
"cloud-config",
"cloud-final",
"reboot.target",
"tuned",
},
DefaultTarget: common.ToPtr("multi-user.target"),
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
NetworkScripts: &osbuild.NetworkScriptsOptions{
IfcfgFiles: map[string]osbuild.IfcfgFile{
"eth0": {
Device: "eth0",
Bootproto: osbuild.IfcfgBootprotoDHCP,
OnBoot: common.ToPtr(true),
Type: osbuild.IfcfgTypeEthernet,
UserCtl: common.ToPtr(true),
PeerDNS: common.ToPtr(true),
IPv6Init: common.ToPtr(false),
},
},
},
},
},
SystemdLogind: []*osbuild.SystemdLogindStageOptions{
{
Filename: "00-getty-fixes.conf",
Config: osbuild.SystemdLogindConfigDropin{
Login: osbuild.SystemdLogindConfigLoginSection{
NAutoVTs: common.ToPtr(0),
},
},
},
},
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "00-rhel-default-user.cfg",
Config: osbuild.CloudInitConfigFile{
SystemInfo: &osbuild.CloudInitConfigSystemInfo{
DefaultUser: &osbuild.CloudInitConfigDefaultUser{
Name: "ec2-user",
},
},
},
},
},
Modprobe: []*osbuild.ModprobeStageOptions{
{
Filename: "blacklist-nouveau.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("nouveau"),
},
},
{
Filename: "blacklist-amdgpu.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("amdgpu"),
},
},
},
// COMPOSER-1807
DracutConf: []*osbuild.DracutConfStageOptions{
{
Filename: "sgdisk.conf",
Config: osbuild.DracutConfigFile{
Install: []string{"sgdisk"},
},
},
},
SystemdUnit: []*osbuild.SystemdUnitStageOptions{
// RHBZ#1822863
{
Unit: "nm-cloud-setup.service",
Dropin: "10-rh-enable-for-ec2.conf",
Config: osbuild.SystemdServiceUnitDropin{
Service: &osbuild.SystemdUnitServiceSection{
Environment: "NM_CLOUD_SETUP_EC2=yes",
},
},
},
},
Authselect: &osbuild.AuthselectStageOptions{
Profile: "sssd",
},
SshdConfig: &osbuild.SshdConfigStageOptions{
Config: osbuild.SshdConfigConfig{
PasswordAuthentication: common.ToPtr(false),
},
},
}
}
// Default AMI (custom image built by users) images config.
// The configuration does not touch the RHSM configuration at all.
// https://issues.redhat.com/browse/COMPOSER-2157
func defaultAMIImageConfig() *distro.ImageConfig {
return baseEc2ImageConfig()
}
// Default AMI x86_64 (custom image built by users) images config.
// The configuration does not touch the RHSM configuration at all.
// https://issues.redhat.com/browse/COMPOSER-2157
func defaultAMIImageConfigX86_64() *distro.ImageConfig {
ic := defaultAMIImageConfig()
return appendEC2DracutX86_64(ic)
}
// common ec2 image build package set
func ec2BuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return distroBuildPackageSet(t).Append(
rpmmd.PackageSet{
Include: []string{
"python3-pyyaml",
},
})
}
func ec2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"cloud-utils-growpart",
"dhcp-client",
"yum-utils",
"dracut-config-generic",
"gdisk",
"grub2",
"langpacks-en",
"NetworkManager-cloud-setup",
"redhat-release",
"redhat-release-eula",
"rsync",
"tuned",
"tar",
},
Exclude: []string{
"aic94xx-firmware",
"alsa-firmware",
"alsa-tools-firmware",
"biosdevname",
"firewalld",
"iprutils",
"ivtv-firmware",
"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",
"libertas-sd8686-firmware",
"libertas-sd8787-firmware",
"libertas-usb8388-firmware",
"plymouth",
// RHBZ#2064087
"dracut-config-rescue",
// RHBZ#2075815
"qemu-guest-agent",
},
}.Append(distroSpecificPackageSet(t))
return ps
}
func mkAMIImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.KernelOptions = amiKernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultAMIImageConfigX86_64()
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkAMIImgTypeAarch64() *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
map[string]rhel.PackageSetFunc{
rhel.BuildPkgsKey: ec2BuildPackageSet,
rhel.OSPkgsKey: ec2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0"
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultAMIImageConfig()
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func appendEC2DracutX86_64(ic *distro.ImageConfig) *distro.ImageConfig {
ic.DracutConf = append(ic.DracutConf,
&osbuild.DracutConfStageOptions{
Filename: "ec2.conf",
Config: osbuild.DracutConfigFile{
AddDrivers: []string{
"nvme",
"xen-blkfront",
},
},
})
return ic
}

View file

@ -0,0 +1,303 @@
package rhel10
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
// Azure non-RHEL image type
func mkAzureImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// Azure BYOS image type
func mkAzureByosImgType(rd distro.Distro) *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// PACKAGE SETS
// Common Azure image package set
func azureCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@Server",
"bzip2",
"cloud-init",
"cloud-utils-growpart",
"dracut-config-generic",
"efibootmgr",
"gdisk",
"hyperv-daemons",
"kernel-core",
"kernel-modules",
"kernel",
"langpacks-en",
"lvm2",
"NetworkManager",
"NetworkManager-cloud-setup",
"nvme-cli",
"patch",
"rng-tools",
"selinux-policy-targeted",
"uuid",
"WALinuxAgent",
"yum-utils",
},
Exclude: []string{
"aic94xx-firmware",
"alsa-firmware",
"alsa-lib",
"alsa-sof-firmware",
"alsa-tools-firmware",
"biosdevname",
"bolt",
"buildah",
"cockpit-podman",
"containernetworking-plugins",
"dnf-plugin-spacewalk",
"dracut-config-rescue",
"glibc-all-langpacks",
"iprutils",
"ivtv-firmware",
"iwl100-firmware",
"iwl1000-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",
"libertas-sd8686-firmware",
"libertas-sd8787-firmware",
"libertas-usb8388-firmware",
"NetworkManager-config-server",
"plymouth",
"podman",
"python3-dnf-plugin-spacewalk",
"python3-hwdata",
"python3-rhnlib",
"rhn-check",
"rhn-client-tools",
"rhn-setup",
"rhnlib",
"rhnsd",
"usb_modeswitch",
},
}.Append(distroSpecificPackageSet(t))
return ps
}
// Azure BYOS image package set
func azurePackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return azureCommonPackageSet(t)
}
// IMAGE CONFIG
// use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT
const defaultAzureKernelOptions = "ro loglevel=3 console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300"
// based on https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/deploying_rhel_9_on_microsoft_azure/assembly_deploying-a-rhel-image-as-a-virtual-machine-on-microsoft-azure_cloud-content-azure#making-configuration-changes_configure-the-image-azure
var defaultAzureImageConfig = &distro.ImageConfig{
Timezone: common.ToPtr("Etc/UTC"),
Locale: common.ToPtr("en_US.UTF-8"),
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
X11Keymap: &osbuild.X11KeymapOptions{
Layouts: []string{"us"},
},
},
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel-core",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
EnabledServices: []string{
"firewalld",
"nm-cloud-setup.service",
"nm-cloud-setup.timer",
"sshd",
"waagent",
},
SshdConfig: &osbuild.SshdConfigStageOptions{
Config: osbuild.SshdConfigConfig{
ClientAliveInterval: common.ToPtr(180),
},
},
Modprobe: []*osbuild.ModprobeStageOptions{
{
Filename: "blacklist-amdgpu.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("amdgpu"),
},
},
{
Filename: "blacklist-intel-cstate.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("intel_cstate"),
},
},
{
Filename: "blacklist-floppy.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("floppy"),
},
},
{
Filename: "blacklist-nouveau.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("nouveau"),
osbuild.NewModprobeConfigCmdBlacklist("lbm-nouveau"),
},
},
{
Filename: "blacklist-skylake-edac.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("skx_edac"),
},
},
},
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "10-azure-kvp.cfg",
Config: osbuild.CloudInitConfigFile{
Reporting: &osbuild.CloudInitConfigReporting{
Logging: &osbuild.CloudInitConfigReportingHandlers{
Type: "log",
},
Telemetry: &osbuild.CloudInitConfigReportingHandlers{
Type: "hyperv",
},
},
},
},
{
Filename: "91-azure_datasource.cfg",
Config: osbuild.CloudInitConfigFile{
Datasource: &osbuild.CloudInitConfigDatasource{
Azure: &osbuild.CloudInitConfigDatasourceAzure{
ApplyNetworkConfig: false,
},
},
DatasourceList: []string{
"Azure",
},
},
},
},
PwQuality: &osbuild.PwqualityConfStageOptions{
Config: osbuild.PwqualityConfConfig{
Minlen: common.ToPtr(6),
Minclass: common.ToPtr(3),
Dcredit: common.ToPtr(0),
Ucredit: common.ToPtr(0),
Lcredit: common.ToPtr(0),
Ocredit: common.ToPtr(0),
},
},
WAAgentConfig: &osbuild.WAAgentConfStageOptions{
Config: osbuild.WAAgentConfig{
RDFormat: common.ToPtr(false),
RDEnableSwap: common.ToPtr(false),
},
},
Grub2Config: &osbuild.GRUB2Config{
DisableRecovery: common.ToPtr(true),
DisableSubmenu: common.ToPtr(true),
Distributor: "$(sed 's, release .*$,,g' /etc/system-release)",
Terminal: []string{"serial", "console"},
Serial: "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1",
Timeout: 10,
TimeoutStyle: osbuild.GRUB2ConfigTimeoutStyleCountdown,
},
UdevRules: &osbuild.UdevRulesStageOptions{
Filename: "/etc/udev/rules.d/68-azure-sriov-nm-unmanaged.rules",
Rules: osbuild.UdevRules{
osbuild.UdevRuleComment{
Comment: []string{
"Accelerated Networking on Azure exposes a new SRIOV interface to the VM.",
"This interface is transparently bonded to the synthetic interface,",
"so NetworkManager should just ignore any SRIOV interfaces.",
},
},
osbuild.NewUdevRule(
[]osbuild.UdevKV{
{K: "SUBSYSTEM", O: "==", V: "net"},
{K: "DRIVERS", O: "==", V: "hv_pci"},
{K: "ACTION", O: "==", V: "add"},
{K: "ENV", A: "NM_UNMANAGED", O: "=", V: "1"},
},
),
},
},
SystemdUnit: []*osbuild.SystemdUnitStageOptions{
{
Unit: "nm-cloud-setup.service",
Dropin: "10-rh-enable-for-azure.conf",
Config: osbuild.SystemdServiceUnitDropin{
Service: &osbuild.SystemdUnitServiceSection{
Environment: "NM_CLOUD_SETUP_AZURE=yes",
},
},
},
},
DefaultTarget: common.ToPtr("multi-user.target"),
}

View file

@ -0,0 +1,26 @@
package rhel10
import (
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
func mkTarImgType() *rhel.ImageType {
return rhel.NewImageType(
"tar",
"root.tar.xz",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{"policycoreutils", "selinux-policy-targeted"},
Exclude: []string{"rng-tools"},
}
},
},
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
}

View file

@ -0,0 +1,264 @@
package rhel10
import (
"fmt"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
)
var (
// rhel9 & cs9 share the same list
// of allowed profiles so a single
// allow list can be used
oscapProfileAllowList = []oscap.Profile{
oscap.AnssiBp28Enhanced,
oscap.AnssiBp28High,
oscap.AnssiBp28Intermediary,
oscap.AnssiBp28Minimal,
oscap.Cis,
oscap.CisServerL1,
oscap.CisWorkstationL1,
oscap.CisWorkstationL2,
oscap.Cui,
oscap.E8,
oscap.Hippa,
oscap.IsmO,
oscap.Ospp,
oscap.PciDss,
oscap.Stig,
oscap.StigGui,
}
)
func defaultDistroImageConfig(d *rhel.Distribution) *distro.ImageConfig {
return &distro.ImageConfig{
Timezone: common.ToPtr("America/New_York"),
Locale: common.ToPtr("C.UTF-8"),
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
}
}
func newDistro(name string, major, minor int) *rhel.Distribution {
rd, err := rhel.NewDistribution(name, major, minor)
if err != nil {
panic(err)
}
rd.CheckOptions = checkOptions
rd.DefaultImageConfig = defaultDistroImageConfig
// Architecture definitions
x86_64 := rhel.NewArchitecture(rd, arch.ARCH_X86_64)
aarch64 := rhel.NewArchitecture(rd, arch.ARCH_AARCH64)
ppc64le := rhel.NewArchitecture(rd, arch.ARCH_PPC64LE)
s390x := rhel.NewArchitecture(rd, arch.ARCH_S390X)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
mkOCIImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
mkOpenstackImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
mkVMDKImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_OVA,
},
},
mkOVAImgType(),
)
x86_64.AddImageTypes(
&platform.X86{},
mkTarImgType(),
mkWSLImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
mkOpenstackImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{},
mkTarImgType(),
mkWSLImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{},
mkTarImgType(),
)
s390x.AddImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
)
s390x.AddImageTypes(
&platform.S390X{},
mkTarImgType(),
)
ec2X86Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
x86_64.AddImageTypes(
ec2X86Platform,
mkAMIImgTypeX86_64(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
mkAMIImgTypeAarch64(),
)
azureX64Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
azureAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
if rd.IsRHEL() { // RHEL-only (non-CentOS) image types
x86_64.AddImageTypes(azureX64Platform, mkAzureByosImgType(rd))
aarch64.AddImageTypes(azureAarch64Platform, mkAzureByosImgType(rd))
} else {
x86_64.AddImageTypes(azureX64Platform, mkAzureImgType())
aarch64.AddImageTypes(azureAarch64Platform, mkAzureImgType())
}
rd.AddArches(x86_64, aarch64, ppc64le, s390x)
return rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
if id.MajorVersion != 10 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, 10, id.MinorVersion)
}

View file

@ -0,0 +1,92 @@
package rhel10
import (
"fmt"
"log"
"golang.org/x/exp/slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/policies"
)
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
customizations := bp.Customizations
// holds warnings (e.g. deprecation notices)
var warnings []string
if slices.Contains(t.UnsupportedPartitioningModes, options.PartitioningMode) {
return warnings, fmt.Errorf("partitioning mode %q is not supported for %q", options.PartitioningMode, t.Name())
}
mountpoints := customizations.GetFilesystems()
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
if osc := customizations.GetOpenSCAP(); osc != nil {
if !oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList) {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported profile: %s", osc.ProfileID))
}
if osc.ProfileID == "" {
return warnings, fmt.Errorf("OpenSCAP profile cannot be empty")
}
}
// Check Directory/File Customizations are valid
dc := customizations.GetDirectories()
fc := customizations.GetFiles()
err = blueprint.ValidateDirFileCustomizations(dc, fc)
if err != nil {
return warnings, err
}
dcp := policies.CustomDirectoriesPolicies
fcp := policies.CustomFilesPolicies
if t.RPMOSTree {
dcp = policies.OstreeCustomDirectoriesPolicies
fcp = policies.OstreeCustomFilesPolicies
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
if err != nil {
return warnings, err
}
// check if repository customizations are valid
_, err = customizations.GetRepositories()
if err != nil {
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetInstaller() != nil {
// only supported by the Anaconda installer
if slices.Index([]string{"image-installer", "edge-installer", "live-installer"}, t.Name()) == -1 {
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.Name())
}
}
return warnings, nil
}

View file

@ -0,0 +1,78 @@
package rhel10
// This file defines package sets that are used by more than one image type.
import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
// BUILD PACKAGE SETS
// distro-wide build package set
func distroBuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"dnf",
"dosfstools",
"e2fsprogs",
"glibc",
"lorax-templates-generic",
"lorax-templates-rhel",
"lvm2",
"policycoreutils",
"python3-iniparse",
"qemu-img",
"selinux-policy-targeted",
"systemd",
"tar",
"xfsprogs",
"xz",
},
}
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664BuildPackageSet(t))
case arch.ARCH_PPC64LE.String():
ps = ps.Append(ppc64leBuildPackageSet(t))
}
return ps
}
// x86_64 build package set
func x8664BuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2-pc",
},
}
}
// ppc64le build package set
func ppc64leBuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2-ppc64le",
"grub2-ppc64le-modules",
},
}
}
// OS package sets
// packages that are only in some (sub)-distributions
func distroSpecificPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
if t.IsRHEL() {
return rpmmd.PackageSet{
Include: []string{
"insights-client",
},
}
}
return rpmmd.PackageSet{}
}

View file

@ -0,0 +1,179 @@
package rhel10
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro/rhel"
)
func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 200 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 1 * common.GibiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 200 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 1 * common.GibiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
case arch.ARCH_PPC64LE.String():
return disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
Partitions: []disk.Partition{
{
Size: 4 * common.MebiByte,
Type: "41",
Bootable: true,
},
{
Size: 1 * common.GibiByte,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * common.GibiByte,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
case arch.ARCH_S390X.String():
return disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
Partitions: []disk.Partition{
{
Size: 1 * common.GibiByte,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * common.GibiByte,
Bootable: true,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
default:
return disk.PartitionTable{}, false
}
}

View file

@ -0,0 +1,200 @@
package rhel10
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
)
func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"qcow2",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0"
it.DefaultSize = 10 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"oci",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0"
it.DefaultSize = 10 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOpenstackImgType() *rhel.ImageType {
it := rhel.NewImageType(
"openstack",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: openstackCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
}
it.KernelOptions = "ro net.ifnames=0"
it.DefaultSize = 4 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func qcow2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"cloud-utils-growpart",
"cockpit-system",
"cockpit-ws",
"dnf-utils",
"dosfstools",
"nfs-utils",
"oddjob",
"oddjob-mkhomedir",
"psmisc",
"python3-jsonschema",
"qemu-guest-agent",
"redhat-release",
"redhat-release-eula",
"rsync",
"tar",
"tuned",
"tcpdump",
},
Exclude: []string{
"aic94xx-firmware",
"alsa-firmware",
"alsa-lib",
"alsa-tools-firmware",
"biosdevname",
"dnf-plugin-spacewalk",
"dracut-config-rescue",
"fedora-release",
"fedora-repos",
"firewalld",
"iprutils",
"ivtv-firmware",
"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",
"langpacks-*",
"langpacks-en",
"libertas-sd8787-firmware",
"nss",
"plymouth",
"rng-tools",
"udisks2",
},
}.Append(distroSpecificPackageSet(t))
// Ensure to not pull in subscription-manager on non-RHEL distro
if t.IsRHEL() {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"subscription-manager-cockpit",
},
})
}
return ps
}
func openstackCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
// Defaults
"@core",
"langpacks-en",
"tuned",
// From the lorax kickstart
"cloud-init",
"qemu-guest-agent",
"spice-vdagent",
},
Exclude: []string{
"dracut-config-rescue",
"rng-tools",
},
}
return ps
}
func qcowImageConfig(d *rhel.Distribution) *distro.ImageConfig {
ic := &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"),
}
if d.IsRHEL() {
ic.RHSMConfig = map[subscription.RHSMStatus]*osbuild.RHSMStageOptions{
subscription.RHSMConfigNoSubscription: {
DnfPlugins: &osbuild.RHSMStageOptionsDnfPlugins{
ProductID: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
SubscriptionManager: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
},
},
}
}
return ic
}

View file

@ -0,0 +1,96 @@
package rhel10
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
func mkWSLImgType() *rhel.ImageType {
it := rhel.NewImageType(
"wsl",
"disk.tar.gz",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ubiCommonPackageSet,
},
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{
Boot: osbuild.WSLConfBootOptions{
Systemd: true,
},
},
}
return it
}
func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"alternatives",
"audit-libs",
"basesystem",
"bash",
"ca-certificates",
"coreutils-single",
"crypto-policies-scripts",
"curl-minimal",
"dejavu-sans-fonts",
"dnf",
"filesystem",
"findutils",
"gdb-gdbserver",
// Differs from official UBI, as we don't include CRB repos
// "gdbm",
"glibc-minimal-langpack",
"gmp",
"gnupg2",
"gobject-introspection",
"hostname",
"langpacks-en",
"libcurl-minimal",
"openssl",
"pam",
"passwd",
"procps-ng",
"python3",
"python3-inotify",
"redhat-release",
"rootfiles",
"rpm",
"sed",
"setup",
"shadow-utils",
"subscription-manager",
"systemd",
"tar",
"tpm2-tss",
"tzdata",
"util-linux",
"vim-minimal",
"yum",
},
Exclude: []string{
"gawk-all-langpacks",
"glibc-gconv-extra",
"glibc-langpack-en",
"openssl-pkcs11",
"python-unversioned-command",
"redhat-release-eula",
"rpm-plugin-systemd-inhibit",
},
}
return ps
}

View file

@ -0,0 +1,80 @@
package rhel10
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
const vmdkKernelOptions = "ro net.ifnames=0"
func mkVMDKImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vmdk",
"disk.vmdk",
"application/x-vmdk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk"},
[]string{"vmdk"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
}
it.KernelOptions = vmdkKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOVAImgType() *rhel.ImageType {
it := rhel.NewImageType(
"ova",
"image.ova",
"application/ovf",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk", "ovf", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
}
it.KernelOptions = vmdkKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func vmdkCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"firewalld",
"langpacks-en",
"open-vm-tools",
"tuned",
},
Exclude: []string{
"dracut-config-rescue",
"rng-tools",
},
}
return ps
}

View file

@ -3,139 +3,157 @@ package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
)
func amiImgTypeX86_64(rd distribution) imageType {
it := imageType{
name: "ami",
filename: "image.raw",
mimeType: "application/octet-stream",
packageSets: map[string]packageSetFunc{
osPkgsKey: ec2CommonPackageSet,
const (
amiX86KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto"
amiAarch64KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0 crashkernel=auto"
amiSapKernelOptions = "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"
)
func mkAmiImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2CommonPackageSet,
},
defaultImageConfig: defaultAMIImageConfigX86_64(),
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image"},
exports: []string{"image"},
basePartitionTables: getEc2PartitionTables(rd.osVersion, rd.isRHEL()),
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.DefaultImageConfig = defaultAMIImageConfigX86_64()
it.KernelOptions = amiX86KernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
func ec2ImgTypeX86_64(rd distribution) imageType {
it := imageType{
name: "ec2",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: rhelEc2PackageSet,
func mkEc2ImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2PackageSet,
},
defaultImageConfig: defaultEc2ImageConfigX86_64(rd),
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: getEc2PartitionTables(rd.osVersion, rd.isRHEL()),
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultEc2ImageConfigX86_64(rd)
it.KernelOptions = amiX86KernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
func ec2HaImgTypeX86_64(rd distribution) imageType {
it := imageType{
name: "ec2-ha",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: rhelEc2HaPackageSet,
func mkEc2HaImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2-ha",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2HaPackageSet,
},
defaultImageConfig: defaultEc2ImageConfigX86_64(rd),
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: getEc2PartitionTables(rd.osVersion, rd.isRHEL()),
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultEc2ImageConfigX86_64(rd)
it.KernelOptions = amiX86KernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
func amiImgTypeAarch64(rd distribution) imageType {
it := imageType{
name: "ami",
filename: "image.raw",
mimeType: "application/octet-stream",
packageSets: map[string]packageSetFunc{
osPkgsKey: ec2CommonPackageSet,
func mkAmiImgTypeAarch64() *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2CommonPackageSet,
},
defaultImageConfig: defaultAMIImageConfig(),
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 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image"},
exports: []string{"image"},
basePartitionTables: getEc2PartitionTables(rd.osVersion, rd.isRHEL()),
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.DefaultImageConfig = defaultAMIImageConfig()
it.KernelOptions = amiAarch64KernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
func ec2ImgTypeAarch64(rd distribution) imageType {
it := imageType{
name: "ec2",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: rhelEc2PackageSet,
func mkEc2ImgTypeAarch64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2PackageSet,
},
defaultImageConfig: defaultEc2ImageConfig(rd),
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 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: getEc2PartitionTables(rd.osVersion, rd.isRHEL()),
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultEc2ImageConfig(rd)
it.KernelOptions = amiAarch64KernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
func ec2SapImgTypeX86_64(rd distribution) imageType {
it := imageType{
name: "ec2-sap",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: rhelEc2SapPackageSet,
func mkEc2SapImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2-sap",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2SapPackageSet,
},
defaultImageConfig: defaultEc2SapImageConfigX86_64(rd),
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,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: getEc2PartitionTables(rd.osVersion, rd.isRHEL()),
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultEc2SapImageConfigX86_64(rd)
it.KernelOptions = amiSapKernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
@ -267,11 +285,11 @@ func baseEc2ImageConfig() *distro.ImageConfig {
}
}
func defaultEc2ImageConfig(rd distribution) *distro.ImageConfig {
func defaultEc2ImageConfig(rd *rhel.Distribution) *distro.ImageConfig {
ic := baseEc2ImageConfig()
// The RHSM configuration should not be applied since 8.7, but it is instead done by installing the
// redhat-cloud-client-configuration package. See COMPOSER-1804 for more information.
if rd.isRHEL() && common.VersionLessThan(rd.osVersion, "8.7") {
if rd.IsRHEL() && common.VersionLessThan(rd.OsVersion(), "8.7") {
ic = appendRHSM(ic)
// Disable RHSM redhat.repo management
rhsmConf := ic.RHSMConfig[subscription.RHSMConfigNoSubscription]
@ -282,7 +300,7 @@ func defaultEc2ImageConfig(rd distribution) *distro.ImageConfig {
return ic
}
func defaultEc2ImageConfigX86_64(rd distribution) *distro.ImageConfig {
func defaultEc2ImageConfigX86_64(rd *rhel.Distribution) *distro.ImageConfig {
ic := defaultEc2ImageConfig(rd)
return appendEC2DracutX86_64(ic)
}
@ -302,13 +320,13 @@ func defaultAMIImageConfigX86_64() *distro.ImageConfig {
return appendEC2DracutX86_64(ic)
}
func defaultEc2SapImageConfigX86_64(rd distribution) *distro.ImageConfig {
func defaultEc2SapImageConfigX86_64(rd *rhel.Distribution) *distro.ImageConfig {
// default EC2-SAP image config (x86_64)
return sapImageConfig(rd).InheritFrom(defaultEc2ImageConfigX86_64(rd))
}
// common package set for RHEL (BYOS/RHUI) and CentOS Stream images
func ec2CommonPackageSet(t *imageType) rpmmd.PackageSet {
func ec2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",
@ -365,17 +383,17 @@ func ec2CommonPackageSet(t *imageType) rpmmd.PackageSet {
}
// common rhel ec2 RHUI image package set
func rhelEc2CommonPackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := ec2CommonPackageSet(t)
// Include "redhat-cloud-client-configuration" on 8.7+ (COMPOSER-1804)
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "8.7") {
if common.VersionGreaterThanOrEqual(t.Arch().Distro().OsVersion(), "8.7") {
ps.Include = append(ps.Include, "redhat-cloud-client-configuration")
}
return ps
}
// rhel-ec2 image package set
func rhelEc2PackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2PackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ec2PackageSet := rhelEc2CommonPackageSet(t)
ec2PackageSet.Include = append(ec2PackageSet.Include, "rh-amazon-rhui-client")
ec2PackageSet.Exclude = append(ec2PackageSet.Exclude, "alsa-lib")
@ -383,7 +401,7 @@ func rhelEc2PackageSet(t *imageType) rpmmd.PackageSet {
}
// rhel-ha-ec2 image package set
func rhelEc2HaPackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2HaPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ec2HaPackageSet := rhelEc2CommonPackageSet(t)
ec2HaPackageSet.Include = append(ec2HaPackageSet.Include,
"fence-agents-all",
@ -398,7 +416,7 @@ func rhelEc2HaPackageSet(t *imageType) rpmmd.PackageSet {
// rhel-sap-ec2 image package set
// Includes the common ec2 package set, the common SAP packages, and
// the amazon rhui sap package
func rhelEc2SapPackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2SapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rh-amazon-rhui-client-sap-bundle-e4s",

View file

@ -6,6 +6,7 @@ import (
"github.com/osbuild/images/pkg/customizations/shell"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
@ -14,115 +15,130 @@ import (
// use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT
const defaultAzureKernelOptions = "ro loglevel=3 crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300"
func azureRhuiImgType() imageType {
return imageType{
name: "azure-rhui",
filename: "disk.vhd.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: azureRhuiPackageSet,
func mkAzureRhuiImgType() *rhel.ImageType {
it := rhel.NewImageType(
"azure-rhui",
"disk.vhd.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azureRhuiPackageSet,
},
defaultImageConfig: defaultAzureRhuiImageConfig.InheritFrom(defaultVhdImageConfig()),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 64 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc", "xz"},
exports: []string{"xz"},
basePartitionTables: azureRhuiBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(defaultVhdImageConfig())
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 64 * common.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables
return it
}
func azureSapRhuiImgType(rd distribution) imageType {
return imageType{
name: "azure-sap-rhui",
filename: "disk.vhd.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: azureSapPackageSet,
func mkAzureSapRhuiImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"azure-sap-rhui",
"disk.vhd.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azureSapPackageSet,
},
defaultImageConfig: defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd)),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 64 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc", "xz"},
exports: []string{"xz"},
basePartitionTables: azureRhuiBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd))
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 64 * common.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables
return it
}
func azureByosImgType() imageType {
return imageType{
name: "vhd",
filename: "disk.vhd",
mimeType: "application/x-vhd",
packageSets: map[string]packageSetFunc{
osPkgsKey: azurePackageSet,
func mkAzureByosImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet,
},
defaultImageConfig: defaultAzureByosImageConfig.InheritFrom(defaultVhdImageConfig()),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc"},
exports: []string{"vpc"},
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
it.DefaultImageConfig = defaultAzureByosImageConfig.InheritFrom(defaultVhdImageConfig())
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// Azure non-RHEL image type
func azureImgType() imageType {
return imageType{
name: "vhd",
filename: "disk.vhd",
mimeType: "application/x-vhd",
packageSets: map[string]packageSetFunc{
osPkgsKey: azurePackageSet,
func mkAzureImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet,
},
defaultImageConfig: defaultVhdImageConfig(),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc"},
exports: []string{"vpc"},
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
it.DefaultImageConfig = defaultVhdImageConfig()
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func azureEap7RhuiImgType() imageType {
return imageType{
name: "azure-eap7-rhui",
workload: eapWorkload(),
filename: "disk.vhd.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: azureEapPackageSet,
func mkAzureEap7RhuiImgType() *rhel.ImageType {
it := rhel.NewImageType(
"azure-eap7-rhui",
"disk.vhd.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azureEapPackageSet,
},
defaultImageConfig: defaultAzureEapImageConfig.InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig)),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 64 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc", "xz"},
exports: []string{"xz"},
basePartitionTables: azureRhuiBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = defaultAzureEapImageConfig.InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig))
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 64 * common.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables
it.Workload = eapWorkload()
return it
}
// PACKAGE SETS
// Common Azure image package set
func azureCommonPackageSet(t *imageType) rpmmd.PackageSet {
func azureCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@Server",
@ -199,7 +215,7 @@ func azureCommonPackageSet(t *imageType) rpmmd.PackageSet {
},
}.Append(distroSpecificPackageSet(t))
if t.arch.distro.isRHEL() {
if t.IsRHEL() {
ps.Append(rpmmd.PackageSet{
Include: []string{
"insights-client",
@ -212,7 +228,7 @@ func azureCommonPackageSet(t *imageType) rpmmd.PackageSet {
}
// Azure BYOS image package set
func azurePackageSet(t *imageType) rpmmd.PackageSet {
func azurePackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"firewalld",
@ -224,7 +240,7 @@ func azurePackageSet(t *imageType) rpmmd.PackageSet {
}
// Azure RHUI image package set
func azureRhuiPackageSet(t *imageType) rpmmd.PackageSet {
func azureRhuiPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"firewalld",
@ -239,7 +255,7 @@ func azureRhuiPackageSet(t *imageType) rpmmd.PackageSet {
// Azure SAP image package set
// Includes the common azure package set, the common SAP packages, and
// the azure rhui sap package.
func azureSapPackageSet(t *imageType) rpmmd.PackageSet {
func azureSapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"firewalld",
@ -248,7 +264,7 @@ func azureSapPackageSet(t *imageType) rpmmd.PackageSet {
}.Append(azureCommonPackageSet(t)).Append(SapPackageSet(t))
}
func azureEapPackageSet(t *imageType) rpmmd.PackageSet {
func azureEapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rhui-azure-rhel8",
@ -261,217 +277,225 @@ func azureEapPackageSet(t *imageType) rpmmd.PackageSet {
// PARTITION TABLES
var azureRhuiBasePartitionTables = distro.BasePartitionTableMap{
arch.ARCH_X86_64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Size: 64 * common.GibiByte,
Partitions: []disk.Partition{
{
Size: 500 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
func azureRhuiBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Size: 64 * common.GibiByte,
Partitions: []disk.Partition{
{
Size: 500 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
},
{
Size: 500 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 500 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 2 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Type: disk.LVMPartitionGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LVMVolumeGroup{
Name: "rootvg",
Description: "built with lvm2 and osbuild",
LogicalVolumes: []disk.LVMLogicalVolume{
{
Size: 1 * common.GibiByte,
Name: "homelv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "home",
Mountpoint: "/home",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 2 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Type: disk.LVMPartitionGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LVMVolumeGroup{
Name: "rootvg",
Description: "built with lvm2 and osbuild",
LogicalVolumes: []disk.LVMLogicalVolume{
{
Size: 1 * common.GibiByte,
Name: "homelv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "home",
Mountpoint: "/home",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 2 * common.GibiByte,
Name: "rootlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 2 * common.GibiByte,
Name: "rootlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 2 * common.GibiByte,
Name: "tmplv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "tmp",
Mountpoint: "/tmp",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 2 * common.GibiByte,
Name: "tmplv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "tmp",
Mountpoint: "/tmp",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 10 * common.GibiByte,
Name: "usrlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "usr",
Mountpoint: "/usr",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 10 * common.GibiByte,
Name: "usrlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "usr",
Mountpoint: "/usr",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 10 * common.GibiByte,
Name: "varlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "var",
Mountpoint: "/var",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 10 * common.GibiByte,
Name: "varlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "var",
Mountpoint: "/var",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
},
},
},
arch.ARCH_AARCH64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Size: 64 * common.GibiByte,
Partitions: []disk.Partition{
{
Size: 500 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
}, true
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Size: 64 * common.GibiByte,
Partitions: []disk.Partition{
{
Size: 500 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
},
{
Size: 500 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 500 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Type: disk.LVMPartitionGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LVMVolumeGroup{
Name: "rootvg",
Description: "built with lvm2 and osbuild",
LogicalVolumes: []disk.LVMLogicalVolume{
{
Size: 1 * common.GibiByte,
Name: "homelv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "home",
Mountpoint: "/home",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Type: disk.LVMPartitionGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LVMVolumeGroup{
Name: "rootvg",
Description: "built with lvm2 and osbuild",
LogicalVolumes: []disk.LVMLogicalVolume{
{
Size: 1 * common.GibiByte,
Name: "homelv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "home",
Mountpoint: "/home",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 2 * common.GibiByte,
Name: "rootlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 2 * common.GibiByte,
Name: "rootlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 2 * common.GibiByte,
Name: "tmplv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "tmp",
Mountpoint: "/tmp",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 2 * common.GibiByte,
Name: "tmplv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "tmp",
Mountpoint: "/tmp",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 10 * common.GibiByte,
Name: "usrlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "usr",
Mountpoint: "/usr",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 10 * common.GibiByte,
Name: "usrlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "usr",
Mountpoint: "/usr",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
{
Size: 10 * common.GibiByte,
Name: "varlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "var",
Mountpoint: "/var",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
{
Size: 10 * common.GibiByte,
Name: "varlv",
Payload: &disk.Filesystem{
Type: "xfs",
Label: "var",
Mountpoint: "/var",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
},
},
},
}, true
default:
return disk.PartitionTable{}, false
}
}
// based on https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/deploying_rhel_8_on_microsoft_azure/assembly_deploying-a-rhel-image-as-a-virtual-machine-on-microsoft-azure_cloud-content-azure#making-configuration-changes_configure-the-image-azure
@ -699,6 +723,6 @@ func defaultVhdImageConfig() *distro.ImageConfig {
return imageConfig.InheritFrom(defaultAzureImageConfig)
}
func sapAzureImageConfig(rd distribution) *distro.ImageConfig {
func sapAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig {
return sapImageConfig(rd).InheritFrom(defaultVhdImageConfig())
}

View file

@ -4,50 +4,63 @@ import (
"fmt"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
func imageInstaller() imageType {
return imageType{
name: "image-installer",
filename: "installer.iso",
mimeType: "application/x-iso9660-image",
packageSets: map[string]packageSetFunc{
osPkgsKey: bareMetalPackageSet,
installerPkgsKey: anacondaPackageSet,
func mkImageInstaller() *rhel.ImageType {
it := rhel.NewImageType(
"image-installer",
"installer.iso",
"application/x-iso9660-image",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: bareMetalPackageSet,
rhel.InstallerPkgsKey: anacondaPackageSet,
},
rhel.ImageInstallerImage,
[]string{"build"},
[]string{"anaconda-tree", "rootfs-image", "efiboot-tree", "os", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
it.BootISO = true
it.Bootable = true
it.ISOLabelFn = distroISOLabelFunc
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"prefixdevname",
"prefixdevname-tools",
},
rpmOstree: false,
bootISO: true,
bootable: true,
image: imageInstallerImage,
isoLabel: distroISOLabelFunc,
buildPipelines: []string{"build"},
payloadPipelines: []string{"anaconda-tree", "rootfs-image", "efiboot-tree", "os", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
}
return it
}
func tarImgType() imageType {
return imageType{
name: "tar",
filename: "root.tar.xz",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: func(t *imageType) rpmmd.PackageSet {
func mkTarImgType() *rhel.ImageType {
it := rhel.NewImageType(
"tar",
"root.tar.xz",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{"policycoreutils", "selinux-policy-targeted"},
Exclude: []string{"rng-tools"},
}
},
},
image: tarImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "archive"},
exports: []string{"archive"},
}
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
return it
}
func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
func bareMetalPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
@ -98,7 +111,7 @@ func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
}.Append(distroSpecificPackageSet(t))
// Ensure to not pull in subscription-manager on non-RHEL distro
if t.arch.distro.isRHEL() {
if t.IsRHEL() {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"subscription-manager-cockpit",
@ -109,7 +122,7 @@ func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func installerPackageSet(t *imageType) rpmmd.PackageSet {
func installerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"anaconda-dracut",
@ -146,7 +159,7 @@ func installerPackageSet(t *imageType) rpmmd.PackageSet {
},
}
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
@ -158,7 +171,7 @@ func installerPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
func anacondaPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
// common installer packages
ps := installerPackageSet(t)
@ -278,7 +291,7 @@ func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
ps = ps.Append(anacondaBootPackageSet(t))
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
@ -296,7 +309,7 @@ func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
})
default:
panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name()))
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps

View file

@ -0,0 +1,462 @@
package rhel8
import (
"fmt"
"strings"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
)
var (
// rhel8 allow all
oscapProfileAllowList = []oscap.Profile{
oscap.AnssiBp28Enhanced,
oscap.AnssiBp28High,
oscap.AnssiBp28Intermediary,
oscap.AnssiBp28Minimal,
oscap.Cis,
oscap.CisServerL1,
oscap.CisWorkstationL1,
oscap.CisWorkstationL2,
oscap.Cui,
oscap.E8,
oscap.Hippa,
oscap.IsmO,
oscap.Ospp,
oscap.PciDss,
oscap.Stig,
oscap.StigGui,
}
)
// RHEL-based OS image configuration defaults
func defaultDistroImageConfig(d *rhel.Distribution) *distro.ImageConfig {
return &distro.ImageConfig{
Timezone: common.ToPtr("America/New_York"),
Locale: common.ToPtr("en_US.UTF-8"),
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
KernelOptionsBootloader: common.ToPtr(true),
DefaultOSCAPDatastream: common.ToPtr(oscap.DefaultRHEL8Datastream(d.IsRHEL())),
}
}
func distroISOLabelFunc(t *rhel.ImageType) string {
const RHEL_ISO_LABEL = "RHEL-%s-%s-0-BaseOS-%s"
const CS_ISO_LABEL = "CentOS-Stream-%s-%s-dvd"
if t.IsRHEL() {
osVer := strings.Split(t.Arch().Distro().OsVersion(), ".")
return fmt.Sprintf(RHEL_ISO_LABEL, osVer[0], osVer[1], t.Arch().Name())
} else {
return fmt.Sprintf(CS_ISO_LABEL, t.Arch().Distro().Releasever(), t.Arch().Name())
}
}
func newDistro(name string, minor int) *rhel.Distribution {
rd, err := rhel.NewDistribution(name, 8, minor)
if err != nil {
panic(err)
}
rd.CheckOptions = checkOptions
rd.DefaultImageConfig = defaultDistroImageConfig
// Architecture definitions
x86_64 := rhel.NewArchitecture(rd, arch.ARCH_X86_64)
aarch64 := rhel.NewArchitecture(rd, arch.ARCH_AARCH64)
ppc64le := rhel.NewArchitecture(rd, arch.ARCH_PPC64LE)
s390x := rhel.NewArchitecture(rd, arch.ARCH_S390X)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
mkQcow2ImgType(rd),
mkOCIImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
mkOpenstackImgType(),
)
ec2X86Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
x86_64.AddImageTypes(
ec2X86Platform,
mkAmiImgTypeX86_64(),
)
bareMetalX86Platform := &platform.X86{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"microcode_ctl", // ??
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6050-firmware",
},
},
BIOS: true,
UEFIVendor: rd.Vendor(),
}
x86_64.AddImageTypes(
bareMetalX86Platform,
mkEdgeOCIImgType(rd),
mkEdgeCommitImgType(rd),
mkEdgeInstallerImgType(rd),
mkImageInstaller(),
)
gceX86Platform := &platform.X86{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_GCE,
},
}
x86_64.AddImageTypes(
gceX86Platform,
mkGceImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
mkVmdkImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_OVA,
},
},
mkOvaImgType(),
)
x86_64.AddImageTypes(
&platform.X86{},
mkTarImgType(),
mkWslImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
mkQcow2ImgType(rd),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
mkOpenstackImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{},
mkTarImgType(),
mkWslImgType(),
)
bareMetalAarch64Platform := &platform.Aarch64{
BasePlatform: platform.BasePlatform{},
UEFIVendor: rd.Vendor(),
}
aarch64.AddImageTypes(
bareMetalAarch64Platform,
mkEdgeOCIImgType(rd),
mkEdgeCommitImgType(rd),
mkEdgeInstallerImgType(rd),
mkImageInstaller(),
)
rawAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
aarch64.AddImageTypes(
rawAarch64Platform,
mkAmiImgTypeAarch64(),
mkMinimalRawImgType(),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
mkQcow2ImgType(rd),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{},
mkTarImgType(),
)
s390x.AddImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
mkQcow2ImgType(rd),
)
s390x.AddImageTypes(
&platform.S390X{},
mkTarImgType(),
)
azureX64Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
azureAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
rawUEFIx86Platform := &platform.X86{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
BIOS: false,
UEFIVendor: rd.Vendor(),
}
x86_64.AddImageTypes(
rawUEFIx86Platform,
mkMinimalRawImgType(),
)
if rd.IsRHEL() {
if common.VersionGreaterThanOrEqual(rd.OsVersion(), "8.6") {
// image types only available on 8.6 and later on RHEL
// These edge image types require FDO which aren't available on older versions
x86_64.AddImageTypes(
bareMetalX86Platform,
mkEdgeRawImgType(),
)
x86_64.AddImageTypes(
rawUEFIx86Platform,
mkEdgeSimplifiedInstallerImgType(rd),
)
x86_64.AddImageTypes(
azureX64Platform,
mkAzureEap7RhuiImgType(),
)
aarch64.AddImageTypes(
rawAarch64Platform,
mkEdgeRawImgType(),
mkEdgeSimplifiedInstallerImgType(rd),
)
// The Azure image types require hyperv-daemons which isn't available on older versions
aarch64.AddImageTypes(
azureAarch64Platform,
mkAzureRhuiImgType(),
mkAzureByosImgType(),
)
}
// add azure to RHEL distro only
x86_64.AddImageTypes(
azureX64Platform,
mkAzureRhuiImgType(),
mkAzureByosImgType(),
mkAzureSapRhuiImgType(rd),
)
// keep the RHEL EC2 x86_64 images before 8.9 BIOS-only for backward compatibility
if common.VersionLessThan(rd.OsVersion(), "8.9") {
ec2X86Platform = &platform.X86{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
}
// add ec2 image types to RHEL distro only
x86_64.AddImageTypes(
ec2X86Platform,
mkEc2ImgTypeX86_64(rd),
mkEc2HaImgTypeX86_64(rd),
)
aarch64.AddImageTypes(
rawAarch64Platform,
mkEc2ImgTypeAarch64(rd),
)
if rd.OsVersion() != "8.5" {
// NOTE: RHEL 8.5 is going away and these image types require some
// work to get working, so we just disable them here until the
// whole distro gets deleted
x86_64.AddImageTypes(
ec2X86Platform,
mkEc2SapImgTypeX86_64(rd),
)
}
// add GCE RHUI image to RHEL only
x86_64.AddImageTypes(
gceX86Platform,
mkGceRhuiImgType(rd),
)
// add s390x to RHEL distro only
rd.AddArches(s390x)
} else {
x86_64.AddImageTypes(
bareMetalX86Platform,
mkEdgeRawImgType(),
)
x86_64.AddImageTypes(
rawUEFIx86Platform,
mkEdgeSimplifiedInstallerImgType(rd),
)
x86_64.AddImageTypes(
azureX64Platform,
mkAzureImgType(),
)
aarch64.AddImageTypes(
rawAarch64Platform,
mkEdgeRawImgType(),
mkEdgeSimplifiedInstallerImgType(rd),
)
aarch64.AddImageTypes(
azureAarch64Platform,
mkAzureImgType(),
)
}
rd.AddArches(x86_64, aarch64, ppc64le)
return rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
// Backward compatibility layer for "rhel-84" or "rhel-810"
if id.Name == "rhel" && id.MinorVersion == -1 {
if id.MajorVersion/10 == 8 {
// handle single digit minor version
id.MinorVersion = id.MajorVersion % 10
id.MajorVersion = 8
} else if id.MajorVersion/100 == 8 {
// handle two digit minor version
id.MinorVersion = id.MajorVersion % 100
id.MajorVersion = 8
}
}
if id.MajorVersion != 8 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, id.MinorVersion)
}

View file

@ -0,0 +1,477 @@
package rhel8
import (
"fmt"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
func mkEdgeCommitImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-commit",
"commit.tar",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: edgeCommitPackageSet,
},
rhel.EdgeCommitImage,
[]string{"build"},
[]string{"os", "ostree-commit", "commit-archive"},
[]string{"commit-archive"},
)
it.NameAliases = []string{"rhel-edge-commit"}
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices(rd),
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
}
it.RPMOSTree = true
return it
}
func mkEdgeOCIImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-container",
"container.tar",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: edgeCommitPackageSet,
rhel.ContainerPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{"nginx"},
}
},
},
rhel.EdgeContainerImage,
[]string{"build"},
[]string{"os", "ostree-commit", "container-tree", "container"},
[]string{"container"},
)
it.NameAliases = []string{"rhel-edge-container"}
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices(rd),
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
}
it.RPMOSTree = true
return it
}
func mkEdgeRawImgType() *rhel.ImageType {
it := rhel.NewImageType(
"edge-raw-image",
"image.raw.xz",
"application/xz",
nil,
rhel.EdgeRawImage,
[]string{"build"},
[]string{"ostree-deployment", "image", "xz"},
[]string{"xz"},
)
it.NameAliases = []string{"rhel-edge-raw-image"}
it.Compression = "xz"
it.KernelOptions = "modprobe.blacklist=vc4"
it.DefaultImageConfig = &distro.ImageConfig{
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
Locale: common.ToPtr("C.UTF-8"),
LockRootUser: common.ToPtr(true),
}
it.DefaultSize = 10 * common.GibiByte
it.RPMOSTree = true
it.Bootable = true
it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{
disk.AutoLVMPartitioningMode,
disk.LVMPartitioningMode,
}
return it
}
func mkEdgeInstallerImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-installer",
"installer.iso",
"application/x-iso9660-image",
map[string]rhel.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.
rhel.InstallerPkgsKey: edgeInstallerPackageSet,
},
rhel.EdgeInstallerImage,
[]string{"build"},
[]string{"anaconda-tree", "rootfs-image", "efiboot-tree", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
it.NameAliases = []string{"rhel-edge-installer"}
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices(rd),
}
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"prefixdevname",
"prefixdevname-tools",
},
}
it.RPMOSTree = true
it.BootISO = true
it.ISOLabelFn = distroISOLabelFunc
return it
}
func mkEdgeSimplifiedInstallerImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-simplified-installer",
"simplified-installer.iso",
"application/x-iso9660-image",
map[string]rhel.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.
rhel.InstallerPkgsKey: edgeSimplifiedInstallerPackageSet,
},
rhel.EdgeSimplifiedInstallerImage,
[]string{"build"},
[]string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
it.NameAliases = []string{"rhel-edge-simplified-installer"}
it.KernelOptions = "modprobe.blacklist=vc4"
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices(rd),
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
Locale: common.ToPtr("C.UTF-8"),
LockRootUser: common.ToPtr(true),
}
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"prefixdevname",
"prefixdevname-tools",
},
}
it.DefaultSize = 10 * common.GibiByte
it.RPMOSTree = true
it.Bootable = true
it.BootISO = true
it.ISOLabelFn = distroISOLabelFunc
it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{
disk.AutoLVMPartitioningMode,
disk.LVMPartitioningMode,
}
return it
}
func mkMinimalRawImgType() *rhel.ImageType {
it := rhel.NewImageType(
"minimal-raw",
"disk.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: minimalrpmPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: minimalrawServices,
// NOTE: temporary workaround for a bug in initial-setup that
// requires a kickstart file in the root directory.
Files: []*fsnode.File{initialSetupKickstart()},
}
it.KernelOptions = "ro"
it.Bootable = true
it.DefaultSize = 2 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// edge commit OS package set
func edgeCommitPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"attr",
"audit",
"basesystem",
"bash",
"bash-completion",
"chrony",
"clevis",
"clevis-dracut",
"clevis-luks",
"container-selinux",
"coreutils",
"criu",
"cryptsetup",
"curl",
"dnsmasq",
"dosfstools",
"dracut-config-generic",
"dracut-network",
"e2fsprogs",
"firewalld",
"fuse-overlayfs",
"fwupd",
"glibc",
"glibc-minimal-langpack",
"gnupg2",
"greenboot",
"gzip",
"hostname",
"ima-evm-utils",
"iproute",
"iptables",
"iputils",
"keyutils",
"less",
"lvm2",
"NetworkManager",
"NetworkManager-wifi",
"NetworkManager-wwan",
"nss-altfiles",
"openssh-clients",
"openssh-server",
"passwd",
"pinentry",
"platform-python",
"podman",
"policycoreutils",
"policycoreutils-python-utils",
"polkit",
"procps-ng",
"redhat-release",
"rootfiles",
"rpm",
"rpm-ostree",
"rsync",
"selinux-policy-targeted",
"setools-console",
"setup",
"shadow-utils",
"shadow-utils",
"skopeo",
"slirp4netns",
"sudo",
"systemd",
"tar",
"tmux",
"traceroute",
"usbguard",
"util-linux",
"vim-minimal",
"wpa_supplicant",
"xz",
},
Exclude: []string{"rng-tools"},
}
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664EdgeCommitPackageSet(t))
case arch.ARCH_AARCH64.String():
ps = ps.Append(aarch64EdgeCommitPackageSet(t))
}
if t.IsRHEL() && common.VersionLessThan(t.Arch().Distro().OsVersion(), "8.6") {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"greenboot-grub2",
"greenboot-reboot",
"greenboot-rpm-ostree-grub2",
"greenboot-status",
},
})
} else {
// 8.6+ and CS8
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"fdo-client",
"fdo-owner-cli",
"greenboot-default-health-checks",
"sos",
},
})
}
return ps
}
func x8664EdgeCommitPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"efibootmgr",
"grub2",
"grub2-efi-x64",
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6000-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
"microcode_ctl",
"shim-x64",
},
Exclude: nil,
}
}
func aarch64EdgeCommitPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"efibootmgr",
"grub2-efi-aa64",
"iwl7260-firmware",
"shim-aa64",
},
Exclude: nil,
}
}
func edgeInstallerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return anacondaPackageSet(t)
}
func edgeSimplifiedInstallerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
// common installer packages
ps := installerPackageSet(t)
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"attr",
"basesystem",
"binutils",
"bsdtar",
"clevis-dracut",
"clevis-luks",
"cloud-utils-growpart",
"coreos-installer",
"coreos-installer-dracut",
"coreutils",
"device-mapper-multipath",
"dnsmasq",
"dosfstools",
"dracut-live",
"e2fsprogs",
"fcoe-utils",
"fdo-init",
"gzip",
"ima-evm-utils",
"iproute",
"iptables",
"iputils",
"iscsi-initiator-utils",
"keyutils",
"lldpad",
"lvm2",
"passwd",
"policycoreutils",
"policycoreutils-python-utils",
"procps-ng",
"redhat-logos",
"rootfiles",
"setools-console",
"sudo",
"traceroute",
"util-linux",
},
Exclude: nil,
})
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664EdgeCommitPackageSet(t))
case arch.ARCH_AARCH64.String():
ps = ps.Append(aarch64EdgeCommitPackageSet(t))
default:
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps
}
func edgeServices(rd *rhel.Distribution) []string {
// Common Services
var edgeServices = []string{"NetworkManager.service", "firewalld.service", "sshd.service"}
if rd.OsVersion() == "8.4" {
// greenboot services aren't enabled by default in 8.4
edgeServices = append(edgeServices,
"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")
}
if !(rd.IsRHEL() && common.VersionLessThan(rd.OsVersion(), "8.6")) {
// enable fdo-client only on RHEL 8.6+ and CS8
// TODO(runcom): move fdo-client-linuxapp.service to presets?
edgeServices = append(edgeServices, "fdo-client-linuxapp.service")
}
return edgeServices
}
var minimalrawServices = []string{
"NetworkManager.service",
"firewalld.service",
"sshd.service",
"initial-setup.service",
}
// initialSetupKickstart returns the File configuration for a kickstart file
// that's required to enable initial-setup to run on first boot.
func initialSetupKickstart() *fsnode.File {
file, err := fsnode.NewFile("/root/anaconda-ks.cfg", nil, "root", "root", []byte("# Run initial-setup on first boot\n# Created by osbuild\nfirstboot --reconfig\nlang en_US.UTF-8\n"))
if err != nil {
panic(err)
}
return file
}

View file

@ -3,6 +3,7 @@ package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
@ -10,51 +11,57 @@ import (
const gceKernelOptions = "net.ifnames=0 biosdevname=0 scsi_mod.use_blk_mq=Y crashkernel=auto console=ttyS0,38400n8d"
func gceImgType(rd distribution) imageType {
return imageType{
name: "gce",
filename: "image.tar.gz",
mimeType: "application/gzip",
packageSets: map[string]packageSetFunc{
osPkgsKey: gcePackageSet,
func mkGceImgType(rd distro.Distro) *rhel.ImageType {
it := rhel.NewImageType(
"gce",
"image.tar.gz",
"application/gzip",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: gcePackageSet,
},
defaultImageConfig: defaultGceByosImageConfig(rd),
kernelOptions: gceKernelOptions,
bootable: true,
defaultSize: 20 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "archive"},
exports: []string{"archive"},
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = defaultGceByosImageConfig(rd)
it.KernelOptions = gceKernelOptions
it.Bootable = true
it.DefaultSize = 20 * common.GibiByte
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func gceRhuiImgType(rd distribution) imageType {
return imageType{
name: "gce-rhui",
filename: "image.tar.gz",
mimeType: "application/gzip",
packageSets: map[string]packageSetFunc{
osPkgsKey: gceRhuiPackageSet,
func mkGceRhuiImgType(rd distro.Distro) *rhel.ImageType {
it := rhel.NewImageType(
"gce-rhui",
"image.tar.gz",
"application/gzip",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: gceRhuiPackageSet,
},
defaultImageConfig: defaultGceRhuiImageConfig(rd),
kernelOptions: gceKernelOptions,
bootable: true,
defaultSize: 20 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "archive"},
exports: []string{"archive"},
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = defaultGceRhuiImageConfig(rd)
it.KernelOptions = gceKernelOptions
it.Bootable = true
it.DefaultSize = 20 * common.GibiByte
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// The configuration for non-RHUI images does not touch the RHSM configuration at all.
// https://issues.redhat.com/browse/COMPOSER-2157
func defaultGceByosImageConfig(rd distribution) *distro.ImageConfig {
func defaultGceByosImageConfig(rd distro.Distro) *distro.ImageConfig {
ic := &distro.ImageConfig{
Timezone: common.ToPtr("UTC"),
TimeSynchronization: &osbuild.ChronyStageOptions{
@ -145,7 +152,7 @@ func defaultGceByosImageConfig(rd distribution) *distro.ImageConfig {
},
},
}
if rd.osVersion == "8.4" {
if rd.OsVersion() == "8.4" {
// NOTE(akoutsou): these are enabled in the package preset, but for
// some reason do not get enabled on 8.4.
// the reason is unknown and deeply mysterious
@ -161,7 +168,7 @@ func defaultGceByosImageConfig(rd distribution) *distro.ImageConfig {
return ic
}
func defaultGceRhuiImageConfig(rd distribution) *distro.ImageConfig {
func defaultGceRhuiImageConfig(rd distro.Distro) *distro.ImageConfig {
ic := &distro.ImageConfig{
RHSMConfig: map[subscription.RHSMStatus]*osbuild.RHSMStageOptions{
subscription.RHSMConfigNoSubscription: {
@ -190,7 +197,7 @@ func defaultGceRhuiImageConfig(rd distribution) *distro.ImageConfig {
}
// common GCE image
func gceCommonPackageSet(t *imageType) rpmmd.PackageSet {
func gceCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",
@ -260,12 +267,12 @@ func gceCommonPackageSet(t *imageType) rpmmd.PackageSet {
}
// GCE BYOS image
func gcePackageSet(t *imageType) rpmmd.PackageSet {
func gcePackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return gceCommonPackageSet(t)
}
// GCE RHUI image
func gceRhuiPackageSet(t *imageType) rpmmd.PackageSet {
func gceRhuiPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"google-rhui-client-rhel8",

View file

@ -0,0 +1,186 @@
package rhel8
import (
"fmt"
"log"
"strings"
"golang.org/x/exp/slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/policies"
)
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
customizations := bp.Customizations
// holds warnings (e.g. deprecation notices)
var warnings []string
// we do not support embedding containers on ostree-derived images, only on commits themselves
if len(bp.Containers) > 0 && t.RPMOSTree && (t.Name() != "edge-commit" && t.Name() != "edge-container") {
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.Name(), t.Arch().Distro().Name())
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
}
}
if t.BootISO && t.RPMOSTree {
// ostree-based ISOs require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return nil, 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" {
allowed := []string{"InstallationDevice", "FDO", "User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.Name())
}
//making fdo optional so that simplified installer can be composed w/o the FDO section in the blueprint
if customizations.GetFDO() != nil {
if customizations.GetFDO().ManufacturingServerURL == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to", t.Name())
}
var diunSet int
if customizations.GetFDO().DiunPubKeyHash != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyInsecure != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyRootCerts != "" {
diunSet++
}
if diunSet != 1 {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to", t.Name())
}
}
} else if t.Name() == "edge-installer" {
allowed := []string{"User", "Group", "FIPS", "Installer", "Timezone", "Locale"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
}
}
}
if t.Name() == "edge-raw-image" {
// ostree-based bootable images require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return warnings, fmt.Errorf("%q images require specifying a URL from which to retrieve the OSTree commit", t.Name())
}
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer"
}
// warn that user & group customizations on edge-commit, edge-container are deprecated
// TODO(edge): directly error if these options are provided when rhel-9.5's time arrives
if t.Name() == "edge-commit" || t.Name() == "edge-container" {
if customizations.GetUsers() != nil {
w := fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetGroups() != nil {
w := fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())
log.Print(w)
warnings = append(warnings, w)
}
}
if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.RPMOSTree && t.Name() != "edge-raw-image" && t.Name() != "edge-simplified-installer" {
return warnings, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
}
if slices.Contains(t.UnsupportedPartitioningModes, options.PartitioningMode) {
return warnings, fmt.Errorf("partitioning mode %q is not supported for %q", options.PartitioningMode, t.Name())
}
mountpoints := customizations.GetFilesystems()
if mountpoints != nil && t.RPMOSTree {
return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types")
}
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
if osc := customizations.GetOpenSCAP(); osc != nil {
if t.Arch().Distro().OsVersion() == "9.0" {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported os version: %s", t.Arch().Distro().OsVersion()))
}
if !oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList) {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported profile: %s", osc.ProfileID))
}
if t.RPMOSTree {
return warnings, fmt.Errorf("OpenSCAP customizations are not supported for ostree types")
}
if osc.ProfileID == "" {
return warnings, fmt.Errorf("OpenSCAP profile cannot be empty")
}
}
// Check Directory/File Customizations are valid
dc := customizations.GetDirectories()
fc := customizations.GetFiles()
err = blueprint.ValidateDirFileCustomizations(dc, fc)
if err != nil {
return warnings, err
}
dcp := policies.CustomDirectoriesPolicies
fcp := policies.CustomFilesPolicies
if t.RPMOSTree {
dcp = policies.OstreeCustomDirectoriesPolicies
fcp = policies.OstreeCustomFilesPolicies
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
if err != nil {
return warnings, err
}
// check if repository customizations are valid
_, err = customizations.GetRepositories()
if err != nil {
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetInstaller() != nil {
// only supported by the Anaconda installer
if slices.Index([]string{"image-installer", "edge-installer", "live-installer"}, t.Name()) == -1 {
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.Name())
}
}
return warnings, nil
}

View file

@ -6,13 +6,14 @@ import (
"fmt"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
// installer boot package sets, needed for booting and
// also in the build host
func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
func anacondaBootPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{}
grubCommon := rpmmd.PackageSet{
@ -29,7 +30,7 @@ func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
},
}
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(grubCommon)
ps = ps.Append(efiCommon)
@ -58,15 +59,15 @@ func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
})
default:
panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name()))
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps
}
// packages that are only in some (sub)-distributions
func distroSpecificPackageSet(t *imageType) rpmmd.PackageSet {
if t.arch.distro.isRHEL() {
func distroSpecificPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
if t.IsRHEL() {
return rpmmd.PackageSet{
Include: []string{"insights-client"},
}
@ -74,7 +75,7 @@ func distroSpecificPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{}
}
func minimalrpmPackageSet(t *imageType) rpmmd.PackageSet {
func minimalrpmPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",

View file

@ -0,0 +1,403 @@
package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro/rhel"
)
func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 100 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 100 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
case arch.ARCH_PPC64LE.String():
return disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
Partitions: []disk.Partition{
{
Size: 4 * common.MebiByte,
Type: "41",
Bootable: true,
},
{
Size: 2 * common.GibiByte,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
case arch.ARCH_S390X.String():
return disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
Partitions: []disk.Partition{
{
Size: 2 * common.GibiByte,
Bootable: true,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
default:
return disk.PartitionTable{}, false
}
}
func edgeBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 127 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 384 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 1,
FSTabPassNo: 1,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LUKSContainer{
Label: "crypt_root",
Cipher: "cipher_null",
Passphrase: "osbuild",
PBKDF: disk.Argon2id{
Memory: 32,
Iterations: 4,
Parallelism: 1,
},
Clevis: &disk.ClevisBind{
Pin: "null",
Policy: "{}",
RemovePassphrase: true,
},
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
}, true
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 127 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 384 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 1,
FSTabPassNo: 1,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LUKSContainer{
Label: "crypt_root",
Cipher: "cipher_null",
Passphrase: "osbuild",
PBKDF: disk.Argon2id{
Memory: 32,
Iterations: 4,
Parallelism: 1,
},
Clevis: &disk.ClevisBind{
Pin: "null",
Policy: "{}",
RemovePassphrase: true,
},
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
}, true
default:
return disk.PartitionTable{}, false
}
}
func ec2PartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
// x86_64 - without /boot
// aarch - <= 8.9 - 512MiB, 8.10 and centos: 1 GiB
var aarch64BootSize uint64
switch {
case common.VersionLessThan(t.Arch().Distro().OsVersion(), "8.10") && t.IsRHEL():
aarch64BootSize = 512 * common.MebiByte
default:
aarch64BootSize = 1 * common.GibiByte
}
x86PartitionTable := disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 200 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}
// RHEL EC2 x86_64 images prior to 8.9 support only BIOS boot
if common.VersionLessThan(t.Arch().Distro().OsVersion(), "8.9") && t.IsRHEL() {
x86PartitionTable = disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}
}
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return x86PartitionTable, true
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 200 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: aarch64BootSize,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
default:
return disk.PartitionTable{}, false
}
}

View file

@ -3,70 +3,81 @@ package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
)
func qcow2ImgType(rd distribution) imageType {
it := imageType{
name: "qcow2",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
kernelOptions: "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto",
packageSets: map[string]packageSetFunc{
osPkgsKey: qcow2CommonPackageSet,
func mkQcow2ImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"qcow2",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"),
},
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
if rd.isRHEL() {
it.defaultImageConfig.RHSMConfig = map[subscription.RHSMStatus]*osbuild.RHSMStageOptions{
subscription.RHSMConfigNoSubscription: {
DnfPlugins: &osbuild.RHSMStageOptionsDnfPlugins{
ProductID: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
SubscriptionManager: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
},
},
}
}
it.DefaultImageConfig = qcowImageConfig(rd)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto"
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func openstackImgType() imageType {
return imageType{
name: "openstack",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
packageSets: map[string]packageSetFunc{
osPkgsKey: openstackCommonPackageSet,
func mkOCIImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"oci",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet,
},
kernelOptions: "ro net.ifnames=0",
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = qcowImageConfig(rd)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto"
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
func mkOpenstackImgType() *rhel.ImageType {
it := rhel.NewImageType(
"openstack",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: openstackCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.KernelOptions = "ro net.ifnames=0"
it.DefaultSize = 4 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func qcow2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
@ -140,7 +151,7 @@ func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
}.Append(distroSpecificPackageSet(t))
// Ensure to not pull in subscription-manager on non-RHEL distro
if t.arch.distro.isRHEL() {
if t.IsRHEL() {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"subscription-manager-cockpit",
@ -151,7 +162,7 @@ func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func openstackCommonPackageSet(t *imageType) rpmmd.PackageSet {
func openstackCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
// Defaults
@ -170,3 +181,24 @@ func openstackCommonPackageSet(t *imageType) rpmmd.PackageSet {
},
}
}
func qcowImageConfig(d *rhel.Distribution) *distro.ImageConfig {
ic := &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"),
}
if d.IsRHEL() {
ic.RHSMConfig = map[subscription.RHSMStatus]*osbuild.RHSMStageOptions{
subscription.RHSMConfigNoSubscription: {
DnfPlugins: &osbuild.RHSMStageOptionsDnfPlugins{
ProductID: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
SubscriptionManager: &osbuild.RHSMStageOptionsDnfPlugin{
Enabled: false,
},
},
},
}
}
return ic
}

View file

@ -3,12 +3,13 @@ package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
// sapImageConfig returns the SAP specific ImageConfig data
func sapImageConfig(rd distribution) *distro.ImageConfig {
func sapImageConfig(rd distro.Distro) *distro.ImageConfig {
return &distro.ImageConfig{
SELinuxConfig: &osbuild.SELinuxConfigStageOptions{
State: osbuild.SELinuxStatePermissive,
@ -110,7 +111,7 @@ func sapImageConfig(rd distribution) *distro.ImageConfig {
[]osbuild.DNFVariable{
{
Name: "releasever",
Value: rd.osVersion,
Value: rd.OsVersion(),
},
},
nil,
@ -119,7 +120,7 @@ func sapImageConfig(rd distribution) *distro.ImageConfig {
}
}
func SapPackageSet(t *imageType) rpmmd.PackageSet {
func SapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
packageSet := rpmmd.PackageSet{
Include: []string{
// RHBZ#2074107
@ -160,7 +161,7 @@ func SapPackageSet(t *imageType) rpmmd.PackageSet {
},
}
if common.VersionLessThan(t.arch.distro.osVersion, "8.6") {
if common.VersionLessThan(t.Arch().Distro().OsVersion(), "8.6") {
packageSet = packageSet.Append(rpmmd.PackageSet{
Include: []string{"ansible"},
})

View file

@ -3,36 +3,39 @@ package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
func wslImgType() imageType {
return imageType{
name: "wsl",
filename: "disk.tar.gz",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: ubiCommonPackageSet,
func mkWslImgType() *rhel.ImageType {
it := rhel.NewImageType(
"wsl",
"disk.tar.gz",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ubiCommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{
Boot: osbuild.WSLConfBootOptions{
Systemd: true,
},
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{
Boot: osbuild.WSLConfBootOptions{
Systemd: true,
},
},
bootable: false,
image: tarImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "archive"},
exports: []string{"archive"},
}
return it
}
func ubiCommonPackageSet(t *imageType) rpmmd.PackageSet {
func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"alternatives",

View file

@ -0,0 +1,71 @@
package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
const vmdkKernelOptions = "ro net.ifnames=0"
func mkVmdkImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vmdk",
"disk.vmdk",
"application/x-vmdk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk"},
[]string{"vmdk"},
)
it.KernelOptions = vmdkKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOvaImgType() *rhel.ImageType {
it := rhel.NewImageType(
"ova",
"image.ova",
"application/ovf",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk", "ovf", "archive"},
[]string{"archive"},
)
it.KernelOptions = vmdkKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func vmdkCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"firewalld",
"langpacks-en",
"open-vm-tools",
"selinux-policy-targeted",
},
Exclude: []string{
"dracut-config-rescue",
"rng-tools",
},
}
}

View file

@ -3,6 +3,7 @@ package rhel9
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
@ -11,118 +12,6 @@ import (
// TODO: move these to the EC2 environment
const amiKernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295"
var (
amiImgTypeX86_64 = imageType{
name: "ami",
filename: "image.raw",
mimeType: "application/octet-stream",
packageSets: map[string]packageSetFunc{
osPkgsKey: ec2CommonPackageSet,
},
kernelOptions: amiKernelOptions,
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image"},
exports: []string{"image"},
basePartitionTables: defaultBasePartitionTables,
}
ec2ImgTypeX86_64 = imageType{
name: "ec2",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: rhelEc2PackageSet,
},
kernelOptions: amiKernelOptions,
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: defaultBasePartitionTables,
}
ec2HaImgTypeX86_64 = imageType{
name: "ec2-ha",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
buildPkgsKey: ec2BuildPackageSet,
osPkgsKey: rhelEc2HaPackageSet,
},
kernelOptions: amiKernelOptions,
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: defaultBasePartitionTables,
}
amiImgTypeAarch64 = imageType{
name: "ami",
filename: "image.raw",
mimeType: "application/octet-stream",
packageSets: map[string]packageSetFunc{
buildPkgsKey: ec2BuildPackageSet,
osPkgsKey: ec2CommonPackageSet,
},
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0",
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image"},
exports: []string{"image"},
basePartitionTables: defaultBasePartitionTables,
}
ec2ImgTypeAarch64 = imageType{
name: "ec2",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
buildPkgsKey: ec2BuildPackageSet,
osPkgsKey: rhelEc2PackageSet,
},
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0",
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: defaultBasePartitionTables,
}
ec2SapImgTypeX86_64 = imageType{
name: "ec2-sap",
filename: "image.raw.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
buildPkgsKey: ec2BuildPackageSet,
osPkgsKey: rhelEc2SapPackageSet,
},
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 processor.max_cstate=1 intel_idle.max_cstate=1",
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: defaultBasePartitionTables,
}
)
// default EC2 images config (common for all architectures)
func baseEc2ImageConfig() *distro.ImageConfig {
return &distro.ImageConfig{
@ -286,7 +175,7 @@ func defaultAMIImageConfigX86_64() *distro.ImageConfig {
}
// common ec2 image build package set
func ec2BuildPackageSet(t *imageType) rpmmd.PackageSet {
func ec2BuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return distroBuildPackageSet(t).Append(
rpmmd.PackageSet{
Include: []string{
@ -295,10 +184,11 @@ func ec2BuildPackageSet(t *imageType) rpmmd.PackageSet {
})
}
func ec2CommonPackageSet(t *imageType) rpmmd.PackageSet {
func ec2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"authselect-compat",
"chrony",
"cloud-init",
"cloud-utils-growpart",
@ -350,25 +240,21 @@ func ec2CommonPackageSet(t *imageType) rpmmd.PackageSet {
},
}.Append(distroSpecificPackageSet(t))
if t.arch.distro.releaseVersion == "9" {
ps.Include = append(ps.Include, "authselect-compat")
}
return ps
}
// common rhel ec2 RHUI image package set
func rhelEc2CommonPackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := ec2CommonPackageSet(t)
// Include "redhat-cloud-client-configuration" on 9.1+ (COMPOSER-1805)
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.1") {
if common.VersionGreaterThanOrEqual(t.Arch().Distro().OsVersion(), "9.1") {
ps.Include = append(ps.Include, "redhat-cloud-client-configuration")
}
return ps
}
// rhel-ec2 image package set
func rhelEc2PackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2PackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ec2PackageSet := rhelEc2CommonPackageSet(t)
ec2PackageSet = ec2PackageSet.Append(rpmmd.PackageSet{
Include: []string{
@ -382,7 +268,7 @@ func rhelEc2PackageSet(t *imageType) rpmmd.PackageSet {
}
// rhel-ha-ec2 image package set
func rhelEc2HaPackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2HaPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ec2HaPackageSet := rhelEc2CommonPackageSet(t)
ec2HaPackageSet = ec2HaPackageSet.Append(rpmmd.PackageSet{
Include: []string{
@ -401,7 +287,7 @@ func rhelEc2HaPackageSet(t *imageType) rpmmd.PackageSet {
// rhel-sap-ec2 image package set
// Includes the common ec2 package set, the common SAP packages, and
// the amazon rhui sap package
func rhelEc2SapPackageSet(t *imageType) rpmmd.PackageSet {
func rhelEc2SapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rh-amazon-rhui-client-sap-bundle-e4s",
@ -414,44 +300,149 @@ func rhelEc2SapPackageSet(t *imageType) rpmmd.PackageSet {
}.Append(rhelEc2CommonPackageSet(t)).Append(SapPackageSet(t))
}
func mkEc2ImgTypeX86_64(osVersion string, rhsm bool) imageType {
it := ec2ImgTypeX86_64
ic := defaultEc2ImageConfigX86_64(osVersion, rhsm)
it.defaultImageConfig = ic
func mkEc2ImgTypeX86_64(osVersion string, rhsm bool) *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2PackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.KernelOptions = amiKernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64(osVersion, rhsm)
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkAMIImgTypeX86_64() imageType {
it := amiImgTypeX86_64
ic := defaultAMIImageConfigX86_64()
it.defaultImageConfig = ic
func mkAMIImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.KernelOptions = amiKernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultAMIImageConfigX86_64()
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkEC2SapImgTypeX86_64(osVersion string, rhsm bool) imageType {
it := ec2SapImgTypeX86_64
it.defaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64(osVersion, rhsm))
func mkEC2SapImgTypeX86_64(osVersion string, rhsm bool) *rhel.ImageType {
it := rhel.NewImageType(
"ec2-sap",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.BuildPkgsKey: ec2BuildPackageSet,
rhel.OSPkgsKey: rhelEc2SapPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 processor.max_cstate=1 intel_idle.max_cstate=1"
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64(osVersion, rhsm))
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkEc2HaImgTypeX86_64(osVersion string, rhsm bool) imageType {
it := ec2HaImgTypeX86_64
ic := defaultEc2ImageConfigX86_64(osVersion, rhsm)
it.defaultImageConfig = ic
func mkEc2HaImgTypeX86_64(osVersion string, rhsm bool) *rhel.ImageType {
it := rhel.NewImageType(
"ec2-ha",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.BuildPkgsKey: ec2BuildPackageSet,
rhel.OSPkgsKey: rhelEc2HaPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.KernelOptions = amiKernelOptions
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64(osVersion, rhsm)
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkAMIImgTypeAarch64() imageType {
it := amiImgTypeAarch64
ic := defaultAMIImageConfig()
it.defaultImageConfig = ic
func mkAMIImgTypeAarch64() *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
map[string]rhel.PackageSetFunc{
rhel.BuildPkgsKey: ec2BuildPackageSet,
rhel.OSPkgsKey: ec2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0"
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultAMIImageConfig()
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkEC2ImgTypeAarch64(osVersion string, rhsm bool) imageType {
it := ec2ImgTypeAarch64
ic := defaultEc2ImageConfig(osVersion, rhsm)
it.defaultImageConfig = ic
func mkEC2ImgTypeAarch64(osVersion string, rhsm bool) *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.BuildPkgsKey: ec2BuildPackageSet,
rhel.OSPkgsKey: rhelEc2PackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0"
it.Bootable = true
it.DefaultSize = 10 * common.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfig(osVersion, rhsm)
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

@ -5,98 +5,113 @@ import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
)
var (
// Azure non-RHEL image type
azureImgType = imageType{
name: "vhd",
filename: "disk.vhd",
mimeType: "application/x-vhd",
packageSets: map[string]packageSetFunc{
osPkgsKey: azurePackageSet,
// Azure non-RHEL image type
func mkAzureImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet,
},
defaultImageConfig: defaultAzureImageConfig,
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc"},
exports: []string{"vpc"},
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
// Azure RHUI image type
azureRhuiImgType = imageType{
name: "azure-rhui",
filename: "disk.vhd.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: azureRhuiPackageSet,
},
defaultImageConfig: defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 64 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc", "xz"},
exports: []string{"xz"},
basePartitionTables: azureRhuiBasePartitionTables,
}
)
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig
it.BasePartitionTables = defaultBasePartitionTables
// Azure BYOS image type
func azureByosImgType(rd distribution) imageType {
return imageType{
name: "vhd",
filename: "disk.vhd",
mimeType: "application/x-vhd",
packageSets: map[string]packageSetFunc{
osPkgsKey: azurePackageSet,
},
defaultImageConfig: defaultAzureByosImageConfig(rd).InheritFrom(defaultAzureImageConfig),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc"},
exports: []string{"vpc"},
basePartitionTables: defaultBasePartitionTables,
}
return it
}
func azureSapRhuiImgType(rd distribution) imageType {
return imageType{
name: "azure-sap-rhui",
filename: "disk.vhd.xz",
mimeType: "application/xz",
compression: "xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: azureSapPackageSet,
// Azure BYOS image type
func mkAzureByosImgType(rd distro.Distro) *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet,
},
defaultImageConfig: defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd)),
kernelOptions: defaultAzureKernelOptions,
bootable: true,
defaultSize: 64 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vpc", "xz"},
exports: []string{"xz"},
basePartitionTables: azureRhuiBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.DefaultImageConfig = defaultAzureByosImageConfig.InheritFrom(defaultAzureImageConfig)
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// Azure RHUI image type
func mkAzureRhuiImgType() *rhel.ImageType {
it := rhel.NewImageType(
"azure-rhui",
"disk.vhd.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azureRhuiPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 64 * common.GibiByte
it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig)
it.BasePartitionTables = azureRhuiBasePartitionTables
return it
}
func mkAzureSapRhuiImgType(rd distro.Distro) *rhel.ImageType {
it := rhel.NewImageType(
"azure-sap-rhui",
"disk.vhd.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azureSapPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.KernelOptions = defaultAzureKernelOptions
it.Bootable = true
it.DefaultSize = 64 * common.GibiByte
it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd))
it.BasePartitionTables = azureRhuiBasePartitionTables
return it
}
// PACKAGE SETS
// Common Azure image package set
func azureCommonPackageSet(t *imageType) rpmmd.PackageSet {
func azureCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@Server",
@ -176,12 +191,12 @@ func azureCommonPackageSet(t *imageType) rpmmd.PackageSet {
}
// Azure BYOS image package set
func azurePackageSet(t *imageType) rpmmd.PackageSet {
func azurePackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return azureCommonPackageSet(t)
}
// Azure RHUI image package set
func azureRhuiPackageSet(t *imageType) rpmmd.PackageSet {
func azureRhuiPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rhui-azure-rhel9",
@ -189,17 +204,28 @@ func azureRhuiPackageSet(t *imageType) rpmmd.PackageSet {
}.Append(azureCommonPackageSet(t))
}
// Azure SAP image package set
// Includes the common azure package set, the common SAP packages, and
// the azure rhui sap package.
func azureSapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rhui-azure-rhel9-sap-ha",
},
}.Append(azureCommonPackageSet(t)).Append(SapPackageSet(t))
}
// PARTITION TABLES
func azureRhuiBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
func azureRhuiBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
// RHEL >= 9.3 needs to have a bigger /boot, see RHEL-7999
bootSize := uint64(600) * common.MebiByte
if common.VersionLessThan(t.arch.distro.osVersion, "9.3") && t.arch.distro.isRHEL() {
if common.VersionLessThan(t.Arch().Distro().OsVersion(), "9.3") && t.IsRHEL() {
bootSize = 500 * common.MebiByte
}
switch t.platform.GetArch() {
case arch.ARCH_X86_64:
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -308,7 +334,7 @@ func azureRhuiBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
},
},
}, true
case arch.ARCH_AARCH64:
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -416,8 +442,10 @@ func azureRhuiBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
}
}
// IMAGE CONFIG
// use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT
var defaultAzureKernelOptions = "ro loglevel=3 console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300"
const defaultAzureKernelOptions = "ro loglevel=3 console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300"
// based on https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/deploying_rhel_9_on_microsoft_azure/assembly_deploying-a-rhel-image-as-a-virtual-machine-on-microsoft-azure_cloud-content-azure#making-configuration-changes_configure-the-image-azure
var defaultAzureImageConfig = &distro.ImageConfig{
@ -576,18 +604,10 @@ var defaultAzureImageConfig = &distro.ImageConfig{
// Diff of the default Image Config compare to the `defaultAzureImageConfig`
// The configuration for non-RHUI images does not touch the RHSM configuration at all.
// https://issues.redhat.com/browse/COMPOSER-2157
func defaultAzureByosImageConfig(rd distribution) *distro.ImageConfig {
ic := &distro.ImageConfig{}
// NOTE RHEL 10 content is currently unsigned - remove this when GPG keys get added to the repos
if rd.Releasever() == "9" {
ic = &distro.ImageConfig{
GPGKeyFiles: []string{
"/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release",
},
}
}
return ic
var defaultAzureByosImageConfig = &distro.ImageConfig{
GPGKeyFiles: []string{
"/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release",
},
}
// Diff of the default Image Config compare to the `defaultAzureImageConfig`
@ -624,17 +644,6 @@ var defaultAzureRhuiImageConfig = &distro.ImageConfig{
},
}
// Azure SAP image package set
// Includes the common azure package set, the common SAP packages, and
// the azure rhui sap package.
func azureSapPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"rhui-azure-rhel9-sap-ha",
},
}.Append(azureCommonPackageSet(t)).Append(SapPackageSet(t))
}
func sapAzureImageConfig(rd distribution) *distro.ImageConfig {
return sapImageConfig(rd.osVersion).InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig))
func sapAzureImageConfig(rd distro.Distro) *distro.ImageConfig {
return sapImageConfig(rd.OsVersion()).InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig))
}

View file

@ -5,48 +5,69 @@ import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
var (
tarImgType = imageType{
name: "tar",
filename: "root.tar.xz",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: func(t *imageType) rpmmd.PackageSet {
func mkTarImgType() *rhel.ImageType {
return rhel.NewImageType(
"tar",
"root.tar.xz",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{"policycoreutils", "selinux-policy-targeted"},
Exclude: []string{"rng-tools"},
}
},
},
image: tarImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "archive"},
exports: []string{"archive"},
}
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
}
imageInstaller = imageType{
name: "image-installer",
filename: "installer.iso",
mimeType: "application/x-iso9660-image",
packageSets: map[string]packageSetFunc{
osPkgsKey: bareMetalPackageSet,
installerPkgsKey: anacondaPackageSet,
func mkImageInstallerImgType() *rhel.ImageType {
it := rhel.NewImageType(
"image-installer",
"installer.iso",
"application/x-iso9660-image",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: bareMetalPackageSet,
rhel.InstallerPkgsKey: anacondaPackageSet,
},
rpmOstree: false,
bootISO: true,
bootable: true,
image: imageInstallerImage,
isoLabel: distroISOLabelFunc,
buildPipelines: []string{"build"},
payloadPipelines: []string{"anaconda-tree", "rootfs-image", "efiboot-tree", "os", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
}
)
rhel.ImageInstallerImage,
[]string{"build"},
[]string{"anaconda-tree", "rootfs-image", "efiboot-tree", "os", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
it.BootISO = true
it.Bootable = true
it.ISOLabelFn = distroISOLabelFunc
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
},
AdditionalDrivers: []string{
"cuse",
"ipmi_devintf",
"ipmi_msghandler",
},
}
return it
}
// PACKAGE SETS
func bareMetalPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
@ -91,12 +112,12 @@ func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
},
}.Append(distroBuildPackageSet(t))
if common.VersionLessThan(t.arch.distro.osVersion, "10.0") {
if common.VersionLessThan(t.Arch().Distro().OsVersion(), "10.0") {
ps.Include = append(ps.Include, "authselect-compat")
}
// Ensure to not pull in subscription-manager on non-RHEL distro
if t.arch.distro.isRHEL() {
if t.IsRHEL() {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"subscription-manager-cockpit",
@ -107,7 +128,7 @@ func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func installerPackageSet(t *imageType) rpmmd.PackageSet {
func installerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"anaconda-dracut",
@ -157,7 +178,7 @@ func installerPackageSet(t *imageType) rpmmd.PackageSet {
},
})
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
@ -169,7 +190,7 @@ func installerPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
func anacondaPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
// common installer packages
ps := installerPackageSet(t)
@ -315,7 +336,7 @@ func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
ps = ps.Append(anacondaBootPackageSet(t))
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
@ -334,7 +355,7 @@ func anacondaPackageSet(t *imageType) rpmmd.PackageSet {
})
default:
panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name()))
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps

View file

@ -0,0 +1,423 @@
package rhel9
import (
"fmt"
"strings"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
)
var (
// rhel9 & cs9 share the same list
// of allowed profiles so a single
// allow list can be used
oscapProfileAllowList = []oscap.Profile{
oscap.AnssiBp28Enhanced,
oscap.AnssiBp28High,
oscap.AnssiBp28Intermediary,
oscap.AnssiBp28Minimal,
oscap.CcnAdvanced,
oscap.CcnBasic,
oscap.CcnIntermediate,
oscap.Cis,
oscap.CisServerL1,
oscap.CisWorkstationL1,
oscap.CisWorkstationL2,
oscap.Cui,
oscap.E8,
oscap.Hippa,
oscap.IsmO,
oscap.Ospp,
oscap.PciDss,
oscap.Stig,
oscap.StigGui,
}
)
func distroISOLabelFunc(t *rhel.ImageType) string {
const RHEL_ISO_LABEL = "RHEL-%s-%s-0-BaseOS-%s"
const CS_ISO_LABEL = "CentOS-Stream-%s-BaseOS-%s"
if t.IsRHEL() {
osVer := strings.Split(t.Arch().Distro().OsVersion(), ".")
return fmt.Sprintf(RHEL_ISO_LABEL, osVer[0], osVer[1], t.Arch().Name())
} else {
return fmt.Sprintf(CS_ISO_LABEL, t.Arch().Distro().Releasever(), t.Arch().Name())
}
}
func defaultDistroImageConfig(d *rhel.Distribution) *distro.ImageConfig {
return &distro.ImageConfig{
Timezone: common.ToPtr("America/New_York"),
Locale: common.ToPtr("C.UTF-8"),
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
DefaultOSCAPDatastream: common.ToPtr(oscap.DefaultRHEL9Datastream(d.IsRHEL())),
}
}
func newDistro(name string, major, minor int) *rhel.Distribution {
rd, err := rhel.NewDistribution(name, major, minor)
if err != nil {
panic(err)
}
rd.CheckOptions = checkOptions
rd.DefaultImageConfig = defaultDistroImageConfig
// Architecture definitions
x86_64 := rhel.NewArchitecture(rd, arch.ARCH_X86_64)
aarch64 := rhel.NewArchitecture(rd, arch.ARCH_AARCH64)
ppc64le := rhel.NewArchitecture(rd, arch.ARCH_PPC64LE)
s390x := rhel.NewArchitecture(rd, arch.ARCH_S390X)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
mkOCIImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
mkOpenstackImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
mkVMDKImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_OVA,
},
},
mkOVAImgType(),
)
x86_64.AddImageTypes(
&platform.X86{},
mkTarImgType(),
mkWSLImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
mkOpenstackImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{},
mkTarImgType(),
mkWSLImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{},
mkTarImgType(),
)
s390x.AddImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd),
)
s390x.AddImageTypes(
&platform.S390X{},
mkTarImgType(),
)
ec2X86Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
x86_64.AddImageTypes(
ec2X86Platform,
mkAMIImgTypeX86_64(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
mkAMIImgTypeAarch64(),
)
azureX64Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
azureAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
if rd.IsRHEL() { // RHEL-only (non-CentOS) image types
x86_64.AddImageTypes(azureX64Platform, mkAzureByosImgType(rd))
aarch64.AddImageTypes(azureAarch64Platform, mkAzureByosImgType(rd))
} else {
x86_64.AddImageTypes(azureX64Platform, mkAzureImgType())
aarch64.AddImageTypes(azureAarch64Platform, mkAzureImgType())
}
gceX86Platform := &platform.X86{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_GCE,
},
}
x86_64.AddImageTypes(
gceX86Platform,
mkGCEImageType(),
)
x86_64.AddImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"microcode_ctl", // ??
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6050-firmware",
},
},
BIOS: true,
UEFIVendor: rd.Vendor(),
},
mkEdgeOCIImgType(rd),
mkEdgeCommitImgType(rd),
mkEdgeInstallerImgType(),
mkEdgeRawImgType(rd),
mkImageInstallerImgType(),
mkEdgeAMIImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
BIOS: true,
UEFIVendor: rd.Vendor(),
},
mkEdgeVsphereImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
BIOS: false,
UEFIVendor: rd.Vendor(),
},
mkEdgeSimplifiedInstallerImgType(rd),
mkMinimalrawImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{},
UEFIVendor: rd.Vendor(),
},
mkEdgeOCIImgType(rd),
mkEdgeCommitImgType(rd),
mkEdgeInstallerImgType(),
mkEdgeSimplifiedInstallerImgType(rd),
mkImageInstallerImgType(),
mkEdgeAMIImgType(rd),
)
aarch64.AddImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
UEFIVendor: rd.Vendor(),
},
mkEdgeVsphereImgType(rd),
)
aarch64.AddImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
UEFIVendor: rd.Vendor(),
},
mkEdgeRawImgType(rd),
mkMinimalrawImgType(),
)
if rd.IsRHEL() { // RHEL-only (non-CentOS) image types
x86_64.AddImageTypes(azureX64Platform, mkAzureRhuiImgType(), mkAzureByosImgType(rd))
aarch64.AddImageTypes(azureAarch64Platform, mkAzureRhuiImgType(), mkAzureByosImgType(rd))
x86_64.AddImageTypes(azureX64Platform, mkAzureSapRhuiImgType(rd))
// keep the RHEL EC2 x86_64 images before 9.3 BIOS-only for backward compatibility
if common.VersionLessThan(rd.OsVersion(), "9.3") {
ec2X86Platform = &platform.X86{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
}
// add ec2 image types to RHEL distro only
x86_64.AddImageTypes(ec2X86Platform, mkEc2ImgTypeX86_64(rd.OsVersion(), rd.IsRHEL()), mkEc2HaImgTypeX86_64(rd.OsVersion(), rd.IsRHEL()), mkEC2SapImgTypeX86_64(rd.OsVersion(), rd.IsRHEL()))
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
mkEC2ImgTypeAarch64(rd.OsVersion(), rd.IsRHEL()),
)
// add GCE RHUI image to RHEL only
x86_64.AddImageTypes(gceX86Platform, mkGCERHUIImageType())
}
rd.AddArches(x86_64, aarch64, ppc64le, s390x)
return rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
// Backward compatibility layer for "rhel-93" or "rhel-910"
if id.Name == "rhel" && id.MinorVersion == -1 {
if id.MajorVersion/10 == 9 {
// handle single digit minor version
id.MinorVersion = id.MajorVersion % 10
id.MajorVersion = 9
} else if id.MajorVersion/100 == 9 {
// handle two digit minor version
id.MinorVersion = id.MajorVersion % 100
id.MajorVersion = 9
}
}
if id.MajorVersion != 9 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, 9, id.MinorVersion)
}

View file

@ -9,84 +9,164 @@ import (
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
var (
// Image Definitions
edgeCommitImgType = imageType{
name: "edge-commit",
nameAliases: []string{"rhel-edge-commit"},
filename: "commit.tar",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: edgeCommitPackageSet,
func mkEdgeCommitImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-commit",
"commit.tar",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: edgeCommitPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices,
SystemdUnit: systemdUnits,
},
rpmOstree: true,
image: edgeCommitImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "ostree-commit", "commit-archive"},
exports: []string{"commit-archive"},
rhel.EdgeCommitImage,
[]string{"build"},
[]string{"os", "ostree-commit", "commit-archive"},
[]string{"commit-archive"},
)
it.NameAliases = []string{"rhel-edge-commit"}
it.RPMOSTree = true
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices,
SystemdUnit: systemdUnits,
}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.DefaultImageConfig.EnabledServices = append(
it.DefaultImageConfig.EnabledServices,
"ignition-firstboot-complete.service",
"coreos-ignition-write-issues.service",
)
}
edgeOCIImgType = imageType{
name: "edge-container",
nameAliases: []string{"rhel-edge-container"},
filename: "container.tar",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: edgeCommitPackageSet,
containerPkgsKey: func(t *imageType) rpmmd.PackageSet {
return it
}
func mkEdgeOCIImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-container",
"container.tar",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: edgeCommitPackageSet,
rhel.ContainerPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{"nginx"}, // FIXME: this has no effect
}
},
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices,
SystemdUnit: systemdUnits,
},
rpmOstree: true,
bootISO: false,
image: edgeContainerImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "ostree-commit", "container-tree", "container"},
exports: []string{"container"},
rhel.EdgeContainerImage,
[]string{"build"},
[]string{"os", "ostree-commit", "container-tree", "container"},
[]string{"container"},
)
it.NameAliases = []string{"rhel-edge-container"}
it.RPMOSTree = true
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices,
SystemdUnit: systemdUnits,
}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.DefaultImageConfig.EnabledServices = append(
it.DefaultImageConfig.EnabledServices,
"ignition-firstboot-complete.service",
"coreos-ignition-write-issues.service",
)
}
edgeRawImgType = imageType{
name: "edge-raw-image",
nameAliases: []string{"rhel-edge-raw-image"},
filename: "image.raw.xz",
compression: "xz",
mimeType: "application/xz",
packageSets: nil,
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
return it
}
func mkEdgeRawImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-raw-image",
"image.raw.xz",
"application/xz",
nil,
rhel.EdgeRawImage,
[]string{"build"},
[]string{"ostree-deployment", "image", "xz"},
[]string{"xz"},
)
it.NameAliases = []string{"rhel-edge-raw-image"}
it.Compression = "xz"
it.DefaultImageConfig = &distro.ImageConfig{
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
kernelOptions: "modprobe.blacklist=vc4",
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
bootable: true,
bootISO: false,
image: edgeRawImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-deployment", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: edgeBasePartitionTables,
Locale: common.ToPtr("C.UTF-8"),
LockRootUser: common.ToPtr(true),
}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.DefaultImageConfig.OSTreeConfSysrootReadOnly = common.ToPtr(true)
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
}
edgeInstallerImgType = imageType{
name: "edge-installer",
nameAliases: []string{"rhel-edge-installer"},
filename: "installer.iso",
mimeType: "application/x-iso9660-image",
packageSets: map[string]packageSetFunc{
it.KernelOptions = "modprobe.blacklist=vc4"
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip"
}
it.DefaultSize = 10 * common.GibiByte
it.RPMOSTree = true
it.Bootable = true
it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{disk.RawPartitioningMode}
return it
}
func mkEdgeInstallerImgType() *rhel.ImageType {
it := rhel.NewImageType(
"edge-installer",
"installer.iso",
"application/x-iso9660-image",
map[string]rhel.PackageSetFunc{
rhel.InstallerPkgsKey: edgeInstallerPackageSet,
},
rhel.EdgeInstallerImage,
[]string{"build"},
[]string{"anaconda-tree", "rootfs-image", "efiboot-tree", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
it.NameAliases = []string{"rhel-edge-installer"}
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
EnabledServices: edgeServices,
}
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
},
AdditionalDrivers: []string{
"cuse",
"ipmi_devintf",
"ipmi_msghandler",
},
}
it.RPMOSTree = true
it.BootISO = true
it.ISOLabelFn = distroISOLabelFunc
return it
}
func mkEdgeSimplifiedInstallerImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-simplified-installer",
"simplified-installer.iso",
"application/x-iso9660-image",
map[string]rhel.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
@ -94,119 +174,159 @@ var (
// 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.
installerPkgsKey: edgeInstallerPackageSet,
rhel.InstallerPkgsKey: edgeSimplifiedInstallerPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
EnabledServices: edgeServices,
rhel.EdgeSimplifiedInstallerImage,
[]string{"build"},
[]string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
it.NameAliases = []string{"rhel-edge-simplified-installer"}
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices,
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
rpmOstree: true,
bootISO: true,
image: edgeInstallerImage,
isoLabel: distroISOLabelFunc,
buildPipelines: []string{"build"},
payloadPipelines: []string{"anaconda-tree", "rootfs-image", "efiboot-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
Locale: common.ToPtr("C.UTF-8"),
LockRootUser: common.ToPtr(true),
}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.DefaultImageConfig.OSTreeConfSysrootReadOnly = common.ToPtr(true)
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
}
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.
installerPkgsKey: edgeSimplifiedInstallerPackageSet,
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"prefixdevname",
"prefixdevname-tools",
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices,
},
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
bootable: true,
bootISO: true,
image: edgeSimplifiedInstallerImage,
isoLabel: distroISOLabelFunc,
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
basePartitionTables: edgeBasePartitionTables,
}
edgeAMIImgType = imageType{
name: "edge-ami",
filename: "image.raw",
mimeType: "application/octet-stream",
packageSets: nil,
it.DefaultSize = 10 * common.GibiByte
it.RPMOSTree = true
it.BootISO = true
it.Bootable = true
it.ISOLabelFn = distroISOLabelFunc
it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{disk.RawPartitioningMode}
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
},
kernelOptions: amiKernelOptions + " modprobe.blacklist=vc4",
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
bootable: true,
bootISO: false,
image: edgeRawImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-deployment", "image"},
exports: []string{"image"},
basePartitionTables: edgeBasePartitionTables,
environment: &environment.EC2{},
it.KernelOptions = "modprobe.blacklist=vc4"
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip"
}
edgeVsphereImgType = imageType{
name: "edge-vsphere",
filename: "image.vmdk",
mimeType: "application/x-vmdk",
packageSets: nil,
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
return it
}
func mkEdgeAMIImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-ami",
"image.raw",
"application/octet-stream",
nil,
rhel.EdgeRawImage,
[]string{"build"},
[]string{"ostree-deployment", "image"},
[]string{"image"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
kernelOptions: "modprobe.blacklist=vc4",
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
bootable: true,
bootISO: false,
image: edgeRawImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-deployment", "image", "vmdk"},
exports: []string{"vmdk"},
basePartitionTables: edgeBasePartitionTables,
Locale: common.ToPtr("C.UTF-8"),
LockRootUser: common.ToPtr(true),
}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.DefaultImageConfig.OSTreeConfSysrootReadOnly = common.ToPtr(true)
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
}
minimalrawImgType = imageType{
name: "minimal-raw",
filename: "disk.raw.xz",
compression: "xz",
mimeType: "application/xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: minimalrpmPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: minimalrawServices,
SystemdUnit: systemdUnits,
// NOTE: temporary workaround for a bug in initial-setup that
// requires a kickstart file in the root directory.
Files: []*fsnode.File{initialSetupKickstart()},
},
rpmOstree: false,
kernelOptions: "ro",
bootable: true,
defaultSize: 2 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: minimalrawPartitionTables,
it.KernelOptions = amiKernelOptions + " modprobe.blacklist=vc4"
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip"
}
it.DefaultSize = 10 * common.GibiByte
it.RPMOSTree = true
it.Bootable = true
it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{disk.RawPartitioningMode}
it.Environment = &environment.EC2{}
return it
}
func mkEdgeVsphereImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"edge-vsphere",
"image.vmdk",
"application/x-vmdk",
nil,
rhel.EdgeRawImage,
[]string{"build"},
[]string{"ostree-deployment", "image", "vmdk"},
[]string{"vmdk"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us",
},
Locale: common.ToPtr("C.UTF-8"),
LockRootUser: common.ToPtr(true),
}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.DefaultImageConfig.OSTreeConfSysrootReadOnly = common.ToPtr(true)
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
}
it.KernelOptions = "modprobe.blacklist=vc4"
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip"
}
it.DefaultSize = 10 * common.GibiByte
it.RPMOSTree = true
it.Bootable = true
it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{disk.RawPartitioningMode}
return it
}
func mkMinimalrawImgType() *rhel.ImageType {
it := rhel.NewImageType(
"minimal-raw",
"disk.raw.xz",
"application/xz",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: minimalrpmPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: minimalrawServices,
SystemdUnit: systemdUnits,
// NOTE: temporary workaround for a bug in initial-setup that
// requires a kickstart file in the root directory.
Files: []*fsnode.File{initialSetupKickstart()},
}
it.KernelOptions = "ro"
it.DefaultSize = 2 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = minimalrawPartitionTables
return it
}
var (
// Shared Services
edgeServices = []string{
// TODO(runcom): move fdo-client-linuxapp.service to presets?
@ -230,16 +350,26 @@ var (
}
)
// initialSetupKickstart returns the File configuration for a kickstart file
// that's required to enable initial-setup to run on first boot.
func initialSetupKickstart() *fsnode.File {
file, err := fsnode.NewFile("/root/anaconda-ks.cfg", nil, "root", "root", []byte("# Run initial-setup on first boot\n# Created by osbuild\nfirstboot --reconfig\nlang en_US.UTF-8\n"))
if err != nil {
panic(err)
}
return file
}
// Partition tables
func minimalrawPartitionTables(t *imageType) (disk.PartitionTable, bool) {
func minimalrawPartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
// RHEL >= 9.3 needs to have a bigger /boot, see RHEL-7999
bootSize := uint64(600) * common.MebiByte
if common.VersionLessThan(t.arch.distro.osVersion, "9.3") && t.arch.distro.isRHEL() {
if common.VersionLessThan(t.Arch().Distro().OsVersion(), "9.3") && t.IsRHEL() {
bootSize = 500 * common.MebiByte
}
switch t.platform.GetArch() {
case arch.ARCH_X86_64:
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -287,7 +417,7 @@ func minimalrawPartitionTables(t *imageType) (disk.PartitionTable, bool) {
},
},
}, true
case arch.ARCH_AARCH64:
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -340,9 +470,9 @@ func minimalrawPartitionTables(t *imageType) (disk.PartitionTable, bool) {
}
}
func edgeBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
switch t.platform.GetArch() {
case arch.ARCH_X86_64:
func edgeBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -419,7 +549,7 @@ func edgeBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
},
},
}, true
case arch.ARCH_AARCH64:
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -499,7 +629,7 @@ func edgeBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
// Package Sets
// edge commit OS package set
func edgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
func edgeCommitPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"redhat-release",
@ -583,7 +713,7 @@ func edgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
},
}
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664EdgeCommitPackageSet(t))
@ -591,7 +721,7 @@ func edgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
ps = ps.Append(aarch64EdgeCommitPackageSet(t))
}
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
if common.VersionGreaterThanOrEqual(t.Arch().Distro().OsVersion(), "9.2") || !t.IsRHEL() {
ps.Include = append(ps.Include, "ignition", "ignition-edge", "ssh-key-dir")
}
@ -599,7 +729,7 @@ func edgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
}
func x8664EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
func x8664EdgeCommitPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2",
@ -622,7 +752,7 @@ func x8664EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
}
}
func aarch64EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
func aarch64EdgeCommitPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2-efi-aa64",
@ -633,11 +763,11 @@ func aarch64EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
}
}
func edgeInstallerPackageSet(t *imageType) rpmmd.PackageSet {
func edgeInstallerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return anacondaPackageSet(t)
}
func edgeSimplifiedInstallerPackageSet(t *imageType) rpmmd.PackageSet {
func edgeSimplifiedInstallerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
// common installer packages
ps := installerPackageSet(t)
@ -682,7 +812,7 @@ func edgeSimplifiedInstallerPackageSet(t *imageType) rpmmd.PackageSet {
},
})
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664EdgeCommitPackageSet(t))
@ -690,7 +820,7 @@ func edgeSimplifiedInstallerPackageSet(t *imageType) rpmmd.PackageSet {
ps = ps.Append(aarch64EdgeCommitPackageSet(t))
default:
panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name()))
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps

View file

@ -3,6 +3,7 @@ package rhel9
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
@ -10,55 +11,53 @@ import (
const gceKernelOptions = "net.ifnames=0 biosdevname=0 scsi_mod.use_blk_mq=Y console=ttyS0,38400n8d"
var (
gceImgType = imageType{
name: "gce",
filename: "image.tar.gz",
mimeType: "application/gzip",
packageSets: map[string]packageSetFunc{
osPkgsKey: gcePackageSet,
func mkGCEImageType() *rhel.ImageType {
it := rhel.NewImageType(
"gce",
"image.tar.gz",
"application/gzip",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: gcePackageSet,
},
kernelOptions: gceKernelOptions,
bootable: true,
defaultSize: 20 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "archive"},
exports: []string{"archive"},
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
basePartitionTables: defaultBasePartitionTables,
}
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "archive"},
[]string{"archive"},
)
gceRhuiImgType = imageType{
name: "gce-rhui",
filename: "image.tar.gz",
mimeType: "application/gzip",
packageSets: map[string]packageSetFunc{
osPkgsKey: gceRhuiPackageSet,
},
kernelOptions: gceKernelOptions,
bootable: true,
defaultSize: 20 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "archive"},
exports: []string{"archive"},
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
basePartitionTables: defaultBasePartitionTables,
}
)
func mkGCEImageType() imageType {
it := gceImgType
// The configuration for non-RHUI images does not touch the RHSM configuration at all.
// https://issues.redhat.com/browse/COMPOSER-2157
it.defaultImageConfig = baseGCEImageConfig()
it.DefaultImageConfig = baseGCEImageConfig()
it.KernelOptions = gceKernelOptions
it.DefaultSize = 20 * common.GibiByte
it.Bootable = true
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkGCERHUIImageType() imageType {
it := gceRhuiImgType
it.defaultImageConfig = defaultGceRhuiImageConfig()
func mkGCERHUIImageType() *rhel.ImageType {
it := rhel.NewImageType(
"gce-rhui",
"image.tar.gz",
"application/gzip",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: gceRhuiPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = defaultGceRhuiImageConfig()
it.KernelOptions = gceKernelOptions
it.DefaultSize = 20 * common.GibiByte
it.Bootable = true
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
it.BasePartitionTables = defaultBasePartitionTables
return it
}
@ -186,7 +185,7 @@ func defaultGceRhuiImageConfig() *distro.ImageConfig {
return ic.InheritFrom(baseGCEImageConfig())
}
func gceCommonPackageSet(t *imageType) rpmmd.PackageSet {
func gceCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
@ -268,12 +267,12 @@ func gceCommonPackageSet(t *imageType) rpmmd.PackageSet {
}
// GCE BYOS image
func gcePackageSet(t *imageType) rpmmd.PackageSet {
func gcePackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return gceCommonPackageSet(t)
}
// GCE RHUI image
func gceRhuiPackageSet(t *imageType) rpmmd.PackageSet {
func gceRhuiPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"google-rhui-client-rhel9",

View file

@ -0,0 +1,205 @@
package rhel9
import (
"fmt"
"log"
"strings"
"golang.org/x/exp/slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/policies"
)
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
customizations := bp.Customizations
// holds warnings (e.g. deprecation notices)
var warnings []string
// we do not support embedding containers on ostree-derived images, only on commits themselves
if len(bp.Containers) > 0 && t.RPMOSTree && (t.Name() != "edge-commit" && t.Name() != "edge-container") {
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.Name(), t.Arch().Distro().Name())
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
}
}
if t.BootISO && t.RPMOSTree {
// ostree-based ISOs require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return nil, 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" {
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.Name())
}
// FDO is optional, but when specified has some restrictions
if customizations.GetFDO() != nil {
if customizations.GetFDO().ManufacturingServerURL == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to when using FDO", t.Name())
}
var diunSet int
if customizations.GetFDO().DiunPubKeyHash != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyInsecure != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyRootCerts != "" {
diunSet++
}
if diunSet != 1 {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to when using FDO", t.Name())
}
}
// ignition is optional, we might be using FDO
if customizations.GetIgnition() != nil {
if customizations.GetIgnition().Embedded != nil && customizations.GetIgnition().FirstBoot != nil {
return warnings, fmt.Errorf("both ignition embedded and firstboot configurations found")
}
if customizations.GetIgnition().FirstBoot != nil && customizations.GetIgnition().FirstBoot.ProvisioningURL == "" {
return warnings, fmt.Errorf("ignition.firstboot requires a provisioning url")
}
}
} else if t.Name() == "edge-installer" {
allowed := []string{"User", "Group", "FIPS", "Installer", "Timezone", "Locale"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
}
}
}
if t.Name() == "edge-raw-image" || t.Name() == "edge-ami" || t.Name() == "edge-vsphere" {
// ostree-based bootable images require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return warnings, fmt.Errorf("%q images require specifying a URL from which to retrieve the OSTree commit", t.Name())
}
allowed := []string{"Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.Name(), strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer"
}
// warn that user & group customizations on edge-commit, edge-container are deprecated
// TODO(edge): directly error if these options are provided when rhel-9.5's time arrives
if t.Name() == "edge-commit" || t.Name() == "edge-container" {
if customizations.GetUsers() != nil {
w := fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetGroups() != nil {
w := fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())
log.Print(w)
warnings = append(warnings, w)
}
}
if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.RPMOSTree && t.Name() != "edge-raw-image" && t.Name() != "edge-simplified-installer" {
return warnings, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
}
if slices.Contains(t.UnsupportedPartitioningModes, options.PartitioningMode) {
return warnings, fmt.Errorf("partitioning mode %q is not supported for %q", options.PartitioningMode, t.Name())
}
mountpoints := customizations.GetFilesystems()
if mountpoints != nil && t.RPMOSTree && (t.Name() == "edge-container" || t.Name() == "edge-commit") {
return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types")
} else if mountpoints != nil && t.RPMOSTree && !(t.Name() == "edge-container" || t.Name() == "edge-commit") {
//customization allowed for edge-raw-image,edge-ami,edge-vsphere,edge-simplified-installer
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.OstreeMountpointPolicies)
if err != nil {
return warnings, err
}
}
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
if osc := customizations.GetOpenSCAP(); osc != nil {
if t.Arch().Distro().OsVersion() == "9.0" {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported os version: %s", t.Arch().Distro().OsVersion()))
}
if !oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList) {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported profile: %s", osc.ProfileID))
}
if t.RPMOSTree {
return warnings, fmt.Errorf("OpenSCAP customizations are not supported for ostree types")
}
if osc.ProfileID == "" {
return warnings, fmt.Errorf("OpenSCAP profile cannot be empty")
}
}
// Check Directory/File Customizations are valid
dc := customizations.GetDirectories()
fc := customizations.GetFiles()
err = blueprint.ValidateDirFileCustomizations(dc, fc)
if err != nil {
return warnings, err
}
dcp := policies.CustomDirectoriesPolicies
fcp := policies.CustomFilesPolicies
if t.RPMOSTree {
dcp = policies.OstreeCustomDirectoriesPolicies
fcp = policies.OstreeCustomFilesPolicies
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
if err != nil {
return warnings, err
}
// check if repository customizations are valid
_, err = customizations.GetRepositories()
if err != nil {
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetInstaller() != nil {
// only supported by the Anaconda installer
if slices.Index([]string{"image-installer", "edge-installer", "live-installer"}, t.Name()) == -1 {
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.Name())
}
}
return warnings, nil
}

View file

@ -6,13 +6,14 @@ import (
"fmt"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
// BUILD PACKAGE SETS
// distro-wide build package set
func distroBuildPackageSet(t *imageType) rpmmd.PackageSet {
func distroBuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"dnf",
@ -33,7 +34,7 @@ func distroBuildPackageSet(t *imageType) rpmmd.PackageSet {
},
}
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664BuildPackageSet(t))
@ -46,7 +47,7 @@ func distroBuildPackageSet(t *imageType) rpmmd.PackageSet {
}
// x86_64 build package set
func x8664BuildPackageSet(t *imageType) rpmmd.PackageSet {
func x8664BuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2-pc",
@ -55,7 +56,7 @@ func x8664BuildPackageSet(t *imageType) rpmmd.PackageSet {
}
// ppc64le build package set
func ppc64leBuildPackageSet(t *imageType) rpmmd.PackageSet {
func ppc64leBuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"grub2-ppc64le",
@ -66,7 +67,7 @@ func ppc64leBuildPackageSet(t *imageType) rpmmd.PackageSet {
// installer boot package sets, needed for booting and
// also in the build host
func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
func anacondaBootPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{}
grubCommon := rpmmd.PackageSet{
@ -83,7 +84,7 @@ func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
},
}
switch t.arch.Name() {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(grubCommon)
ps = ps.Append(efiCommon)
@ -110,7 +111,7 @@ func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
})
default:
panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name()))
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps
@ -119,8 +120,8 @@ func anacondaBootPackageSet(t *imageType) rpmmd.PackageSet {
// OS package sets
// packages that are only in some (sub)-distributions
func distroSpecificPackageSet(t *imageType) rpmmd.PackageSet {
if t.arch.distro.isRHEL() {
func distroSpecificPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
if t.IsRHEL() {
return rpmmd.PackageSet{
Include: []string{
"insights-client",
@ -130,7 +131,7 @@ func distroSpecificPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{}
}
func minimalrpmPackageSet(t *imageType) rpmmd.PackageSet {
func minimalrpmPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",

View file

@ -4,15 +4,16 @@ import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro/rhel"
)
func defaultBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
var bootSize uint64
switch {
case common.VersionLessThan(t.arch.distro.osVersion, "9.3") && t.arch.distro.isRHEL():
case common.VersionLessThan(t.Arch().Distro().OsVersion(), "9.3") && t.IsRHEL():
// RHEL <= 9.2 had only 500 MiB /boot
bootSize = 500 * common.MebiByte
case common.VersionLessThan(t.arch.distro.osVersion, "9.4") && t.arch.distro.isRHEL():
case common.VersionLessThan(t.Arch().Distro().OsVersion(), "9.4") && t.IsRHEL():
// RHEL 9.3 had 600 MiB /boot, see RHEL-7999
bootSize = 600 * common.MebiByte
default:
@ -20,8 +21,8 @@ func defaultBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
bootSize = 1 * common.GibiByte
}
switch t.platform.GetArch() {
case arch.ARCH_X86_64:
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -74,7 +75,7 @@ func defaultBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
},
},
}, true
case arch.ARCH_AARCH64:
case arch.ARCH_AARCH64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
@ -121,7 +122,7 @@ func defaultBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
},
},
}, true
case arch.ARCH_PPC64LE:
case arch.ARCH_PPC64LE.String():
return disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
@ -155,7 +156,7 @@ func defaultBasePartitionTables(t *imageType) (disk.PartitionTable, bool) {
},
}, true
case arch.ARCH_S390X:
case arch.ARCH_S390X.String():
return disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",

View file

@ -3,37 +3,88 @@ package rhel9
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/subscription"
)
var (
openstackImgType = imageType{
name: "openstack",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
packageSets: map[string]packageSetFunc{
osPkgsKey: openstackCommonPackageSet,
func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"qcow2",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
},
kernelOptions: "ro net.ifnames=0",
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: defaultBasePartitionTables,
}
)
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0"
it.DefaultSize = 10 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"oci",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0"
it.DefaultSize = 10 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOpenstackImgType() *rhel.ImageType {
it := rhel.NewImageType(
"openstack",
"disk.qcow2",
"application/x-qemu-disk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: openstackCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
}
it.KernelOptions = "ro net.ifnames=0"
it.DefaultSize = 4 * common.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func qcow2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"authselect-compat",
"chrony",
"cloud-init",
"cloud-utils-growpart",
@ -93,12 +144,8 @@ func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
},
}.Append(distroSpecificPackageSet(t))
if t.arch.distro.releaseVersion == "9" {
ps.Include = append(ps.Include, "authselect-compat")
}
// Ensure to not pull in subscription-manager on non-RHEL distro
if t.arch.distro.isRHEL() {
if t.IsRHEL() {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"subscription-manager-cockpit",
@ -109,7 +156,7 @@ func qcow2CommonPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func openstackCommonPackageSet(t *imageType) rpmmd.PackageSet {
func openstackCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
// Defaults
@ -131,11 +178,11 @@ func openstackCommonPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func qcowImageConfig(d distribution) *distro.ImageConfig {
func qcowImageConfig(d *rhel.Distribution) *distro.ImageConfig {
ic := &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"),
}
if d.isRHEL() {
if d.IsRHEL() {
ic.RHSMConfig = map[subscription.RHSMStatus]*osbuild.RHSMStageOptions{
subscription.RHSMConfigNoSubscription: {
DnfPlugins: &osbuild.RHSMStageOptionsDnfPlugins{
@ -152,24 +199,3 @@ func qcowImageConfig(d distribution) *distro.ImageConfig {
}
return ic
}
func mkQcow2ImgType(d distribution) imageType {
it := imageType{
name: "qcow2",
filename: "disk.qcow2",
mimeType: "application/x-qemu-disk",
kernelOptions: "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0",
packageSets: map[string]packageSetFunc{
osPkgsKey: qcow2CommonPackageSet,
},
bootable: true,
defaultSize: 10 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "qcow2"},
exports: []string{"qcow2"},
basePartitionTables: defaultBasePartitionTables,
}
it.defaultImageConfig = qcowImageConfig(d)
return it
}

View file

@ -2,6 +2,7 @@ package rhel9
import (
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
@ -118,7 +119,7 @@ func sapImageConfig(osVersion string) *distro.ImageConfig {
}
}
func SapPackageSet(t *imageType) rpmmd.PackageSet {
func SapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
// RHBZ#2076763

View file

@ -3,18 +3,26 @@ package rhel9
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
var wslImgType = imageType{
name: "wsl",
filename: "disk.tar.gz",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: ubiCommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
func mkWSLImgType() *rhel.ImageType {
it := rhel.NewImageType(
"wsl",
"disk.tar.gz",
"application/x-tar",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ubiCommonPackageSet,
},
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{
@ -22,15 +30,12 @@ var wslImgType = imageType{
Systemd: true,
},
},
},
bootable: false,
image: tarImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "archive"},
exports: []string{"archive"},
}
return it
}
func ubiCommonPackageSet(t *imageType) rpmmd.PackageSet {
func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"alternatives",

View file

@ -0,0 +1,80 @@
package rhel9
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
const vmdkKernelOptions = "ro net.ifnames=0"
func mkVMDKImgType() *rhel.ImageType {
it := rhel.NewImageType(
"vmdk",
"disk.vmdk",
"application/x-vmdk",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk"},
[]string{"vmdk"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
}
it.KernelOptions = vmdkKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOVAImgType() *rhel.ImageType {
it := rhel.NewImageType(
"ova",
"image.ova",
"application/ovf",
map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet,
},
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk", "ovf", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
}
it.KernelOptions = vmdkKernelOptions
it.Bootable = true
it.DefaultSize = 4 * common.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func vmdkCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"firewalld",
"langpacks-en",
"open-vm-tools",
"tuned",
},
Exclude: []string{
"dracut-config-rescue",
"rng-tools",
},
}
return ps
}

View file

@ -46,6 +46,7 @@ var defaultDistroImageConfig = &distro.ImageConfig{
},
},
},
KernelOptionsBootloader: common.ToPtr(true),
}
// --- Distribution ---

View file

@ -6,7 +6,6 @@ import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/users"
@ -23,7 +22,7 @@ func osCustomizations(
options distro.ImageOptions,
containers []container.SourceSpec,
c *blueprint.Customizations,
) manifest.OSCustomizations {
) (manifest.OSCustomizations, error) {
imageConfig := t.getDefaultImageConfig()
@ -40,8 +39,8 @@ func osCustomizations(
kernelOptions = append(kernelOptions, bpKernel.Append)
}
osc.KernelOptionsAppend = kernelOptions
if t.platform.GetArch() != arch.ARCH_S390X {
osc.KernelOptionsBootloader = true
if imageConfig.KernelOptionsBootloader != nil {
osc.KernelOptionsBootloader = *imageConfig.KernelOptionsBootloader
}
}
@ -131,10 +130,18 @@ func osCustomizations(
}
if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil {
var datastream = oscapConfig.DataStream
if datastream == "" {
if imageConfig.DefaultOSCAPDatastream == nil {
return manifest.OSCustomizations{}, fmt.Errorf("No OSCAP datastream specified and the distro does not have any default set")
}
datastream = *imageConfig.DefaultOSCAPDatastream
}
osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(
oscapDataDir,
osbuild.OscapConfig{
Datastream: oscapConfig.DataStream,
Datastream: datastream,
ProfileID: oscapConfig.ProfileID,
Compression: true,
},
@ -219,7 +226,7 @@ func osCustomizations(
osc.Files = append(osc.Files, imageConfig.Files...)
osc.Directories = append(osc.Directories, imageConfig.Directories...)
return osc
return osc, nil
}
func diskImage(workload workload.Workload,
@ -232,7 +239,13 @@ func diskImage(workload workload.Workload,
img := image.NewDiskImage()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
if err != nil {
return nil, err
}
img.Environment = t.environment
img.Workload = workload
img.Compression = t.compression

View file

@ -287,12 +287,15 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
dcp := policies.CustomDirectoriesPolicies
fcp := policies.CustomFilesPolicies
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
if err != nil {
return warnings, err
}

View file

@ -1,532 +0,0 @@
package rhel8
import (
"errors"
"fmt"
"sort"
"strings"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/runner"
)
var (
// rhel8 allow all
oscapProfileAllowList = []oscap.Profile{
oscap.AnssiBp28Enhanced,
oscap.AnssiBp28High,
oscap.AnssiBp28Intermediary,
oscap.AnssiBp28Minimal,
oscap.Cis,
oscap.CisServerL1,
oscap.CisWorkstationL1,
oscap.CisWorkstationL2,
oscap.Cui,
oscap.E8,
oscap.Hippa,
oscap.IsmO,
oscap.Ospp,
oscap.PciDss,
oscap.Stig,
oscap.StigGui,
}
)
type distribution struct {
name string
product string
osVersion string
releaseVersion string
modulePlatformID string
vendor string
ostreeRefTmpl string
runner runner.Runner
arches map[string]distro.Arch
defaultImageConfig *distro.ImageConfig
}
// RHEL-based OS image configuration defaults
var defaultDistroImageConfig = &distro.ImageConfig{
Timezone: common.ToPtr("America/New_York"),
Locale: common.ToPtr("en_US.UTF-8"),
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
}
func (d *distribution) Name() string {
return d.name
}
func (d *distribution) Releasever() string {
return d.releaseVersion
}
func (d *distribution) OsVersion() string {
return d.osVersion
}
func (d *distribution) Product() string {
return d.product
}
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")
}
func (d *distribution) getDefaultImageConfig() *distro.ImageConfig {
return d.defaultImageConfig
}
func newDistro(name string, minor int) *distribution {
var rd distribution
switch name {
case "rhel":
rd = distribution{
name: fmt.Sprintf("rhel-8.%d", minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("8.%d", minor),
releaseVersion: "8",
modulePlatformID: "platform:el8",
vendor: "redhat",
ostreeRefTmpl: "rhel/8/%s/edge",
runner: &runner.RHEL{Major: uint64(8), Minor: uint64(minor)},
defaultImageConfig: defaultDistroImageConfig,
}
case "centos":
rd = distribution{
name: "centos-8",
product: "CentOS Stream",
osVersion: "8-stream",
releaseVersion: "8",
modulePlatformID: "platform:el8",
vendor: "centos",
ostreeRefTmpl: "centos/8/%s/edge",
runner: &runner.CentOS{Version: uint64(8)},
defaultImageConfig: defaultDistroImageConfig,
}
default:
panic(fmt.Sprintf("unknown distro name: %s", name))
}
// Architecture definitions
x86_64 := architecture{
name: arch.ARCH_X86_64.String(),
distro: &rd,
}
aarch64 := architecture{
name: arch.ARCH_AARCH64.String(),
distro: &rd,
}
ppc64le := architecture{
distro: &rd,
name: arch.ARCH_PPC64LE.String(),
}
s390x := architecture{
distro: &rd,
name: arch.ARCH_S390X.String(),
}
ociImgType := qcow2ImgType(rd)
ociImgType.name = "oci"
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
qcow2ImgType(rd),
ociImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
openstackImgType(),
)
ec2X86Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
x86_64.addImageTypes(
ec2X86Platform,
amiImgTypeX86_64(rd),
)
bareMetalX86Platform := &platform.X86{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"microcode_ctl", // ??
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6050-firmware",
},
},
BIOS: true,
UEFIVendor: rd.vendor,
}
x86_64.addImageTypes(
bareMetalX86Platform,
edgeOCIImgType(rd),
edgeCommitImgType(rd),
edgeInstallerImgType(rd),
imageInstaller(),
)
gceX86Platform := &platform.X86{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_GCE,
},
}
x86_64.addImageTypes(
gceX86Platform,
gceImgType(rd),
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
vmdkImgType(),
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_OVA,
},
},
ovaImgType(),
)
x86_64.addImageTypes(
&platform.X86{},
tarImgType(),
wslImgType(),
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
qcow2ImgType(rd),
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
openstackImgType(),
)
aarch64.addImageTypes(
&platform.Aarch64{},
tarImgType(),
wslImgType(),
)
bareMetalAarch64Platform := &platform.Aarch64{
BasePlatform: platform.BasePlatform{},
UEFIVendor: rd.vendor,
}
aarch64.addImageTypes(
bareMetalAarch64Platform,
edgeOCIImgType(rd),
edgeCommitImgType(rd),
edgeInstallerImgType(rd),
imageInstaller(),
)
rawAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
aarch64.addImageTypes(
rawAarch64Platform,
amiImgTypeAarch64(rd),
minimalRawImgType(rd),
)
ppc64le.addImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
qcow2ImgType(rd),
)
ppc64le.addImageTypes(
&platform.PPC64LE{},
tarImgType(),
)
s390x.addImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
qcow2ImgType(rd),
)
s390x.addImageTypes(
&platform.S390X{},
tarImgType(),
)
azureX64Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
azureAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
rawUEFIx86Platform := &platform.X86{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
BIOS: false,
UEFIVendor: rd.vendor,
}
x86_64.addImageTypes(
rawUEFIx86Platform,
minimalRawImgType(rd),
)
if rd.isRHEL() {
if common.VersionGreaterThanOrEqual(rd.osVersion, "8.6") {
// image types only available on 8.6 and later on RHEL
// These edge image types require FDO which aren't available on older versions
x86_64.addImageTypes(
bareMetalX86Platform,
edgeRawImgType(),
)
x86_64.addImageTypes(
rawUEFIx86Platform,
edgeSimplifiedInstallerImgType(rd),
)
azureEap := azureEap7RhuiImgType()
x86_64.addImageTypes(azureX64Platform, azureEap)
aarch64.addImageTypes(
rawAarch64Platform,
edgeRawImgType(),
edgeSimplifiedInstallerImgType(rd),
)
// The Azure image types require hyperv-daemons which isn't available on older versions
aarch64.addImageTypes(azureAarch64Platform, azureRhuiImgType(), azureByosImgType())
}
// add azure to RHEL distro only
x86_64.addImageTypes(azureX64Platform, azureRhuiImgType(), azureByosImgType(), azureSapRhuiImgType(rd))
// keep the RHEL EC2 x86_64 images before 8.9 BIOS-only for backward compatibility
if common.VersionLessThan(rd.osVersion, "8.9") {
ec2X86Platform = &platform.X86{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
}
// add ec2 image types to RHEL distro only
x86_64.addImageTypes(ec2X86Platform, ec2ImgTypeX86_64(rd), ec2HaImgTypeX86_64(rd))
aarch64.addImageTypes(rawAarch64Platform, ec2ImgTypeAarch64(rd))
if rd.osVersion != "8.5" {
// NOTE: RHEL 8.5 is going away and these image types require some
// work to get working, so we just disable them here until the
// whole distro gets deleted
x86_64.addImageTypes(ec2X86Platform, ec2SapImgTypeX86_64(rd))
}
// add GCE RHUI image to RHEL only
x86_64.addImageTypes(gceX86Platform, gceRhuiImgType(rd))
// add s390x to RHEL distro only
rd.addArches(s390x)
} else {
x86_64.addImageTypes(
bareMetalX86Platform,
edgeRawImgType(),
)
x86_64.addImageTypes(
rawUEFIx86Platform,
edgeSimplifiedInstallerImgType(rd),
)
x86_64.addImageTypes(azureX64Platform, azureImgType())
aarch64.addImageTypes(
rawAarch64Platform,
edgeRawImgType(),
edgeSimplifiedInstallerImgType(rd),
)
aarch64.addImageTypes(azureAarch64Platform, azureImgType())
}
rd.addArches(x86_64, aarch64, ppc64le)
return &rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
// Backward compatibility layer for "rhel-84" or "rhel-810"
if id.Name == "rhel" && id.MinorVersion == -1 {
if id.MajorVersion/10 == 8 {
// handle single digit minor version
id.MinorVersion = id.MajorVersion % 10
id.MajorVersion = 8
} else if id.MajorVersion/100 == 8 {
// handle two digit minor version
id.MinorVersion = id.MajorVersion % 100
id.MajorVersion = 8
}
}
if id.MajorVersion != 8 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, id.MinorVersion)
}

View file

@ -1,423 +0,0 @@
package rhel8
import (
"fmt"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
)
func edgeCommitImgType(rd distribution) imageType {
it := imageType{
name: "edge-commit",
nameAliases: []string{"rhel-edge-commit"},
filename: "commit.tar",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: edgeCommitPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices(rd),
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
},
rpmOstree: true,
image: edgeCommitImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "ostree-commit", "commit-archive"},
exports: []string{"commit-archive"},
}
return it
}
func edgeOCIImgType(rd distribution) imageType {
it := imageType{
name: "edge-container",
nameAliases: []string{"rhel-edge-container"},
filename: "container.tar",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: edgeCommitPackageSet,
containerPkgsKey: func(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{"nginx"},
}
},
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices(rd),
DracutConf: []*osbuild.DracutConfStageOptions{osbuild.FIPSDracutConfStageOptions},
},
rpmOstree: true,
bootISO: false,
image: edgeContainerImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "ostree-commit", "container-tree", "container"},
exports: []string{"container"},
}
return it
}
func edgeRawImgType() imageType {
it := imageType{
name: "edge-raw-image",
nameAliases: []string{"rhel-edge-raw-image"},
filename: "image.raw.xz",
compression: "xz",
mimeType: "application/xz",
image: edgeRawImage,
packageSets: nil,
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
bootable: true,
bootISO: false,
kernelOptions: "modprobe.blacklist=vc4",
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-deployment", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: edgeBasePartitionTables,
}
return it
}
func edgeInstallerImgType(rd distribution) imageType {
it := 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.
installerPkgsKey: edgeInstallerPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices(rd),
},
rpmOstree: true,
bootISO: true,
image: edgeInstallerImage,
isoLabel: distroISOLabelFunc,
buildPipelines: []string{"build"},
payloadPipelines: []string{"anaconda-tree", "rootfs-image", "efiboot-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
}
return it
}
func edgeSimplifiedInstallerImgType(rd distribution) imageType {
it := 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.
installerPkgsKey: edgeSimplifiedInstallerPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: edgeServices(rd),
},
defaultSize: 10 * common.GibiByte,
rpmOstree: true,
bootable: true,
bootISO: true,
image: edgeSimplifiedInstallerImage,
isoLabel: distroISOLabelFunc,
buildPipelines: []string{"build"},
payloadPipelines: []string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"},
basePartitionTables: edgeBasePartitionTables,
}
return it
}
func minimalRawImgType(rd distribution) imageType {
it := imageType{
name: "minimal-raw",
filename: "disk.raw.xz",
compression: "xz",
mimeType: "application/xz",
packageSets: map[string]packageSetFunc{
osPkgsKey: minimalrpmPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
EnabledServices: minimalrawServices(rd),
// NOTE: temporary workaround for a bug in initial-setup that
// requires a kickstart file in the root directory.
Files: []*fsnode.File{initialSetupKickstart()},
},
rpmOstree: false,
kernelOptions: "ro",
bootable: true,
defaultSize: 2 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "xz"},
exports: []string{"xz"},
basePartitionTables: defaultBasePartitionTables,
}
return it
}
// edge commit OS package set
func edgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"attr",
"audit",
"basesystem",
"bash",
"bash-completion",
"chrony",
"clevis",
"clevis-dracut",
"clevis-luks",
"container-selinux",
"coreutils",
"criu",
"cryptsetup",
"curl",
"dnsmasq",
"dosfstools",
"dracut-config-generic",
"dracut-network",
"e2fsprogs",
"firewalld",
"fuse-overlayfs",
"fwupd",
"glibc",
"glibc-minimal-langpack",
"gnupg2",
"greenboot",
"gzip",
"hostname",
"ima-evm-utils",
"iproute",
"iptables",
"iputils",
"keyutils",
"less",
"lvm2",
"NetworkManager",
"NetworkManager-wifi",
"NetworkManager-wwan",
"nss-altfiles",
"openssh-clients",
"openssh-server",
"passwd",
"pinentry",
"platform-python",
"podman",
"policycoreutils",
"policycoreutils-python-utils",
"polkit",
"procps-ng",
"redhat-release",
"rootfiles",
"rpm",
"rpm-ostree",
"rsync",
"selinux-policy-targeted",
"setools-console",
"setup",
"shadow-utils",
"shadow-utils",
"skopeo",
"slirp4netns",
"sudo",
"systemd",
"tar",
"tmux",
"traceroute",
"usbguard",
"util-linux",
"vim-minimal",
"wpa_supplicant",
"xz",
},
Exclude: []string{"rng-tools"},
}
switch t.arch.Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664EdgeCommitPackageSet(t))
case arch.ARCH_AARCH64.String():
ps = ps.Append(aarch64EdgeCommitPackageSet(t))
}
if t.arch.distro.isRHEL() && common.VersionLessThan(t.arch.distro.osVersion, "8.6") {
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"greenboot-grub2",
"greenboot-reboot",
"greenboot-rpm-ostree-grub2",
"greenboot-status",
},
})
} else {
// 8.6+ and CS8
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"fdo-client",
"fdo-owner-cli",
"greenboot-default-health-checks",
"sos",
},
})
}
return ps
}
func x8664EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"efibootmgr",
"grub2",
"grub2-efi-x64",
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6000-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
"microcode_ctl",
"shim-x64",
},
Exclude: nil,
}
}
func aarch64EdgeCommitPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"efibootmgr",
"grub2-efi-aa64",
"iwl7260-firmware",
"shim-aa64",
},
Exclude: nil,
}
}
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",
"clevis-dracut",
"clevis-luks",
"cloud-utils-growpart",
"coreos-installer",
"coreos-installer-dracut",
"coreutils",
"device-mapper-multipath",
"dnsmasq",
"dosfstools",
"dracut-live",
"e2fsprogs",
"fcoe-utils",
"fdo-init",
"gzip",
"ima-evm-utils",
"iproute",
"iptables",
"iputils",
"iscsi-initiator-utils",
"keyutils",
"lldpad",
"lvm2",
"passwd",
"policycoreutils",
"policycoreutils-python-utils",
"procps-ng",
"redhat-logos",
"rootfiles",
"setools-console",
"sudo",
"traceroute",
"util-linux",
},
Exclude: nil,
})
switch t.arch.Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(x8664EdgeCommitPackageSet(t))
case arch.ARCH_AARCH64.String():
ps = ps.Append(aarch64EdgeCommitPackageSet(t))
default:
panic(fmt.Sprintf("unsupported arch: %s", t.arch.Name()))
}
return ps
}
func edgeServices(rd distribution) []string {
// Common Services
var edgeServices = []string{"NetworkManager.service", "firewalld.service", "sshd.service"}
if rd.osVersion == "8.4" {
// greenboot services aren't enabled by default in 8.4
edgeServices = append(edgeServices,
"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")
}
if !(rd.isRHEL() && common.VersionLessThan(rd.osVersion, "8.6")) {
// enable fdo-client only on RHEL 8.6+ and CS8
// TODO(runcom): move fdo-client-linuxapp.service to presets?
edgeServices = append(edgeServices, "fdo-client-linuxapp.service")
}
return edgeServices
}
func minimalrawServices(rd distribution) []string {
// Common Services
var minimalrawServices = []string{"NetworkManager.service", "firewalld.service", "sshd.service", "initial-setup.service"}
return minimalrawServices
}

View file

@ -1,469 +0,0 @@
package rhel8
import (
"fmt"
"log"
"math/rand"
"strings"
"golang.org/x/exp/slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/policies"
"github.com/osbuild/images/pkg/rpmmd"
)
const (
// package set names
// main/common os image package set name
osPkgsKey = "os"
// container package set name
containerPkgsKey = "container"
// installer package set name
installerPkgsKey = "installer"
// blueprint package set name
blueprintPkgsKey = "blueprint"
// location for saving openscap remediation data
oscapDataDir = "/oscap_data"
)
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error)
type packageSetFunc func(t *imageType) rpmmd.PackageSet
type isoLabelFunc func(t *imageType) string
type imageType struct {
arch *architecture
platform platform.Platform
environment environment.Environment
workload workload.Workload
name string
nameAliases []string
filename string
compression string // TODO: remove from image definition and make it a transport option
mimeType string
packageSets map[string]packageSetFunc
defaultImageConfig *distro.ImageConfig
kernelOptions string
defaultSize uint64
buildPipelines []string
payloadPipelines []string
exports []string
image imageFunc
isoLabel isoLabelFunc
// bootISO: installable ISO
bootISO bool
// rpmOstree: edge/ostree
rpmOstree bool
// bootable image
bootable bool
// 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) ISOLabel() (string, error) {
if !t.bootISO {
return "", fmt.Errorf("image type %q is not an ISO", t.name)
}
if t.isoLabel != nil {
return t.isoLabel(t), nil
}
return "", nil
}
func (t *imageType) Size(size uint64) uint64 {
// Microsoft Azure requires vhd images to be rounded up to the nearest MB
if t.name == "vhd" && size%common.MebiByte != 0 {
size = (size/common.MebiByte + 1) * common.MebiByte
}
if size == 0 {
size = t.defaultSize
}
return size
}
func (t *imageType) BuildPipelines() []string {
return t.buildPipelines
}
func (t *imageType) PayloadPipelines() []string {
return t.payloadPipelines
}
func (t *imageType) PayloadPackageSets() []string {
return []string{blueprintPkgsKey}
}
func (t *imageType) PackageSetsChains() map[string][]string {
return nil
}
func (t *imageType) Exports() []string {
if len(t.exports) > 0 {
return t.exports
}
return []string{"assembler"}
}
func (t *imageType) BootMode() distro.BootMode {
if t.platform.GetUEFIVendor() != "" && t.platform.GetBIOSPlatform() != "" {
return distro.BOOT_HYBRID
} else if t.platform.GetUEFIVendor() != "" {
return distro.BOOT_UEFI
} else if t.platform.GetBIOSPlatform() != "" || t.platform.GetZiplSupport() {
return distro.BOOT_LEGACY
}
return distro.BOOT_NONE
}
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 nil, fmt.Errorf("no partition table defined for architecture %q for image type %q", archName, t.Name())
}
imageSize := t.Size(options.Size)
partitioningMode := options.PartitioningMode
if t.rpmOstree {
// Edge supports only raw, force it.
// LVM is not supported, return an error if it is requested
// TODO Need a central location for logic like this
if partitioningMode == disk.LVMPartitioningMode {
return nil, fmt.Errorf("partitioning mode lvm not supported for %s on %s", t.Name(), t.arch.Name())
}
partitioningMode = disk.RawPartitioningMode
}
return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, partitioningMode, nil, rng)
}
func (t *imageType) getDefaultImageConfig() *distro.ImageConfig {
// ensure that image always returns non-nil default config
imageConfig := t.defaultImageConfig
if imageConfig == nil {
imageConfig = &distro.ImageConfig{}
}
return imageConfig.InheritFrom(t.arch.distro.getDefaultImageConfig())
}
func (t *imageType) PartitionType() string {
archName := t.arch.Name()
basePartitionTable, exists := t.basePartitionTables[archName]
if !exists {
return ""
}
return basePartitionTable.Type
}
func (t *imageType) Manifest(bp *blueprint.Blueprint,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
seed int64) (*manifest.Manifest, []string, error) {
warnings, err := t.checkOptions(bp, options)
if err != nil {
return nil, nil, err
}
// merge package sets that appear in the image type with the package sets
// of the same name from the distro and arch
staticPackageSets := make(map[string]rpmmd.PackageSet)
for name, getter := range t.packageSets {
staticPackageSets[name] = getter(t)
}
// amend with repository information and collect payload repos
payloadRepos := make([]rpmmd.RepoConfig, 0)
for _, repo := range repos {
if len(repo.PackageSets) > 0 {
// only apply the repo to the listed package sets
for _, psName := range repo.PackageSets {
if slices.Contains(t.PayloadPackageSets(), psName) {
payloadRepos = append(payloadRepos, repo)
}
ps := staticPackageSets[psName]
ps.Repositories = append(ps.Repositories, repo)
staticPackageSets[psName] = ps
}
}
}
w := t.workload
if w == nil {
cw := &workload.Custom{
BaseWorkload: workload.BaseWorkload{
Repos: payloadRepos,
},
Packages: bp.GetPackagesEx(false),
}
if services := bp.Customizations.GetServices(); services != nil {
cw.Services = services.Enabled
cw.DisabledServices = services.Disabled
}
w = cw
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
Local: cont.LocalStorage,
}
}
source := rand.NewSource(seed)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(source)
if t.image == nil {
return nil, nil, nil
}
img, err := t.image(w, t, bp.Customizations, options, staticPackageSets, containerSources, rng)
if err != nil {
return nil, nil, err
}
mf := manifest.New()
mf.Distro = manifest.DISTRO_EL8
_, err = img.InstantiateManifest(&mf, repos, t.arch.distro.runner, rng)
if err != nil {
return nil, nil, err
}
return &mf, warnings, err
}
func distroISOLabelFunc(t *imageType) string {
const RHEL_ISO_LABEL = "RHEL-8-%s-0-BaseOS-%s"
const CS_ISO_LABEL = "CentOS-Stream-8-%s-dvd"
if t.arch.distro.isRHEL() {
minor := strings.Split(t.Arch().Distro().OsVersion(), ".")[1]
return fmt.Sprintf(RHEL_ISO_LABEL, minor, t.Arch().Name())
} else {
return fmt.Sprintf(CS_ISO_LABEL, t.Arch().Name())
}
}
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
customizations := bp.Customizations
// holds warnings (e.g. deprecation notices)
var warnings []string
if t.workload != nil {
// For now, if an image type defines its own workload, don't allow any
// user customizations.
// Soon we will have more workflows and each will define its allowed
// set of customizations. The current set of customizations defined in
// the blueprint spec corresponds to the Custom workflow.
if customizations != nil {
return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name)
}
}
// we do not support embedding containers on ostree-derived images, only on commits themselves
if len(bp.Containers) > 0 && t.rpmOstree && (t.name != "edge-commit" && t.name != "edge-container") {
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name)
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
}
}
if t.bootISO && t.rpmOstree {
// ostree-based ISOs require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return nil, 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" {
allowed := []string{"InstallationDevice", "FDO", "User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name)
}
//making fdo optional so that simplified installer can be composed w/o the FDO section in the blueprint
if customizations.GetFDO() != nil {
if customizations.GetFDO().ManufacturingServerURL == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to", t.name)
}
var diunSet int
if customizations.GetFDO().DiunPubKeyHash != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyInsecure != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyRootCerts != "" {
diunSet++
}
if diunSet != 1 {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to", t.name)
}
}
} else if t.name == "edge-installer" {
allowed := []string{"User", "Group", "FIPS", "Installer", "Timezone", "Locale"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
}
}
if t.name == "edge-raw-image" {
// ostree-based bootable images require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return warnings, fmt.Errorf("%q images require specifying a URL from which to retrieve the OSTree commit", t.name)
}
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer"
}
// warn that user & group customizations on edge-commit, edge-container are deprecated
// TODO(edge): directly error if these options are provided when rhel-9.5's time arrives
if t.name == "edge-commit" || t.name == "edge-container" {
if customizations.GetUsers() != nil {
w := fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.name)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetGroups() != nil {
w := fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.name)
log.Print(w)
warnings = append(warnings, w)
}
}
if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.rpmOstree && t.name != "edge-raw-image" && t.name != "edge-simplified-installer" {
return warnings, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
}
mountpoints := customizations.GetFilesystems()
if mountpoints != nil && t.rpmOstree {
return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types")
}
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
if osc := customizations.GetOpenSCAP(); osc != nil {
if t.arch.distro.osVersion == "9.0" {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported os version: %s", t.arch.distro.osVersion))
}
if !oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList) {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported profile: %s", osc.ProfileID))
}
if t.rpmOstree {
return warnings, fmt.Errorf("OpenSCAP customizations are not supported for ostree types")
}
if osc.ProfileID == "" {
return warnings, fmt.Errorf("OpenSCAP profile cannot be empty")
}
}
// Check Directory/File Customizations are valid
dc := customizations.GetDirectories()
fc := customizations.GetFiles()
err = blueprint.ValidateDirFileCustomizations(dc, fc)
if err != nil {
return warnings, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
if err != nil {
return warnings, err
}
// check if repository customizations are valid
_, err = customizations.GetRepositories()
if err != nil {
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetInstaller() != nil {
// only supported by the Anaconda installer
if slices.Index([]string{"image-installer", "edge-installer", "live-installer"}, t.name) == -1 {
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.name)
}
}
return warnings, nil
}

View file

@ -1,376 +0,0 @@
package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
)
var defaultBasePartitionTables = distro.BasePartitionTableMap{
arch.ARCH_X86_64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 100 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
arch.ARCH_AARCH64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 100 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
arch.ARCH_PPC64LE.String(): disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
Partitions: []disk.Partition{
{
Size: 4 * common.MebiByte,
Type: "41",
Bootable: true,
},
{
Size: 2 * common.GibiByte,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
arch.ARCH_S390X.String(): disk.PartitionTable{
UUID: "0x14fc63d2",
Type: "dos",
Partitions: []disk.Partition{
{
Size: 2 * common.GibiByte,
Bootable: true,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
}
var edgeBasePartitionTables = distro.BasePartitionTableMap{
arch.ARCH_X86_64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 127 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 384 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 1,
FSTabPassNo: 1,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LUKSContainer{
Label: "crypt_root",
Cipher: "cipher_null",
Passphrase: "osbuild",
PBKDF: disk.Argon2id{
Memory: 32,
Iterations: 4,
Parallelism: 1,
},
Clevis: &disk.ClevisBind{
Pin: "null",
Policy: "{}",
RemovePassphrase: true,
},
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
arch.ARCH_AARCH64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 127 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 384 * common.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 1,
FSTabPassNo: 1,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.LUKSContainer{
Label: "crypt_root",
Cipher: "cipher_null",
Passphrase: "osbuild",
PBKDF: disk.Argon2id{
Memory: 32,
Iterations: 4,
Parallelism: 1,
},
Clevis: &disk.ClevisBind{
Pin: "null",
Policy: "{}",
RemovePassphrase: true,
},
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
}
func getEc2PartitionTables(osVersion string, isRHEL bool) distro.BasePartitionTableMap {
// x86_64 - without /boot
// aarch - <= 8.9 - 512MiB, 8.10 and centos: 1 GiB
var aarch64BootSize uint64
switch {
case common.VersionLessThan(osVersion, "8.10") && isRHEL:
aarch64BootSize = 512 * common.MebiByte
default:
aarch64BootSize = 1 * common.GibiByte
}
x86PartitionTable := disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 200 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}
// RHEL EC2 x86_64 images prior to 8.9 support only BIOS boot
if common.VersionLessThan(osVersion, "8.9") && isRHEL {
x86PartitionTable = disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 1 * common.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}
}
return distro.BasePartitionTableMap{
arch.ARCH_X86_64.String(): x86PartitionTable,
arch.ARCH_AARCH64.String(): disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []disk.Partition{
{
Size: 200 * common.MebiByte,
Type: disk.EFISystemPartitionGUID,
UUID: disk.EFISystemPartitionUUID,
Payload: &disk.Filesystem{
Type: "vfat",
UUID: disk.EFIFilesystemUUID,
Mountpoint: "/boot/efi",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: aarch64BootSize,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * common.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
}
}

View file

@ -1,64 +0,0 @@
package rhel8
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/rpmmd"
)
const vmdkKernelOptions = "ro net.ifnames=0"
func vmdkImgType() imageType {
return imageType{
name: "vmdk",
filename: "disk.vmdk",
mimeType: "application/x-vmdk",
packageSets: map[string]packageSetFunc{
osPkgsKey: vmdkCommonPackageSet,
},
kernelOptions: vmdkKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vmdk"},
exports: []string{"vmdk"},
basePartitionTables: defaultBasePartitionTables,
}
}
func ovaImgType() imageType {
return imageType{
name: "ova",
filename: "image.ova",
mimeType: "application/ovf",
packageSets: map[string]packageSetFunc{
osPkgsKey: vmdkCommonPackageSet,
},
kernelOptions: vmdkKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vmdk", "ovf", "archive"},
exports: []string{"archive"},
basePartitionTables: defaultBasePartitionTables,
}
}
func vmdkCommonPackageSet(t *imageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"firewalld",
"langpacks-en",
"open-vm-tools",
"selinux-policy-targeted",
},
Exclude: []string{
"dracut-config-rescue",
"rng-tools",
},
}
}

View file

@ -1,70 +0,0 @@
package rhel9
import (
"errors"
"fmt"
"sort"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/platform"
)
type architecture struct {
distro *distribution
name string
imageTypes map[string]distro.ImageType
imageTypeAliases map[string]string
}
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(platform platform.Platform, imageTypes ...imageType) {
if a.imageTypes == nil {
a.imageTypes = map[string]distro.ImageType{}
}
for idx := range imageTypes {
it := imageTypes[idx]
it.arch = a
it.platform = platform
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
}

View file

@ -1,592 +0,0 @@
package rhel9
import (
"errors"
"fmt"
"sort"
"strings"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/runner"
)
var (
// rhel9 & cs9 share the same list
// of allowed profiles so a single
// allow list can be used
oscapProfileAllowList = []oscap.Profile{
oscap.AnssiBp28Enhanced,
oscap.AnssiBp28High,
oscap.AnssiBp28Intermediary,
oscap.AnssiBp28Minimal,
oscap.Cis,
oscap.CisServerL1,
oscap.CisWorkstationL1,
oscap.CisWorkstationL2,
oscap.Cui,
oscap.E8,
oscap.Hippa,
oscap.IsmO,
oscap.Ospp,
oscap.PciDss,
oscap.Stig,
oscap.StigGui,
}
)
type distribution struct {
name string
product string
osVersion string
releaseVersion string
modulePlatformID string
vendor string
ostreeRefTmpl string
runner runner.Runner
arches map[string]distro.Arch
defaultImageConfig *distro.ImageConfig
}
// CentOS- and RHEL-based OS image configuration defaults
var defaultDistroImageConfig = &distro.ImageConfig{
Timezone: common.ToPtr("America/New_York"),
Locale: common.ToPtr("C.UTF-8"),
Sysconfig: []*osbuild.SysconfigStageOptions{
{
Kernel: &osbuild.SysconfigKernelOptions{
UpdateDefault: true,
DefaultKernel: "kernel",
},
Network: &osbuild.SysconfigNetworkOptions{
Networking: true,
NoZeroConf: true,
},
},
},
}
func (d *distribution) Name() string {
return d.name
}
func (d *distribution) Releasever() string {
return d.releaseVersion
}
func (d *distribution) OsVersion() string {
return d.osVersion
}
func (d *distribution) Product() string {
return d.product
}
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")
}
func (d *distribution) getDefaultImageConfig() *distro.ImageConfig {
return d.defaultImageConfig
}
func newDistro(name string, major, minor int) *distribution {
var rd distribution
switch fmt.Sprintf("%s-%d", name, major) {
case "rhel-9":
rd = distribution{
name: fmt.Sprintf("rhel-9.%d", minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("9.%d", minor),
releaseVersion: "9",
modulePlatformID: "platform:el9",
vendor: "redhat",
ostreeRefTmpl: "rhel/9/%s/edge",
runner: &runner.RHEL{Major: uint64(9), Minor: uint64(minor)},
defaultImageConfig: defaultDistroImageConfig,
}
case "rhel-10":
rd = distribution{
name: fmt.Sprintf("rhel-10.%d", minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("10.%d", minor),
releaseVersion: "10",
modulePlatformID: "platform:el10",
vendor: "redhat",
ostreeRefTmpl: "rhel/10/%s/edge",
runner: &runner.RHEL{Major: uint64(10), Minor: uint64(minor)},
defaultImageConfig: defaultDistroImageConfig,
}
case "centos-9":
rd = distribution{
name: "centos-9",
product: "CentOS Stream",
osVersion: "9-stream",
releaseVersion: "9",
modulePlatformID: "platform:el9",
vendor: "centos",
ostreeRefTmpl: "centos/9/%s/edge",
runner: &runner.CentOS{Version: uint64(9)},
defaultImageConfig: defaultDistroImageConfig,
}
case "centos-10":
rd = distribution{
name: "centos-10",
product: "CentOS Stream",
osVersion: "10-stream",
releaseVersion: "10",
modulePlatformID: "platform:el10",
vendor: "centos",
ostreeRefTmpl: "centos/10/%s/edge",
runner: &runner.CentOS{Version: uint64(10)},
defaultImageConfig: defaultDistroImageConfig,
}
default:
panic(fmt.Sprintf("unknown distro name: %s and major: %d", name, major))
}
// Architecture definitions
x86_64 := architecture{
name: arch.ARCH_X86_64.String(),
distro: &rd,
}
aarch64 := architecture{
name: arch.ARCH_AARCH64.String(),
distro: &rd,
}
ppc64le := architecture{
distro: &rd,
name: arch.ARCH_PPC64LE.String(),
}
s390x := architecture{
distro: &rd,
name: arch.ARCH_S390X.String(),
}
qcow2ImgType := mkQcow2ImgType(rd)
ociImgType := qcow2ImgType
ociImgType.name = "oci"
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
qcow2ImgType,
ociImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
openstackImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
vmdkImgType,
)
x86_64.addImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_OVA,
},
},
ovaImgType,
)
x86_64.addImageTypes(
&platform.X86{},
tarImgType,
wslImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
},
},
openstackImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{},
tarImgType,
wslImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
qcow2ImgType,
)
ppc64le.addImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
qcow2ImgType,
)
ppc64le.addImageTypes(
&platform.PPC64LE{},
tarImgType,
)
s390x.addImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
qcow2ImgType,
)
s390x.addImageTypes(
&platform.S390X{},
tarImgType,
)
ec2X86Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
x86_64.addImageTypes(
ec2X86Platform,
mkAMIImgTypeX86_64(),
)
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
mkAMIImgTypeAarch64(),
)
azureX64Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
azureAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
if rd.isRHEL() { // RHEL-only (non-CentOS) image types
x86_64.addImageTypes(azureX64Platform, azureByosImgType(rd))
aarch64.addImageTypes(azureAarch64Platform, azureByosImgType(rd))
} else {
x86_64.addImageTypes(azureX64Platform, azureImgType)
aarch64.addImageTypes(azureAarch64Platform, azureImgType)
}
// NOTE: This condition is a temporary separation of EL9 and EL10 while we
// add support for all image types on EL10. Currently only a small subset
// is supported on EL10 because of package availability. This big
// conditional separation should be removed when most image types become
// available in EL10.
if major == 9 {
gceX86Platform := &platform.X86{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_GCE,
},
}
x86_64.addImageTypes(
gceX86Platform,
mkGCEImageType(),
)
x86_64.addImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"microcode_ctl", // ??
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6050-firmware",
},
},
BIOS: true,
UEFIVendor: rd.vendor,
},
edgeOCIImgType,
edgeCommitImgType,
edgeInstallerImgType,
edgeRawImgType,
imageInstaller,
edgeAMIImgType,
)
x86_64.addImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
BIOS: true,
UEFIVendor: rd.vendor,
},
edgeVsphereImgType,
)
x86_64.addImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
BIOS: false,
UEFIVendor: rd.vendor,
},
edgeSimplifiedInstallerImgType,
minimalrawImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{},
UEFIVendor: rd.vendor,
},
edgeCommitImgType,
edgeOCIImgType,
edgeInstallerImgType,
edgeSimplifiedInstallerImgType,
imageInstaller,
edgeAMIImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
UEFIVendor: rd.vendor,
},
edgeVsphereImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
UEFIVendor: rd.vendor,
},
edgeRawImgType,
minimalrawImgType,
)
if rd.isRHEL() { // RHEL-only (non-CentOS) image types
x86_64.addImageTypes(azureX64Platform, azureRhuiImgType, azureByosImgType(rd))
aarch64.addImageTypes(azureAarch64Platform, azureRhuiImgType, azureByosImgType(rd))
x86_64.addImageTypes(azureX64Platform, azureSapRhuiImgType(rd))
// keep the RHEL EC2 x86_64 images before 9.3 BIOS-only for backward compatibility
if common.VersionLessThan(rd.osVersion, "9.3") {
ec2X86Platform = &platform.X86{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
}
// add ec2 image types to RHEL distro only
x86_64.addImageTypes(ec2X86Platform, mkEc2ImgTypeX86_64(rd.osVersion, rd.isRHEL()), mkEc2HaImgTypeX86_64(rd.osVersion, rd.isRHEL()), mkEC2SapImgTypeX86_64(rd.osVersion, rd.isRHEL()))
aarch64.addImageTypes(
&platform.Aarch64{
UEFIVendor: rd.vendor,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
mkEC2ImgTypeAarch64(rd.osVersion, rd.isRHEL()),
)
// add GCE RHUI image to RHEL only
x86_64.addImageTypes(gceX86Platform, mkGCERHUIImageType())
}
}
rd.addArches(x86_64, aarch64, ppc64le, s390x)
return &rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
// Backward compatibility layer for "rhel-93" or "rhel-910"
if id.Name == "rhel" && id.MinorVersion == -1 {
if id.MajorVersion/10 == 9 {
// handle single digit minor version
id.MinorVersion = id.MajorVersion % 10
id.MajorVersion = 9
} else if id.MajorVersion/100 == 9 {
// handle two digit minor version
id.MinorVersion = id.MajorVersion % 100
id.MajorVersion = 9
}
}
if id.MajorVersion != 9 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, 9, id.MinorVersion)
}
func ParseIDEl10(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
if id.MajorVersion != 10 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactoryEl10(idStr string) distro.Distro {
id, err := ParseIDEl10(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, 10, id.MinorVersion)
}

View file

@ -1,736 +0,0 @@
package rhel9
import (
"fmt"
"math/rand"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/fdo"
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/customizations/ignition"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/customizations/users"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/ostree"
"github.com/osbuild/images/pkg/rpmmd"
)
func osCustomizations(
t *imageType,
osPackageSet rpmmd.PackageSet,
options distro.ImageOptions,
containers []container.SourceSpec,
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
}
osc.FIPS = c.GetFIPS()
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
osc.MaskedServices = imageConfig.MaskedServices
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 t.arch.distro.isRHEL() && options.Facts != nil {
osc.FactAPIType = &options.Facts.APIType
}
var err error
osc.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(c.GetDirectories())
if err != nil {
// In theory this should never happen, because the blueprint directory customizations
// should have been validated before this point.
panic(fmt.Sprintf("failed to convert directory customizations to fs node directories: %v", err))
}
osc.Files, err = blueprint.FileCustomizationsToFsNodeFiles(c.GetFiles())
if err != nil {
// In theory this should never happen, because the blueprint file customizations
// should have been validated before this point.
panic(fmt.Sprintf("failed to convert file customizations to fs node files: %v", err))
}
// OSTree commits do not include data in `/var` since that is tied to the
// deployment, rather than the commit. Therefore the containers need to be
// stored in a different location, like `/usr/share`, and the container
// storage engine configured accordingly.
if t.rpmOstree && len(containers) > 0 {
storagePath := "/usr/share/containers/storage"
osc.ContainersStorage = &storagePath
}
if containerStorage := c.GetContainerStorage(); containerStorage != nil {
osc.ContainersStorage = containerStorage.StoragePath
}
// set yum repos first, so it doesn't get overridden by
// imageConfig.YUMRepos
osc.YUMRepos = imageConfig.YUMRepos
customRepos, err := c.GetRepositories()
if err != nil {
// This shouldn't happen and since the repos
// should have already been validated
panic(fmt.Sprintf("failed to get custom repos: %v", err))
}
// This function returns a map of filename and corresponding yum repos
// and a list of fs node files for the inline gpg keys so we can save
// them to disk. This step also swaps the inline gpg key with the path
// to the file in the os file tree
yumRepos, gpgKeyFiles, err := blueprint.RepoCustomizationsToRepoConfigAndGPGKeyFiles(customRepos)
if err != nil {
panic(fmt.Sprintf("failed to convert inline gpgkeys to fs node files: %v", err))
}
// add the gpg key files to the list of files to be added to the tree
if len(gpgKeyFiles) > 0 {
osc.Files = append(osc.Files, gpgKeyFiles...)
}
for filename, repos := range yumRepos {
osc.YUMRepos = append(osc.YUMRepos, osbuild.NewYumReposStageOptions(filename, repos))
}
if oscapConfig := c.GetOpenSCAP(); oscapConfig != nil {
if t.rpmOstree {
panic("unexpected oscap options for ostree image type")
}
// although the osbuild stage will create this directory,
// it's probably better to ensure that it is created here
dataDirNode, err := fsnode.NewDirectory(oscapDataDir, nil, nil, nil, true)
if err != nil {
panic("unexpected error creating OpenSCAP data directory")
}
osc.Directories = append(osc.Directories, dataDirNode)
var datastream = oscapConfig.DataStream
if datastream == "" {
datastream = oscap.DefaultRHEL9Datastream(t.arch.distro.isRHEL())
}
oscapStageOptions := osbuild.OscapConfig{
Datastream: datastream,
ProfileID: oscapConfig.ProfileID,
Compression: true,
}
if oscapConfig.Tailoring != nil {
newProfile, tailoringFilepath, tailoringDir, err := oscap.GetTailoringFile(oscapConfig.ProfileID)
if err != nil {
panic(fmt.Sprintf("unexpected error creating tailoring file options: %v", err))
}
tailoringOptions := osbuild.OscapAutotailorConfig{
NewProfile: newProfile,
Datastream: datastream,
ProfileID: oscapConfig.ProfileID,
Selected: oscapConfig.Tailoring.Selected,
Unselected: oscapConfig.Tailoring.Unselected,
}
osc.OpenSCAPTailorConfig = osbuild.NewOscapAutotailorStageOptions(
tailoringFilepath,
tailoringOptions,
)
// overwrite the profile id with the new tailoring id
oscapStageOptions.ProfileID = newProfile
oscapStageOptions.Tailoring = tailoringFilepath
// add the parent directory for the tailoring file
osc.Directories = append(osc.Directories, tailoringDir)
}
osc.OpenSCAPConfig = osbuild.NewOscapRemediationStageOptions(oscapDataDir, oscapStageOptions)
}
osc.ShellInit = imageConfig.ShellInit
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.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
osc.WSLConfig = imageConfig.WSLConfig
osc.Files = append(osc.Files, imageConfig.Files...)
osc.Directories = append(osc.Directories, imageConfig.Directories...)
return osc
}
func diskImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewDiskImage()
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
}
func edgeCommitImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
parentCommit, commitRef := makeOSTreeParentCommit(options.OSTree, t.OSTreeRef())
img := image.NewOSTreeArchive(commitRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
img.Workload = workload
img.OSTreeParent = parentCommit
img.OSVersion = t.arch.distro.osVersion
img.Filename = t.Filename()
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
img.OSCustomizations.EnabledServices = append(img.OSCustomizations.EnabledServices, "ignition-firstboot-complete.service", "coreos-ignition-write-issues.service")
}
img.Environment = t.environment
img.Workload = workload
img.OSVersion = t.arch.distro.osVersion
img.Filename = t.Filename()
return img, nil
}
func edgeContainerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
parentCommit, commitRef := makeOSTreeParentCommit(options.OSTree, t.OSTreeRef())
img := image.NewOSTreeContainer(commitRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.ContainerLanguage = img.OSCustomizations.Language
img.Environment = t.environment
img.Workload = workload
img.OSTreeParent = parentCommit
img.OSVersion = t.arch.distro.osVersion
img.ExtraContainerPackages = packageSets[containerPkgsKey]
img.Filename = t.Filename()
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
img.OSCustomizations.EnabledServices = append(img.OSCustomizations.EnabledServices, "ignition-firstboot-complete.service", "coreos-ignition-write-issues.service")
}
return img, nil
}
func edgeInstallerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
d := t.arch.distro
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
if err != nil {
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
}
img := image.NewAnacondaOSTreeInstaller(commit)
img.Platform = t.platform
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.Language, img.Keyboard = customizations.GetPrimaryLocale()
// ignore ntp servers - we don't currently support setting these in the
// kickstart though kickstart does support setting them
img.Timezone, _ = customizations.GetTimezoneSettings()
if instCust := customizations.GetInstaller(); instCust != nil {
img.NoPasswd = instCust.SudoNopasswd
img.UnattendedKickstart = instCust.Unattended
}
img.SquashfsCompression = "xz"
img.AdditionalDracutModules = []string{
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
}
img.AdditionalDrivers = []string{"cuse", "ipmi_devintf", "ipmi_msghandler"}
if len(img.Users)+len(img.Groups) > 0 {
// only enable the users module if needed
img.AdditionalAnacondaModules = []string{"org.fedoraproject.Anaconda.Modules.Users"}
}
img.ISOLabel, err = t.ISOLabel()
if err != nil {
return nil, err
}
img.Product = d.product
img.Variant = "edge"
img.OSName = "rhel"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.FIPS = customizations.GetFIPS()
img.Filename = t.Filename()
return img, nil
}
func edgeRawImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
if err != nil {
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
}
img := image.NewOSTreeDiskImageFromCommit(commit)
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.FIPS = customizations.GetFIPS()
// The kernel options defined on the image type are usually handled in
// osCustomiztions() but ostree images don't use OSCustomizations, so we
// handle them here separately.
if t.kernelOptions != "" {
img.KernelOptionsAppend = append(img.KernelOptionsAppend, t.kernelOptions)
}
img.Keyboard = "us"
img.Locale = "C.UTF-8"
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
img.SysrootReadOnly = true
img.KernelOptionsAppend = append(img.KernelOptionsAppend, "rw")
}
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
img.IgnitionPlatform = "metal"
img.KernelOptionsAppend = append(img.KernelOptionsAppend, "coreos.no_persist_ip")
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
img.KernelOptionsAppend = append(img.KernelOptionsAppend, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}
}
img.Platform = t.platform
img.Workload = workload
img.Remote = ostree.Remote{
Name: "rhel-edge",
URL: options.OSTree.URL,
ContentURL: options.OSTree.ContentURL,
}
img.OSName = "redhat"
img.LockRoot = true
if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" {
img.KernelOptionsAppend = append(img.KernelOptionsAppend, kopts.Append)
}
// 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()
img.Compression = t.compression
for _, fs := range customizations.GetFilesystems() {
img.CustomFilesystems = append(img.CustomFilesystems, fs.Mountpoint)
}
return img, nil
}
func edgeSimplifiedInstallerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
commit, err := makeOSTreePayloadCommit(options.OSTree, t.OSTreeRef())
if err != nil {
return nil, fmt.Errorf("%s: %s", t.Name(), err.Error())
}
rawImg := image.NewOSTreeDiskImageFromCommit(commit)
rawImg.Users = users.UsersFromBP(customizations.GetUsers())
rawImg.Groups = users.GroupsFromBP(customizations.GetGroups())
rawImg.FIPS = customizations.GetFIPS()
rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
rawImg.Keyboard = "us"
rawImg.Locale = "C.UTF-8"
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
rawImg.SysrootReadOnly = true
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "rw")
}
rawImg.Platform = t.platform
rawImg.Workload = workload
rawImg.Remote = ostree.Remote{
Name: "rhel-edge",
URL: options.OSTree.URL,
ContentURL: options.OSTree.ContentURL,
}
rawImg.OSName = "redhat"
rawImg.LockRoot = true
if common.VersionGreaterThanOrEqual(t.arch.distro.osVersion, "9.2") || !t.arch.distro.isRHEL() {
rawImg.IgnitionPlatform = "metal"
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "coreos.no_persist_ip")
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}
}
// TODO: move generation into LiveImage
pt, err := t.getPartitionTable(customizations.GetFilesystems(), options, rng)
if err != nil {
return nil, err
}
rawImg.PartitionTable = pt
rawImg.Filename = t.Filename()
for _, fs := range customizations.GetFilesystems() {
rawImg.CustomFilesystems = append(rawImg.CustomFilesystems, fs.Mountpoint)
}
// 92+ only
if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" {
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, kopts.Append)
}
img := image.NewOSTreeSimplifiedInstaller(rawImg, customizations.InstallationDevice)
img.ExtraBasePackages = packageSets[installerPkgsKey]
// img.Workload = workload
img.Platform = t.platform
img.Filename = t.Filename()
if bpFDO := customizations.GetFDO(); bpFDO != nil {
img.FDO = fdo.FromBP(*bpFDO)
}
// ignition configs from blueprint
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil {
if bpIgnition.Embedded != nil {
var err error
img.IgnitionEmbedded, err = ignition.EmbeddedOptionsFromBP(*bpIgnition.Embedded)
if err != nil {
return nil, err
}
}
}
img.ISOLabel, err = t.ISOLabel()
if err != nil {
return nil, err
}
d := t.arch.distro
img.Product = d.product
img.Variant = "edge"
img.OSName = "redhat"
img.OSVersion = d.osVersion
img.AdditionalDracutModules = []string{"prefixdevname", "prefixdevname-tools"}
return img, nil
}
func imageInstallerImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewAnacondaTarInstaller()
img.Platform = t.platform
img.Workload = workload
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
img.AdditionalDracutModules = []string{
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
}
img.AdditionalDrivers = []string{"cuse", "ipmi_devintf", "ipmi_msghandler"}
img.AdditionalAnacondaModules = []string{"org.fedoraproject.Anaconda.Modules.Users"}
if instCust := customizations.GetInstaller(); instCust != nil {
img.NoPasswd = instCust.SudoNopasswd
img.UnattendedKickstart = instCust.Unattended
}
img.SquashfsCompression = "xz"
// put the kickstart file in the root of the iso
img.ISORootKickstart = true
var err error
img.ISOLabel, err = t.ISOLabel()
if err != nil {
return nil, err
}
d := t.arch.distro
img.Product = d.product
img.OSName = "redhat"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)
img.Filename = t.Filename()
return img, nil
}
func tarImage(workload workload.Workload,
t *imageType,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewArchive()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
img.Workload = workload
img.Filename = t.Filename()
return img, nil
}
// Create an ostree SourceSpec to define an ostree parent commit using the user
// options and the default ref for the image type. Additionally returns the
// ref to be used for the new commit to be created.
func makeOSTreeParentCommit(options *ostree.ImageOptions, defaultRef string) (*ostree.SourceSpec, string) {
commitRef := defaultRef
if options == nil {
// nothing to do
return nil, commitRef
}
if options.ImageRef != "" {
// user option overrides default commit ref
commitRef = options.ImageRef
}
var parentCommit *ostree.SourceSpec
if options.URL == "" {
// no parent
return nil, commitRef
}
// ostree URL specified: set source spec for parent commit
parentRef := options.ParentRef
if parentRef == "" {
// parent ref not set: use image ref
parentRef = commitRef
}
parentCommit = &ostree.SourceSpec{
URL: options.URL,
Ref: parentRef,
RHSM: options.RHSM,
}
return parentCommit, commitRef
}
// Create an ostree SourceSpec to define an ostree payload using the user options and the default ref for the image type.
func makeOSTreePayloadCommit(options *ostree.ImageOptions, defaultRef string) (ostree.SourceSpec, error) {
if options == nil || options.URL == "" {
// this should be caught by checkOptions() in distro, but it's good
// to guard against it here as well
return ostree.SourceSpec{}, fmt.Errorf("ostree commit URL required")
}
commitRef := defaultRef
if options.ImageRef != "" {
// user option overrides default commit ref
commitRef = options.ImageRef
}
return ostree.SourceSpec{
URL: options.URL,
Ref: commitRef,
RHSM: options.RHSM,
}, nil
}
// initialSetupKickstart returns the File configuration for a kickstart file
// that's required to enable initial-setup to run on first boot.
func initialSetupKickstart() *fsnode.File {
file, err := fsnode.NewFile("/root/anaconda-ks.cfg", nil, "root", "root", []byte("# Run initial-setup on first boot\n# Created by osbuild\nfirstboot --reconfig\nlang en_US.UTF-8\n"))
if err != nil {
panic(err)
}
return file
}

View file

@ -1,490 +0,0 @@
package rhel9
import (
"fmt"
"log"
"math/rand"
"strings"
"golang.org/x/exp/slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/policies"
"github.com/osbuild/images/pkg/rpmmd"
)
const (
// package set names
// build package set name
buildPkgsKey = "build"
// main/common os image package set name
osPkgsKey = "os"
// container package set name
containerPkgsKey = "container"
// installer package set name
installerPkgsKey = "installer"
// blueprint package set name
blueprintPkgsKey = "blueprint"
// location for saving openscap remediation data
oscapDataDir = "/oscap_data"
)
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error)
type packageSetFunc func(t *imageType) rpmmd.PackageSet
type basePartitionTableFunc func(t *imageType) (disk.PartitionTable, bool)
type isoLabelFunc func(t *imageType) string
type imageType struct {
arch *architecture
platform platform.Platform
environment environment.Environment
workload workload.Workload
name string
nameAliases []string
filename string
compression string // TODO: remove from image definition and make it a transport option
mimeType string
packageSets map[string]packageSetFunc
defaultImageConfig *distro.ImageConfig
kernelOptions string
defaultSize uint64
buildPipelines []string
payloadPipelines []string
exports []string
image imageFunc
isoLabel isoLabelFunc
// bootISO: installable ISO
bootISO bool
// rpmOstree: edge/ostree
rpmOstree bool
// bootable image
bootable bool
// List of valid arches for the image type
basePartitionTables basePartitionTableFunc
}
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) ISOLabel() (string, error) {
if !t.bootISO {
return "", fmt.Errorf("image type %q is not an ISO", t.name)
}
if t.isoLabel != nil {
return t.isoLabel(t), nil
}
return "", nil
}
func (t *imageType) Size(size uint64) uint64 {
// Microsoft Azure requires vhd images to be rounded up to the nearest MB
if t.name == "vhd" && size%common.MebiByte != 0 {
size = (size/common.MebiByte + 1) * common.MebiByte
}
if size == 0 {
size = t.defaultSize
}
return size
}
func (t *imageType) BuildPipelines() []string {
return t.buildPipelines
}
func (t *imageType) PayloadPipelines() []string {
return t.payloadPipelines
}
func (t *imageType) PayloadPackageSets() []string {
return []string{blueprintPkgsKey}
}
func (t *imageType) PackageSetsChains() map[string][]string {
return nil
}
func (t *imageType) Exports() []string {
if len(t.exports) > 0 {
return t.exports
}
return []string{"assembler"}
}
func (t *imageType) BootMode() distro.BootMode {
if t.platform.GetUEFIVendor() != "" && t.platform.GetBIOSPlatform() != "" {
return distro.BOOT_HYBRID
} else if t.platform.GetUEFIVendor() != "" {
return distro.BOOT_UEFI
} else if t.platform.GetBIOSPlatform() != "" || t.platform.GetZiplSupport() {
return distro.BOOT_LEGACY
}
return distro.BOOT_NONE
}
func (t *imageType) getPartitionTable(
mountpoints []blueprint.FilesystemCustomization,
options distro.ImageOptions,
rng *rand.Rand,
) (*disk.PartitionTable, error) {
archName := t.arch.Name()
basePartitionTable, exists := t.basePartitionTables(t)
if !exists {
return nil, fmt.Errorf("no partition table defined for architecture %q for image type %q", archName, t.Name())
}
imageSize := t.Size(options.Size)
partitioningMode := options.PartitioningMode
if t.rpmOstree {
// Edge supports only LVM, force it.
// TODO Need a central location for logic like this
partitioningMode = disk.LVMPartitioningMode
}
return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, partitioningMode, nil, rng)
}
func (t *imageType) getDefaultImageConfig() *distro.ImageConfig {
// ensure that image always returns non-nil default config
imageConfig := t.defaultImageConfig
if imageConfig == nil {
imageConfig = &distro.ImageConfig{}
}
return imageConfig.InheritFrom(t.arch.distro.getDefaultImageConfig())
}
func (t *imageType) PartitionType() string {
basePartitionTable, exists := t.basePartitionTables(t)
if !exists {
return ""
}
return basePartitionTable.Type
}
func (t *imageType) Manifest(bp *blueprint.Blueprint,
options distro.ImageOptions,
repos []rpmmd.RepoConfig,
seed int64) (*manifest.Manifest, []string, error) {
warnings, err := t.checkOptions(bp, options)
if err != nil {
return nil, nil, err
}
// merge package sets that appear in the image type with the package sets
// of the same name from the distro and arch
staticPackageSets := make(map[string]rpmmd.PackageSet)
for name, getter := range t.packageSets {
staticPackageSets[name] = getter(t)
}
// amend with repository information and collect payload repos
payloadRepos := make([]rpmmd.RepoConfig, 0)
for _, repo := range repos {
if len(repo.PackageSets) > 0 {
// only apply the repo to the listed package sets
for _, psName := range repo.PackageSets {
if slices.Contains(t.PayloadPackageSets(), psName) {
payloadRepos = append(payloadRepos, repo)
}
ps := staticPackageSets[psName]
ps.Repositories = append(ps.Repositories, repo)
staticPackageSets[psName] = ps
}
}
}
w := t.workload
if w == nil {
cw := &workload.Custom{
BaseWorkload: workload.BaseWorkload{
Repos: payloadRepos,
},
Packages: bp.GetPackagesEx(false),
}
if services := bp.Customizations.GetServices(); services != nil {
cw.Services = services.Enabled
cw.DisabledServices = services.Disabled
}
w = cw
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
Local: cont.LocalStorage,
}
}
source := rand.NewSource(seed)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(source)
img, err := t.image(w, t, bp.Customizations, options, staticPackageSets, containerSources, rng)
if err != nil {
return nil, nil, err
}
mf := manifest.New()
switch t.arch.distro.releaseVersion {
case "9":
mf.Distro = manifest.DISTRO_EL9
case "10":
mf.Distro = manifest.DISTRO_EL10
default:
return nil, nil, fmt.Errorf("unsupported distro release version %s", t.arch.distro.releaseVersion)
}
_, err = img.InstantiateManifest(&mf, repos, t.arch.distro.runner, rng)
if err != nil {
return nil, nil, err
}
return &mf, warnings, err
}
func distroISOLabelFunc(t *imageType) string {
const RHEL_ISO_LABEL = "RHEL-%s-%s-0-BaseOS-%s"
const CS_ISO_LABEL = "CentOS-Stream-%s-BaseOS-%s"
if t.arch.distro.isRHEL() {
osVer := strings.Split(t.Arch().Distro().OsVersion(), ".")
return fmt.Sprintf(RHEL_ISO_LABEL, osVer[0], osVer[1], t.Arch().Name())
} else {
return fmt.Sprintf(CS_ISO_LABEL, t.Arch().Distro().Releasever(), t.Arch().Name())
}
}
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
customizations := bp.Customizations
// holds warnings (e.g. deprecation notices)
var warnings []string
if t.workload != nil {
// For now, if an image type defines its own workload, don't allow any
// user customizations.
// Soon we will have more workflows and each will define its allowed
// set of customizations. The current set of customizations defined in
// the blueprint spec corresponds to the Custom workflow.
if customizations != nil {
return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name)
}
}
// we do not support embedding containers on ostree-derived images, only on commits themselves
if len(bp.Containers) > 0 && t.rpmOstree && (t.name != "edge-commit" && t.name != "edge-container") {
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name)
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
}
}
if t.bootISO && t.rpmOstree {
// ostree-based ISOs require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return nil, 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" {
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name)
}
// FDO is optional, but when specified has some restrictions
if customizations.GetFDO() != nil {
if customizations.GetFDO().ManufacturingServerURL == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to when using FDO", t.name)
}
var diunSet int
if customizations.GetFDO().DiunPubKeyHash != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyInsecure != "" {
diunSet++
}
if customizations.GetFDO().DiunPubKeyRootCerts != "" {
diunSet++
}
if diunSet != 1 {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to when using FDO", t.name)
}
}
// ignition is optional, we might be using FDO
if customizations.GetIgnition() != nil {
if customizations.GetIgnition().Embedded != nil && customizations.GetIgnition().FirstBoot != nil {
return warnings, fmt.Errorf("both ignition embedded and firstboot configurations found")
}
if customizations.GetIgnition().FirstBoot != nil && customizations.GetIgnition().FirstBoot.ProvisioningURL == "" {
return warnings, fmt.Errorf("ignition.firstboot requires a provisioning url")
}
}
} else if t.name == "edge-installer" {
allowed := []string{"User", "Group", "FIPS", "Installer", "Timezone", "Locale"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
}
}
if t.name == "edge-raw-image" || t.name == "edge-ami" || t.name == "edge-vsphere" {
// ostree-based bootable images require a URL from which to pull a payload commit
if options.OSTree == nil || options.OSTree.URL == "" {
return warnings, fmt.Errorf("%q images require specifying a URL from which to retrieve the OSTree commit", t.name)
}
allowed := []string{"Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer"
}
// warn that user & group customizations on edge-commit, edge-container are deprecated
// TODO(edge): directly error if these options are provided when rhel-9.5's time arrives
if t.name == "edge-commit" || t.name == "edge-container" {
if customizations.GetUsers() != nil {
w := fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.name)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetGroups() != nil {
w := fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.name)
log.Print(w)
warnings = append(warnings, w)
}
}
if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.rpmOstree && t.name != "edge-raw-image" && t.name != "edge-simplified-installer" {
return warnings, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types")
}
mountpoints := customizations.GetFilesystems()
if mountpoints != nil && t.rpmOstree && (t.name == "edge-container" || t.name == "edge-commit") {
return warnings, fmt.Errorf("Custom mountpoints are not supported for edge-container and edge-commit")
} else if mountpoints != nil && t.rpmOstree && !(t.name == "edge-container" || t.name == "edge-commit") {
//customization allowed for edge-raw-image,edge-ami,edge-vsphere,edge-simplified-installer
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.OstreeMountpointPolicies)
if err != nil {
return warnings, err
}
}
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
if osc := customizations.GetOpenSCAP(); osc != nil {
if t.arch.distro.osVersion == "9.0" {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported os version: %s", t.arch.distro.osVersion))
}
if !oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList) {
return warnings, fmt.Errorf(fmt.Sprintf("OpenSCAP unsupported profile: %s", osc.ProfileID))
}
if t.rpmOstree {
return warnings, fmt.Errorf("OpenSCAP customizations are not supported for ostree types")
}
if osc.ProfileID == "" {
return warnings, fmt.Errorf("OpenSCAP profile cannot be empty")
}
}
// Check Directory/File Customizations are valid
dc := customizations.GetDirectories()
fc := customizations.GetFiles()
err = blueprint.ValidateDirFileCustomizations(dc, fc)
if err != nil {
return warnings, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
if err != nil {
return warnings, err
}
// check if repository customizations are valid
_, err = customizations.GetRepositories()
if err != nil {
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
if customizations.GetInstaller() != nil {
// only supported by the Anaconda installer
if slices.Index([]string{"image-installer", "edge-installer", "live-installer"}, t.name) == -1 {
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.name)
}
}
return warnings, nil
}

View file

@ -1,69 +0,0 @@
package rhel9
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/rpmmd"
)
const vmdkKernelOptions = "ro net.ifnames=0"
var vmdkImgType = imageType{
name: "vmdk",
filename: "disk.vmdk",
mimeType: "application/x-vmdk",
packageSets: map[string]packageSetFunc{
osPkgsKey: vmdkCommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
},
kernelOptions: vmdkKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vmdk"},
exports: []string{"vmdk"},
basePartitionTables: defaultBasePartitionTables,
}
var ovaImgType = imageType{
name: "ova",
filename: "image.ova",
mimeType: "application/ovf",
packageSets: map[string]packageSetFunc{
osPkgsKey: vmdkCommonPackageSet,
},
defaultImageConfig: &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"),
},
kernelOptions: vmdkKernelOptions,
bootable: true,
defaultSize: 4 * common.GibiByte,
image: diskImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "image", "vmdk", "ovf", "archive"},
exports: []string{"archive"},
basePartitionTables: defaultBasePartitionTables,
}
func vmdkCommonPackageSet(t *imageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"firewalld",
"langpacks-en",
"open-vm-tools",
"tuned",
},
Exclude: []string{
"dracut-config-rescue",
"rng-tools",
},
}
return ps
}

View file

@ -6,9 +6,10 @@ import (
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/fedora"
"github.com/osbuild/images/pkg/distro/rhel/rhel10"
"github.com/osbuild/images/pkg/distro/rhel/rhel8"
"github.com/osbuild/images/pkg/distro/rhel/rhel9"
"github.com/osbuild/images/pkg/distro/rhel7"
"github.com/osbuild/images/pkg/distro/rhel8"
"github.com/osbuild/images/pkg/distro/rhel9"
"github.com/osbuild/images/pkg/distro/test_distro"
)
@ -112,7 +113,7 @@ func NewDefault() *Factory {
rhel7.DistroFactory,
rhel8.DistroFactory,
rhel9.DistroFactory,
rhel9.DistroFactoryEl10,
rhel10.DistroFactory,
)
}

View file

@ -3,9 +3,10 @@ package distroidparser
import (
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/fedora"
"github.com/osbuild/images/pkg/distro/rhel/rhel10"
"github.com/osbuild/images/pkg/distro/rhel/rhel8"
"github.com/osbuild/images/pkg/distro/rhel/rhel9"
"github.com/osbuild/images/pkg/distro/rhel7"
"github.com/osbuild/images/pkg/distro/rhel8"
"github.com/osbuild/images/pkg/distro/rhel9"
)
var DefaultParser = NewDefaultParser()
@ -66,6 +67,6 @@ func NewDefaultParser() *Parser {
rhel7.ParseID,
rhel8.ParseID,
rhel9.ParseID,
rhel9.ParseIDEl10,
rhel10.ParseID,
)
}

View file

@ -5,26 +5,38 @@ import (
"math/rand"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/users"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/runner"
)
type BootcDiskImage struct {
*OSTreeDiskImage
Base
Platform platform.Platform
PartitionTable *disk.PartitionTable
Filename string
ContainerSource *container.SourceSpec
// Customizations
KernelOptionsAppend []string
// "Users" is a bit misleading as only root and its ssh key is supported
// right now because that is all that bootc gives us by default but that
// will most likely change over time.
// See https://github.com/containers/bootc/pull/267
Users []users.User
}
func NewBootcDiskImage(container container.SourceSpec) *BootcDiskImage {
// XXX: hardcoded for now
ref := "ostree/1/1/0"
return &BootcDiskImage{
&OSTreeDiskImage{
Base: NewBase("bootc-raw-image"),
ContainerSource: &container,
Ref: ref,
OSName: "default",
},
Base: NewBase("bootc-raw-image"),
ContainerSource: &container,
}
}
@ -40,14 +52,17 @@ func (img *BootcDiskImage) InstantiateManifestFromContainers(m *manifest.Manifes
// this is signified by passing nil to the below pipelines.
var hostPipeline manifest.Build
opts := &baseRawOstreeImageOpts{useBootupd: true}
fileBasename := img.Filename
// TODO: no support for customization right now but minimal support
// for root ssh keys is supported
baseImage := manifest.NewRawBootcImage(buildPipeline, containers, img.Platform)
baseImage.PartitionTable = img.PartitionTable
baseImage.Users = img.Users
baseImage.KernelOptionsAppend = img.KernelOptionsAppend
// In BIB, we export multiple images from the same pipeline so we use the
// filename as the basename for each export and set the extensions based on
// each file format.
baseImage := baseRawOstreeImage(img.OSTreeDiskImage, buildPipeline, opts)
fileBasename := img.Filename
baseImage.SetFilename(fmt.Sprintf("%s.raw", fileBasename))
qcow2Pipeline := manifest.NewQCOW2(hostPipeline, baseImage)

View file

@ -7,8 +7,6 @@ import (
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/artifact"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/customizations/users"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/ostree"
@ -24,41 +22,22 @@ type OSTreeDiskImage struct {
Workload workload.Workload
PartitionTable *disk.PartitionTable
Users []users.User
Groups []users.Group
OSTreeDeploymentCustomizations manifest.OSTreeDeploymentCustomizations
CommitSource *ostree.SourceSpec
ContainerSource *container.SourceSpec
SysrootReadOnly bool
Remote ostree.Remote
OSName string
Ref string
KernelOptionsAppend []string
Keyboard string
Locale string
Filename string
IgnitionPlatform string
Compression string
Directories []*fsnode.Directory
Files []*fsnode.File
FIPS bool
// Lock the root account in the deployment unless the user defined root
// user options in the build configuration.
LockRoot bool
Compression string
// Container buildable tweaks the buildroot to be container friendly,
// i.e. to not rely on an installed osbuild-selinux
ContainerBuildable bool
CustomFilesystems []string
}
func NewOSTreeDiskImageFromCommit(commit ostree.SourceSpec) *OSTreeDiskImage {
@ -97,19 +76,8 @@ func baseRawOstreeImage(img *OSTreeDiskImage, buildPipeline manifest.Build, opts
osPipeline.PartitionTable = img.PartitionTable
osPipeline.Remote = img.Remote
osPipeline.KernelOptionsAppend = img.KernelOptionsAppend
osPipeline.Keyboard = img.Keyboard
osPipeline.Locale = img.Locale
osPipeline.Users = img.Users
osPipeline.Groups = img.Groups
osPipeline.SysrootReadOnly = img.SysrootReadOnly
osPipeline.Directories = img.Directories
osPipeline.Files = img.Files
osPipeline.FIPS = img.FIPS
osPipeline.IgnitionPlatform = img.IgnitionPlatform
osPipeline.LockRoot = img.LockRoot
osPipeline.OSTreeDeploymentCustomizations = img.OSTreeDeploymentCustomizations
osPipeline.UseBootupd = opts.useBootupd
osPipeline.CustomFileSystems = img.CustomFilesystems
// other image types (e.g. live) pass the workload to the pipeline.
if img.Workload != nil {

View file

@ -235,11 +235,7 @@ func (p *BuildrootFromContainer) serialize() osbuild.Pipeline {
pipeline.Runner = p.runner.String()
image := osbuild.NewContainersInputForSingleSource(p.containerSpecs[0])
options := &osbuild.ContainerDeployOptions{
Exclude: []string{"/sysroot"},
}
stage, err := osbuild.NewContainerDeployStage(image, options)
stage, err := osbuild.NewContainerDeployStage(image, &osbuild.ContainerDeployOptions{})
if err != nil {
panic(err)
}
@ -247,6 +243,7 @@ func (p *BuildrootFromContainer) serialize() osbuild.Pipeline {
pipeline.AddStage(osbuild.NewSELinuxStage(
&osbuild.SELinuxStageOptions{
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
ExcludePaths: []string{"/sysroot"},
Labels: p.getSELinuxLabels(),
},
))

View file

@ -608,7 +608,7 @@ func (p *OS) serialize() osbuild.Pipeline {
}))
}
if !p.KernelOptionsBootloader {
if !p.KernelOptionsBootloader || p.platform.GetArch() == arch.ARCH_S390X {
pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), pt)
}

View file

@ -16,11 +16,43 @@ import (
"github.com/osbuild/images/pkg/rpmmd"
)
// OSTreeDeploymentCustomizations encapsulates all configuration applied to an
// OSTree deployment independently of where and how it is integrated and what
// workload it is running.
type OSTreeDeploymentCustomizations struct {
SysrootReadOnly bool
KernelOptionsAppend []string
Keyboard string
Locale string
Users []users.User
Groups []users.Group
// Specifies the ignition platform to use.
// If empty, ignition is not enabled.
IgnitionPlatform string
Directories []*fsnode.Directory
Files []*fsnode.File
FIPS bool
CustomFileSystems []string
// Lock the root account in the deployment unless the user defined root
// user options in the build configuration.
LockRoot bool
}
// OSTreeDeployment represents the filesystem tree of a target image based
// on a deployed ostree commit.
type OSTreeDeployment struct {
Base
// Customizations to apply to the deployment
OSTreeDeploymentCustomizations
Remote ostree.Remote
OSVersion string
@ -40,42 +72,18 @@ type OSTreeDeployment struct {
// deployed in this pipeline.
containerSpec *container.Spec
SysrootReadOnly bool
osName string
ref string
KernelOptionsAppend []string
Keyboard string
Locale string
Users []users.User
Groups []users.Group
platform platform.Platform
PartitionTable *disk.PartitionTable
// Specifies the ignition platform to use.
// If empty, ignition is not enabled.
IgnitionPlatform string
Directories []*fsnode.Directory
Files []*fsnode.File
EnabledServices []string
DisabledServices []string
FIPS bool
// Lock the root account in the deployment unless the user defined root
// user options in the build configuration.
LockRoot bool
// Use bootupd instead of grub2 as the bootloader
UseBootupd bool
CustomFileSystems []string
}
// NewOSTreeCommitDeployment creates a pipeline for an ostree deployment from a

View file

@ -97,7 +97,7 @@ func (p Base) getCheckpoint() bool {
}
func (p *Base) Export() *artifact.Artifact {
panic("can't export pipeline")
panic("can't export pipeline directly from pipeline.Base")
}
func (p Base) getExport() bool {

View file

@ -0,0 +1,142 @@
package manifest
import (
"fmt"
"github.com/osbuild/images/pkg/artifact"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/users"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/ostree"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/rpmmd"
)
// A RawBootcImage represents a raw bootc image file which can be booted in a
// hypervisor.
type RawBootcImage struct {
Base
filename string
platform platform.Platform
containers []container.SourceSpec
containerSpecs []container.Spec
// customizations go here because there is no intermediate
// tree, with `bootc install to-filesystem` we can only work
// with the image itself
PartitionTable *disk.PartitionTable
KernelOptionsAppend []string
// "Users" is a bit misleading as only root and its ssh key is supported
// right now because that is all that bootc gives us by default but that
// will most likely change over time.
// See https://github.com/containers/bootc/pull/267
Users []users.User
}
func (p RawBootcImage) Filename() string {
return p.filename
}
func (p *RawBootcImage) SetFilename(filename string) {
p.filename = filename
}
func NewRawBootcImage(buildPipeline Build, containers []container.SourceSpec, platform platform.Platform) *RawBootcImage {
p := &RawBootcImage{
Base: NewBase("image", buildPipeline),
filename: "disk.img",
platform: platform,
containers: containers,
}
buildPipeline.addDependent(p)
return p
}
func (p *RawBootcImage) getContainerSources() []container.SourceSpec {
return p.containers
}
func (p *RawBootcImage) getContainerSpecs() []container.Spec {
return p.containerSpecs
}
func (p *RawBootcImage) serializeStart(_ []rpmmd.PackageSpec, containerSpecs []container.Spec, _ []ostree.CommitSpec) {
if len(p.containerSpecs) > 0 {
panic("double call to serializeStart()")
}
p.containerSpecs = containerSpecs
}
func (p *RawBootcImage) serializeEnd() {
if len(p.containerSpecs) == 0 {
panic("serializeEnd() call when serialization not in progress")
}
p.containerSpecs = nil
}
func (p *RawBootcImage) serialize() osbuild.Pipeline {
pipeline := p.Base.serialize()
pt := p.PartitionTable
if pt == nil {
panic(fmt.Errorf("no partition table in live image"))
}
if len(p.Users) > 1 {
panic(fmt.Errorf("raw bootc image only supports a single root key for user customization, got %v", p.Users))
}
if len(p.Users) == 1 && p.Users[0].Name != "root" {
panic(fmt.Errorf("raw bootc image only supports the root user, got %v", p.Users))
}
for _, stage := range osbuild.GenImagePrepareStages(pt, p.filename, osbuild.PTSfdisk) {
pipeline.AddStage(stage)
}
if len(p.containerSpecs) != 1 {
panic(fmt.Errorf("expected a single container input got %v", p.containerSpecs))
}
opts := &osbuild.BootcInstallToFilesystemOptions{
Kargs: p.KernelOptionsAppend,
}
if len(p.Users) == 1 && p.Users[0].Key != nil {
opts.RootSSHAuthorizedKeys = []string{*p.Users[0].Key}
}
inputs := osbuild.ContainerDeployInputs{
Images: osbuild.NewContainersInputForSingleSource(p.containerSpecs[0]),
}
devices, mounts, err := osbuild.GenBootupdDevicesMounts(p.filename, p.PartitionTable)
if err != nil {
panic(err)
}
st, err := osbuild.NewBootcInstallToFilesystemStage(opts, inputs, devices, mounts)
if err != nil {
panic(err)
}
pipeline.AddStage(st)
// XXX: there is no way right now to support any customizations,
// we cannot touch the filesystem after bootc installed it or
// we risk messing with it's selinux labels or future fsverity
// magic. Once we have a mechanism like --copy-etc from
// https://github.com/containers/bootc/pull/267 things should
// be a bit better
for _, stage := range osbuild.GenImageFinishStages(pt, p.filename) {
pipeline.AddStage(stage)
}
return pipeline
}
// XXX: copied from raw.go
func (p *RawBootcImage) Export() *artifact.Artifact {
p.Base.export = true
return artifact.New(p.Name(), p.Filename(), nil)
}

View file

@ -4,6 +4,15 @@ import (
"fmt"
)
type BootcInstallToFilesystemOptions struct {
// options for --root-ssh-authorized-keys
RootSSHAuthorizedKeys []string `json:"root-ssh-authorized-keys,omitempty"`
// options for --karg
Kargs []string `json:"kernel-args,omitempty"`
}
func (BootcInstallToFilesystemOptions) isStageOptions() {}
// NewBootcInstallToFilesystem creates a new stage for the
// org.osbuild.bootc.install-to-filesystem stage.
//
@ -12,17 +21,18 @@ import (
// bootc/bootupd find and install all required bootloader bits.
//
// The mounts input should be generated with GenBootupdDevicesMounts.
func NewBootcInstallToFilesystemStage(inputs ContainersInput, devices map[string]Device, mounts []Mount) (*Stage, error) {
func NewBootcInstallToFilesystemStage(options *BootcInstallToFilesystemOptions, inputs ContainerDeployInputs, devices map[string]Device, mounts []Mount) (*Stage, error) {
if err := validateBootupdMounts(mounts); err != nil {
return nil, err
}
if len(inputs.References) != 1 {
return nil, fmt.Errorf("expected exactly one container input but got: %v (%v)", len(inputs.References), inputs.References)
if len(inputs.Images.References) != 1 {
return nil, fmt.Errorf("expected exactly one container input but got: %v (%v)", len(inputs.Images.References), inputs.Images.References)
}
return &Stage{
Type: "org.osbuild.bootc.install-to-filesystem",
Options: options,
Inputs: inputs,
Devices: devices,
Mounts: mounts,

View file

@ -9,7 +9,7 @@ type ContainerDeployInputs struct {
func (ContainerDeployInputs) isStageInputs() {}
type ContainerDeployOptions struct {
Exclude []string `json:"exclude"`
Exclude []string `json:"exclude,omitempty"`
}
func (ContainerDeployOptions) isStageOptions() {}

View file

@ -1,6 +1,16 @@
package osbuild
import "github.com/osbuild/images/internal/common"
type OSTreeMountSource string
const (
OSTreeMountSourceTree OSTreeMountSource = "tree"
OSTreeMountSourceMount OSTreeMountSource = "mount"
)
type OSTreeMountOptions struct {
Source OSTreeMountSource `json:"source,omitempty"`
Deployment OSTreeMountDeployment `json:"deployment"`
}
@ -8,13 +18,16 @@ func (OSTreeMountOptions) isMountOptions() {}
type OSTreeMountDeployment struct {
// Name of the stateroot to be used in the deployment
OSName string `json:"osname"`
OSName string `json:"osname,omitempty"`
// OStree ref to create and use for deployment
Ref string `json:"ref"`
Ref string `json:"ref,omitempty"`
// The deployment serial (usually '0')
Serial *int `json:"serial,omitempty"`
// When set the OSName/Ref/Serial is detected automatically
Default *bool `json:"default,omitempty"`
}
func NewOSTreeDeploymentMount(name, osName, ref string, serial int) *Mount {
@ -30,3 +43,16 @@ func NewOSTreeDeploymentMount(name, osName, ref string, serial int) *Mount {
},
}
}
func NewOSTreeDeploymentMountDefault(name string, source OSTreeMountSource) *Mount {
return &Mount{
Type: "org.osbuild.ostree.deployment",
Name: name,
Options: &OSTreeMountOptions{
Source: source,
Deployment: OSTreeMountDeployment{
Default: common.ToPtr(true),
},
},
}
}

View file

@ -6,6 +6,7 @@ package osbuild
// the filesystem labels to apply to the image.
type SELinuxStageOptions struct {
FileContexts string `json:"file_contexts"`
ExcludePaths []string `json:"exclude_paths,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
ForceAutorelabel *bool `json:"force_autorelabel,omitempty"`
}

View file

@ -36,21 +36,48 @@ var MountpointPolicies = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPo
// CustomDirectoriesPolicies is a set of default policies for custom directories
var CustomDirectoriesPolicies = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPolicy{
"/": {Deny: true},
"/etc": {},
"/": {},
"/bin": {Deny: true},
"/boot": {Deny: true},
"/dev": {Deny: true},
"/lib": {Deny: true},
"/lib64": {Deny: true},
"/lost+found": {Deny: true},
"/proc": {Deny: true},
"/run": {Deny: true},
"/sbin": {Deny: true},
"/sys": {Deny: true},
"/sysroot": {Deny: true},
"/tmp": {Deny: true},
"/usr": {Deny: true},
"/var/run": {Deny: true},
"/var/tmp": {Deny: true},
"/efi": {Deny: true},
})
// CustomFilesPolicies is a set of default policies for custom files
var CustomFilesPolicies = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPolicy{
"/": {Deny: true},
"/etc": {},
"/root": {},
"/usr/local/bin": {},
"/usr/local/sbin": {},
"/etc/fstab": {Deny: true},
"/etc/shadow": {Deny: true},
"/etc/passwd": {Deny: true},
"/etc/group": {Deny: true},
"/": {},
"/bin": {Deny: true},
"/boot": {Deny: true},
"/dev": {Deny: true},
"/efi": {Deny: true},
"/etc/fstab": {Deny: true},
"/etc/group": {Deny: true},
"/etc/passwd": {Deny: true},
"/etc/shadow": {Deny: true},
"/lib": {Deny: true},
"/lib64": {Deny: true},
"/lost+found": {Deny: true},
"/proc": {Deny: true},
"/run": {Deny: true},
"/sbin": {Deny: true},
"/sys": {Deny: true},
"/sysroot": {Deny: true},
"/tmp": {Deny: true},
"/usr": {Deny: true},
"/var/run": {Deny: true},
"/var/tmp": {Deny: true},
})
// MountpointPolicies for ostree
@ -65,3 +92,22 @@ var OstreeMountpointPolicies = pathpolicy.NewPathPolicies(map[string]pathpolicy.
"/var/usrlocal": {Deny: true},
"/var/mnt": {Deny: true},
})
// CustomDirectoriesPolicies for ostree
var OstreeCustomDirectoriesPolicies = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPolicy{
"/": {Deny: true},
"/etc": {},
})
// CustomFilesPolicies for ostree
var OstreeCustomFilesPolicies = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPolicy{
"/": {Deny: true},
"/etc": {},
"/root": {},
"/usr/local/bin": {},
"/usr/local/sbin": {},
"/etc/fstab": {Deny: true},
"/etc/shadow": {Deny: true},
"/etc/passwd": {Deny: true},
"/etc/group": {Deny: true},
})

10
vendor/modules.txt vendored
View file

@ -846,8 +846,8 @@ github.com/oracle/oci-go-sdk/v54/identity
github.com/oracle/oci-go-sdk/v54/objectstorage
github.com/oracle/oci-go-sdk/v54/objectstorage/transfer
github.com/oracle/oci-go-sdk/v54/workrequests
# github.com/osbuild/images v0.51.0
## explicit; go 1.19
# github.com/osbuild/images v0.54.0
## explicit; go 1.20
github.com/osbuild/images/internal/common
github.com/osbuild/images/internal/environment
github.com/osbuild/images/internal/pathpolicy
@ -866,9 +866,11 @@ github.com/osbuild/images/pkg/customizations/users
github.com/osbuild/images/pkg/disk
github.com/osbuild/images/pkg/distro
github.com/osbuild/images/pkg/distro/fedora
github.com/osbuild/images/pkg/distro/rhel
github.com/osbuild/images/pkg/distro/rhel/rhel10
github.com/osbuild/images/pkg/distro/rhel/rhel8
github.com/osbuild/images/pkg/distro/rhel/rhel9
github.com/osbuild/images/pkg/distro/rhel7
github.com/osbuild/images/pkg/distro/rhel8
github.com/osbuild/images/pkg/distro/rhel9
github.com/osbuild/images/pkg/distro/test_distro
github.com/osbuild/images/pkg/distrofactory
github.com/osbuild/images/pkg/distroidparser