go.mod: update osbuild/images to v0.124.0

This commit is contained in:
Achilleas Koutsou 2025-03-17 18:08:15 +01:00 committed by Sanne Raymaekers
parent a27880c0c6
commit 6a112877f1
62 changed files with 2390 additions and 2108 deletions

2
go.mod
View file

@ -45,7 +45,7 @@ require (
github.com/oapi-codegen/runtime v1.1.1 github.com/oapi-codegen/runtime v1.1.1
github.com/openshift-online/ocm-sdk-go v0.1.438 github.com/openshift-online/ocm-sdk-go v0.1.438
github.com/oracle/oci-go-sdk/v54 v54.0.0 github.com/oracle/oci-go-sdk/v54 v54.0.0
github.com/osbuild/images v0.123.0 github.com/osbuild/images v0.124.0
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d
github.com/osbuild/pulp-client v0.1.0 github.com/osbuild/pulp-client v0.1.0
github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_golang v1.20.5

4
go.sum
View file

@ -575,8 +575,8 @@ github.com/openshift-online/ocm-sdk-go v0.1.438 h1:tsLCCUzbLCTL4RZG02y9RuopmGCXp
github.com/openshift-online/ocm-sdk-go v0.1.438/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y= github.com/openshift-online/ocm-sdk-go v0.1.438/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y=
github.com/oracle/oci-go-sdk/v54 v54.0.0 h1:CDLjeSejv2aDpElAJrhKpi6zvT/zhZCZuXchUUZ+LS4= github.com/oracle/oci-go-sdk/v54 v54.0.0 h1:CDLjeSejv2aDpElAJrhKpi6zvT/zhZCZuXchUUZ+LS4=
github.com/oracle/oci-go-sdk/v54 v54.0.0/go.mod h1:+t+yvcFGVp+3ZnztnyxqXfQDsMlq8U25faBLa+mqCMc= github.com/oracle/oci-go-sdk/v54 v54.0.0/go.mod h1:+t+yvcFGVp+3ZnztnyxqXfQDsMlq8U25faBLa+mqCMc=
github.com/osbuild/images v0.123.0 h1:9b2sfl6751dpAEU3wR0bMN1d/bEhbJ39N5a/9ZVCxcg= github.com/osbuild/images v0.124.0 h1:WnR2nf43HkNERzz6sa/+Ohzx3QW83bvIlaqi9NGvg4A=
github.com/osbuild/images v0.123.0/go.mod h1:Ag87vmyxooiPQBJEDILbypG8/SRIear75YA78NwLix0= github.com/osbuild/images v0.124.0/go.mod h1:Ag87vmyxooiPQBJEDILbypG8/SRIear75YA78NwLix0=
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d h1:r9BFPDv0uuA9k1947Jybcxs36c/pTywWS1gjeizvtcQ= github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d h1:r9BFPDv0uuA9k1947Jybcxs36c/pTywWS1gjeizvtcQ=
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d/go.mod h1:zR1iu/hOuf+OQNJlk70tju9IqzzM4ycq0ectkFBm94U= github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d/go.mod h1:zR1iu/hOuf+OQNJlk70tju9IqzzM4ycq0ectkFBm94U=
github.com/osbuild/pulp-client v0.1.0 h1:L0C4ezBJGTamN3BKdv+rKLuq/WxXJbsFwz/Hj7aEmJ8= github.com/osbuild/pulp-client v0.1.0 h1:L0C4ezBJGTamN3BKdv+rKLuq/WxXJbsFwz/Hj7aEmJ8=

View file

@ -59,3 +59,12 @@ func ExecError(err error) error {
} }
return err return err
} }
// Must() can be used to shortcut all `NewT() (T, err)` constructors.
// It will panic if an error is passed.
func Must[T any](val T, err error) T {
if err != nil {
panic(err)
}
return val
}

View file

@ -262,20 +262,19 @@ func (c *Customizations) GetGroups() []GroupCustomization {
} }
func (c *Customizations) GetKernel() *KernelCustomization { func (c *Customizations) GetKernel() *KernelCustomization {
var name string var kernelName, kernelAppend string
var append string
if c != nil && c.Kernel != nil { if c != nil && c.Kernel != nil {
name = c.Kernel.Name kernelName = c.Kernel.Name
append = c.Kernel.Append kernelAppend = c.Kernel.Append
} }
if name == "" { if kernelName == "" {
name = "kernel" kernelName = "kernel"
} }
return &KernelCustomization{ return &KernelCustomization{
Name: name, Name: kernelName,
Append: append, Append: kernelAppend,
} }
} }

View file

@ -6,9 +6,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
"regexp"
"slices" "slices"
"strings" "strings"
"github.com/google/uuid"
"github.com/osbuild/images/pkg/datasizes" "github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/pathpolicy" "github.com/osbuild/images/pkg/pathpolicy"
) )
@ -64,6 +66,12 @@ type PartitionCustomization struct {
// (optional, defaults depend on payload and mountpoints). // (optional, defaults depend on payload and mountpoints).
MinSize uint64 `json:"minsize" toml:"minsize"` MinSize uint64 `json:"minsize" toml:"minsize"`
// The partition type GUID for GPT partitions. For DOS partitions, this
// field can be used to set the (2 hex digit) partition type.
// If not set, the type will be automatically set based on the mountpoint
// or the payload type.
PartType string `json:"part_type,omitempty" toml:"part_type,omitempty"`
BtrfsVolumeCustomization BtrfsVolumeCustomization
VGCustomization VGCustomization
@ -154,8 +162,9 @@ type BtrfsSubvolumeCustomization struct {
func (v *PartitionCustomization) UnmarshalJSON(data []byte) error { func (v *PartitionCustomization) UnmarshalJSON(data []byte) error {
errPrefix := "JSON unmarshal:" errPrefix := "JSON unmarshal:"
var typeSniffer struct { var typeSniffer struct {
Type string `json:"type"` Type string `json:"type"`
MinSize any `json:"minsize"` MinSize any `json:"minsize"`
PartType string `json:"part_type"`
} }
if err := json.Unmarshal(data, &typeSniffer); err != nil { if err := json.Unmarshal(data, &typeSniffer); err != nil {
return fmt.Errorf("%s %w", errPrefix, err) return fmt.Errorf("%s %w", errPrefix, err)
@ -184,6 +193,7 @@ func (v *PartitionCustomization) UnmarshalJSON(data []byte) error {
} }
v.Type = partType v.Type = partType
v.PartType = typeSniffer.PartType
if typeSniffer.MinSize == nil { if typeSniffer.MinSize == nil {
return fmt.Errorf("minsize is required") return fmt.Errorf("minsize is required")
@ -203,10 +213,11 @@ func (v *PartitionCustomization) UnmarshalJSON(data []byte) error {
// the type is "plain", none of the fields for btrfs or lvm are used. // the type is "plain", none of the fields for btrfs or lvm are used.
func decodePlain(v *PartitionCustomization, data []byte) error { func decodePlain(v *PartitionCustomization, data []byte) error {
var plain struct { var plain struct {
// Type and minsize are handled by the caller. These are added here to // Type, minsize, and part_type are handled by the caller. These are added here to
// satisfy "DisallowUnknownFields" when decoding. // satisfy "DisallowUnknownFields" when decoding.
Type string `json:"type"` Type string `json:"type"`
MinSize any `json:"minsize"` MinSize any `json:"minsize"`
PartType string `json:"part_type"`
FilesystemTypedCustomization FilesystemTypedCustomization
} }
@ -226,10 +237,11 @@ func decodePlain(v *PartitionCustomization, data []byte) error {
// the type is btrfs, none of the fields for plain or lvm are used. // the type is btrfs, none of the fields for plain or lvm are used.
func decodeBtrfs(v *PartitionCustomization, data []byte) error { func decodeBtrfs(v *PartitionCustomization, data []byte) error {
var btrfs struct { var btrfs struct {
// Type and minsize are handled by the caller. These are added here to // Type, minsize, and part_type are handled by the caller. These are added here to
// satisfy "DisallowUnknownFields" when decoding. // satisfy "DisallowUnknownFields" when decoding.
Type string `json:"type"` Type string `json:"type"`
MinSize any `json:"minsize"` MinSize any `json:"minsize"`
PartType string `json:"part_type"`
BtrfsVolumeCustomization BtrfsVolumeCustomization
} }
@ -249,10 +261,11 @@ func decodeBtrfs(v *PartitionCustomization, data []byte) error {
// is lvm, none of the fields for plain or btrfs are used. // is lvm, none of the fields for plain or btrfs are used.
func decodeLVM(v *PartitionCustomization, data []byte) error { func decodeLVM(v *PartitionCustomization, data []byte) error {
var vg struct { var vg struct {
// Type and minsize are handled by the caller. These are added here to // Type, minsize, and part_type are handled by the caller. These are added here to
// satisfy "DisallowUnknownFields" when decoding. // satisfy "DisallowUnknownFields" when decoding.
Type string `json:"type"` Type string `json:"type"`
MinSize any `json:"minsize"` MinSize any `json:"minsize"`
PartType string `json:"part_type"`
VGCustomization VGCustomization
} }
@ -367,6 +380,9 @@ func (p *DiskCustomization) Validate() error {
vgnames := make(map[string]bool) vgnames := make(map[string]bool)
var errs []error var errs []error
for _, part := range p.Partitions { for _, part := range p.Partitions {
if err := part.ValidatePartitionTypeID(p.Type); err != nil {
errs = append(errs, err)
}
switch part.Type { switch part.Type {
case "plain", "": case "plain", "":
errs = append(errs, part.validatePlain(mountpoints)) errs = append(errs, part.validatePlain(mountpoints))
@ -471,6 +487,44 @@ var validPlainFSTypes = []string{
"xfs", "xfs",
} }
// exactly 2 hex digits
var validDosPartitionType = regexp.MustCompile(`^[0-9a-fA-F]{2}$`)
// ValidatePartitionTypeID returns an error if the partition type ID is not
// valid given the partition table type. If the partition table type is an
// empty string, the function returns an error only if the partition type ID is
// invalid for both gpt and dos partition tables.
func (p *PartitionCustomization) ValidatePartitionTypeID(ptType string) error {
// Empty PartType is fine, it will be selected automatically
if p.PartType == "" {
return nil
}
_, uuidErr := uuid.Parse(p.PartType)
validDosType := validDosPartitionType.MatchString(p.PartType)
switch ptType {
case "gpt":
if uuidErr != nil {
return fmt.Errorf("invalid partition part_type %q for partition table type %q (must be a valid UUID): %w", p.PartType, ptType, uuidErr)
}
case "dos":
if !validDosType {
return fmt.Errorf("invalid partition part_type %q for partition table type %q (must be a 2-digit hex number)", p.PartType, ptType)
}
case "":
// We don't know the partition table type yet, the fallback is controlled
// by the CustomPartitionTableOptions, so return an error if it fails both.
if uuidErr != nil && !validDosType {
return fmt.Errorf("invalid part_type %q: must be a valid UUID for GPT partition tables or a 2-digit hex number for DOS partition tables", p.PartType)
}
default:
// ignore: handled elsewhere
}
return nil
}
func (p *PartitionCustomization) validatePlain(mountpoints map[string]bool) error { func (p *PartitionCustomization) validatePlain(mountpoints map[string]bool) error {
if p.FSType == "swap" { if p.FSType == "swap" {
// make sure the mountpoint is empty and return // make sure the mountpoint is empty and return

View file

@ -1272,6 +1272,13 @@ func NewCustomPartitionTable(customizations *blueprint.DiskCustomization, option
} }
// add user customized partitions // add user customized partitions
for _, part := range customizations.Partitions { for _, part := range customizations.Partitions {
if part.PartType != "" {
// check the partition type now that we also know the partition table type
if err := part.ValidatePartitionTypeID(pt.Type.String()); err != nil {
return nil, fmt.Errorf("%s error validating partition type ID for %q: %w", errPrefix, part.Mountpoint, err)
}
}
switch part.Type { switch part.Type {
case "plain", "": case "plain", "":
if err := addPlainPartition(pt, part, options); err != nil { if err := addPlainPartition(pt, part, options); err != nil {
@ -1320,28 +1327,34 @@ func addPlainPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz
return fmt.Errorf("error creating partition with mountpoint %q: %w", partition.Mountpoint, err) return fmt.Errorf("error creating partition with mountpoint %q: %w", partition.Mountpoint, err)
} }
// all user-defined partitions are data partitions except boot and swap partType := partition.PartType
var typeName string
switch {
case partition.Mountpoint == "/":
typeName = "root"
case partition.Mountpoint == "/usr":
typeName = "usr"
case partition.Mountpoint == "/boot":
typeName = "boot"
case fstype == "swap":
typeName = "swap"
default:
typeName = "data"
}
partType, err := getPartitionTypeIDfor(pt.Type, typeName, options.Architecture) if partType == "" {
if err != nil { // if the partition type is not specified, determine it based on the
return fmt.Errorf("error getting partition type ID for %q: %w", partition.Mountpoint, err) // mountpoint and the partition type
var typeName string
switch {
case partition.Mountpoint == "/":
typeName = "root"
case partition.Mountpoint == "/usr":
typeName = "usr"
case partition.Mountpoint == "/boot":
typeName = "boot"
case fstype == "swap":
typeName = "swap"
default:
typeName = "data"
}
partType, err = getPartitionTypeIDfor(pt.Type, typeName, options.Architecture)
if err != nil {
return fmt.Errorf("error getting partition type ID for %q: %w", partition.Mountpoint, err)
}
} }
var payload PayloadEntity var payload PayloadEntity
switch typeName { switch fstype {
case "swap": case "swap":
payload = &Swap{ payload = &Swap{
Label: partition.Label, Label: partition.Label,
@ -1419,10 +1432,15 @@ func addLVMPartition(pt *PartitionTable, partition blueprint.PartitionCustomizat
} }
// create partition for volume group // create partition for volume group
partType, err := getPartitionTypeIDfor(pt.Type, "lvm", arch.ARCH_UNSET) partType := partition.PartType
if err != nil { if partType == "" {
return fmt.Errorf("error creating lvm partition %q: %w", vgname, err) var err error
partType, err = getPartitionTypeIDfor(pt.Type, "lvm", options.Architecture)
if err != nil {
return fmt.Errorf("error creating lvm partition %q: %w", vgname, err)
}
} }
newpart := Partition{ newpart := Partition{
Type: partType, Type: partType,
Size: partition.MinSize, Size: partition.MinSize,
@ -1448,9 +1466,13 @@ func addBtrfsPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz
} }
// create partition for btrfs volume // create partition for btrfs volume
partType, err := getPartitionTypeIDfor(pt.Type, "data", arch.ARCH_UNSET) partType := partition.PartType
if err != nil { if partType == "" {
return fmt.Errorf("error creating btrfs partition: %w", err) var err error
partType, err = getPartitionTypeIDfor(pt.Type, "data", arch.ARCH_UNSET)
if err != nil {
return fmt.Errorf("error creating btrfs partition: %w", err)
}
} }
newpart := Partition{ newpart := Partition{
Type: partType, Type: partType,

View file

@ -34,15 +34,6 @@ const (
// blueprint package set name // blueprint package set name
blueprintPkgsKey = "blueprint" blueprintPkgsKey = "blueprint"
//Default kernel command line
defaultKernelOptions = "ro"
// 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"
) )
var ( var (
@ -59,6 +50,23 @@ var (
} }
) )
// kernel command line arguments
// NOTE: we define them as functions to make sure they globals are never
// modified
// Default kernel command line
func defaultKernelOptions() []string { return []string{"ro"} }
// Added kernel command line options for ami, qcow2, openstack, vhd and vmdk types
func cloudKernelOptions() []string {
return []string{"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
func ostreeDeploymentKernelOptions() []string {
return []string{"modprobe.blacklist=vc4", "rw", "coreos.no_persist_ip"}
}
// Image Definitions // Image Definitions
func mkImageInstallerImgType(d distribution) imageType { func mkImageInstallerImgType(d distribution) imageType {
return imageType{ return imageType{
@ -67,7 +75,7 @@ func mkImageInstallerImgType(d distribution) imageType {
filename: "installer.iso", filename: "installer.iso",
mimeType: "application/x-iso9660-image", mimeType: "application/x-iso9660-image",
packageSets: map[string]packageSetFunc{ packageSets: map[string]packageSetFunc{
osPkgsKey: func(t *imageType) rpmmd.PackageSet { osPkgsKey: func(t *imageType) (rpmmd.PackageSet, error) {
// use the minimal raw image type for the OS package set // use the minimal raw image type for the OS package set
return packagesets.Load(t, "minimal-raw", VersionReplacements()) return packagesets.Load(t, "minimal-raw", VersionReplacements())
}, },
@ -164,8 +172,8 @@ func mkIotOCIImgType(d distribution) imageType {
mimeType: "application/x-tar", mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{ packageSets: map[string]packageSetFunc{
osPkgsKey: packageSetLoader, osPkgsKey: packageSetLoader,
containerPkgsKey: func(t *imageType) rpmmd.PackageSet { containerPkgsKey: func(t *imageType) (rpmmd.PackageSet, error) {
return rpmmd.PackageSet{} return rpmmd.PackageSet{}, nil
}, },
}, },
defaultImageConfig: &distro.ImageConfig{ defaultImageConfig: &distro.ImageConfig{
@ -235,7 +243,7 @@ func mkIotSimplifiedInstallerImgType(d distribution) imageType {
payloadPipelines: []string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"}, payloadPipelines: []string{"ostree-deployment", "image", "xz", "coi-tree", "efiboot-tree", "bootiso-tree", "bootiso"},
exports: []string{"bootiso"}, exports: []string{"bootiso"},
basePartitionTables: iotSimplifiedInstallerPartitionTables, basePartitionTables: iotSimplifiedInstallerPartitionTables,
kernelOptions: ostreeDeploymentKernelOptions, kernelOptions: ostreeDeploymentKernelOptions(),
requiredPartitionSizes: requiredDirectorySizes, requiredPartitionSizes: requiredDirectorySizes,
} }
} }
@ -265,7 +273,7 @@ func mkIotRawImgType(d distribution) imageType {
payloadPipelines: []string{"ostree-deployment", "image", "xz"}, payloadPipelines: []string{"ostree-deployment", "image", "xz"},
exports: []string{"xz"}, exports: []string{"xz"},
basePartitionTables: iotBasePartitionTables, basePartitionTables: iotBasePartitionTables,
kernelOptions: ostreeDeploymentKernelOptions, kernelOptions: ostreeDeploymentKernelOptions(),
// Passing an empty map into the required partition sizes disables the // Passing an empty map into the required partition sizes disables the
// default partition sizes normally set so our `basePartitionTables` can // default partition sizes normally set so our `basePartitionTables` can
@ -297,7 +305,7 @@ func mkIotQcow2ImgType(d distribution) imageType {
payloadPipelines: []string{"ostree-deployment", "image", "qcow2"}, payloadPipelines: []string{"ostree-deployment", "image", "qcow2"},
exports: []string{"qcow2"}, exports: []string{"qcow2"},
basePartitionTables: iotBasePartitionTables, basePartitionTables: iotBasePartitionTables,
kernelOptions: ostreeDeploymentKernelOptions, kernelOptions: ostreeDeploymentKernelOptions(),
requiredPartitionSizes: requiredDirectorySizes, requiredPartitionSizes: requiredDirectorySizes,
} }
} }
@ -314,7 +322,7 @@ func mkQcow2ImgType(d distribution) imageType {
defaultImageConfig: &distro.ImageConfig{ defaultImageConfig: &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"), DefaultTarget: common.ToPtr("multi-user.target"),
}, },
kernelOptions: cloudKernelOptions, kernelOptions: cloudKernelOptions(),
bootable: true, bootable: true,
defaultSize: 5 * datasizes.GibiByte, defaultSize: 5 * datasizes.GibiByte,
image: diskImage, image: diskImage,
@ -347,7 +355,7 @@ func mkVmdkImgType(d distribution) imageType {
osPkgsKey: packageSetLoader, osPkgsKey: packageSetLoader,
}, },
defaultImageConfig: vmdkDefaultImageConfig, defaultImageConfig: vmdkDefaultImageConfig,
kernelOptions: cloudKernelOptions, kernelOptions: cloudKernelOptions(),
bootable: true, bootable: true,
defaultSize: 2 * datasizes.GibiByte, defaultSize: 2 * datasizes.GibiByte,
image: diskImage, image: diskImage,
@ -368,7 +376,7 @@ func mkOvaImgType(d distribution) imageType {
osPkgsKey: packageSetLoader, osPkgsKey: packageSetLoader,
}, },
defaultImageConfig: vmdkDefaultImageConfig, defaultImageConfig: vmdkDefaultImageConfig,
kernelOptions: cloudKernelOptions, kernelOptions: cloudKernelOptions(),
bootable: true, bootable: true,
defaultSize: 2 * datasizes.GibiByte, defaultSize: 2 * datasizes.GibiByte,
image: diskImage, image: diskImage,
@ -412,6 +420,20 @@ func mkWslImgType(d distribution) imageType {
osPkgsKey: packageSetLoader, osPkgsKey: packageSetLoader,
}, },
defaultImageConfig: &distro.ImageConfig{ defaultImageConfig: &distro.ImageConfig{
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "99_wsl.cfg",
Config: osbuild.CloudInitConfigFile{
DatasourceList: []string{
"WSL",
"None",
},
Network: &osbuild.CloudInitConfigNetwork{
Config: "disabled",
},
},
},
},
NoSElinux: common.ToPtr(true), NoSElinux: common.ToPtr(true),
ExcludeDocs: common.ToPtr(true), ExcludeDocs: common.ToPtr(true),
Locale: common.ToPtr("C.UTF-8"), Locale: common.ToPtr("C.UTF-8"),
@ -432,7 +454,7 @@ func mkWslImgType(d distribution) imageType {
} }
func mkMinimalRawImgType(d distribution) imageType { func mkMinimalRawImgType(d distribution) imageType {
return imageType{ it := imageType{
name: "minimal-raw", name: "minimal-raw",
filename: "disk.raw.xz", filename: "disk.raw.xz",
compression: "xz", compression: "xz",
@ -452,7 +474,7 @@ func mkMinimalRawImgType(d distribution) imageType {
InstallWeakDeps: common.ToPtr(common.VersionLessThan(d.osVersion, VERSION_MINIMAL_WEAKDEPS)), InstallWeakDeps: common.ToPtr(common.VersionLessThan(d.osVersion, VERSION_MINIMAL_WEAKDEPS)),
}, },
rpmOstree: false, rpmOstree: false,
kernelOptions: defaultKernelOptions, kernelOptions: defaultKernelOptions(),
bootable: true, bootable: true,
defaultSize: 2 * datasizes.GibiByte, defaultSize: 2 * datasizes.GibiByte,
image: diskImage, image: diskImage,
@ -462,6 +484,12 @@ func mkMinimalRawImgType(d distribution) imageType {
basePartitionTables: minimalrawPartitionTables, basePartitionTables: minimalrawPartitionTables,
requiredPartitionSizes: requiredDirectorySizes, requiredPartitionSizes: requiredDirectorySizes,
} }
if common.VersionGreaterThanOrEqual(d.osVersion, "43") {
// from Fedora 43 onward, we stop writing /etc/fstab and start using
// mount units only
it.defaultImageConfig.MountUnits = common.ToPtr(true)
}
return it
} }
type distribution struct { type distribution struct {
@ -478,6 +506,7 @@ type distribution struct {
// Fedora based OS image configuration defaults // Fedora based OS image configuration defaults
var defaultDistroImageConfig = &distro.ImageConfig{ var defaultDistroImageConfig = &distro.ImageConfig{
Hostname: common.ToPtr("localhost.localdomain"),
Timezone: common.ToPtr("UTC"), Timezone: common.ToPtr("UTC"),
Locale: common.ToPtr("C.UTF-8"), Locale: common.ToPtr("C.UTF-8"),
DefaultOSCAPDatastream: common.ToPtr(oscap.DefaultFedoraDatastream()), DefaultOSCAPDatastream: common.ToPtr(oscap.DefaultFedoraDatastream()),

View file

@ -6,6 +6,7 @@ import (
"github.com/osbuild/images/internal/common" "github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/workload" "github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/blueprint" "github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/anaconda" "github.com/osbuild/images/pkg/customizations/anaconda"
@ -40,8 +41,8 @@ func osCustomizations(
osc.KernelName = c.GetKernel().Name osc.KernelName = c.GetKernel().Name
var kernelOptions []string var kernelOptions []string
if t.kernelOptions != "" { if len(t.kernelOptions) > 0 {
kernelOptions = append(kernelOptions, t.kernelOptions) kernelOptions = append(kernelOptions, t.kernelOptions...)
} }
if bpKernel := c.GetKernel(); bpKernel.Append != "" { if bpKernel := c.GetKernel(); bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append) kernelOptions = append(kernelOptions, bpKernel.Append)
@ -106,8 +107,8 @@ func osCustomizations(
if hostname := c.GetHostname(); hostname != nil { if hostname := c.GetHostname(); hostname != nil {
osc.Hostname = *hostname osc.Hostname = *hostname
} else { } else if imageConfig.Hostname != nil {
osc.Hostname = "localhost.localdomain" osc.Hostname = *imageConfig.Hostname
} }
if imageConfig.InstallWeakDeps != nil { if imageConfig.InstallWeakDeps != nil {
@ -242,6 +243,10 @@ func osCustomizations(
osc.MachineIdUninitialized = *imageConfig.MachineIdUninitialized osc.MachineIdUninitialized = *imageConfig.MachineIdUninitialized
} }
if imageConfig.MountUnits != nil {
osc.MountUnits = *imageConfig.MountUnits
}
return osc, nil return osc, nil
} }
@ -257,8 +262,8 @@ func ostreeDeploymentCustomizations(
deploymentConf := manifest.OSTreeDeploymentCustomizations{} deploymentConf := manifest.OSTreeDeploymentCustomizations{}
var kernelOptions []string var kernelOptions []string
if t.kernelOptions != "" { if len(t.kernelOptions) > 0 {
kernelOptions = append(kernelOptions, t.kernelOptions) kernelOptions = append(kernelOptions, t.kernelOptions...)
} }
if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" { if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append) kernelOptions = append(kernelOptions, bpKernel.Append)
@ -415,6 +420,11 @@ func liveInstallerImage(workload workload.Workload,
img.RootfsType = manifest.SquashfsRootfs img.RootfsType = manifest.SquashfsRootfs
} }
// Enable grub2 BIOS iso on x86_64 only
if img.Platform.GetArch() == arch.ARCH_X86_64 {
img.ISOBoot = manifest.Grub2ISOBoot
}
if locale := t.getDefaultImageConfig().Locale; locale != nil { if locale := t.getDefaultImageConfig().Locale; locale != nil {
img.Locale = *locale img.Locale = *locale
} }
@ -516,6 +526,11 @@ func imageInstallerImage(workload workload.Workload,
img.RootfsType = manifest.SquashfsRootfs img.RootfsType = manifest.SquashfsRootfs
} }
// Enable grub2 BIOS iso on x86_64 only
if img.Platform.GetArch() == arch.ARCH_X86_64 {
img.ISOBoot = manifest.Grub2ISOBoot
}
return img, nil return img, nil
} }
@ -727,6 +742,11 @@ func iotInstallerImage(workload workload.Workload,
img.RootfsType = manifest.SquashfsRootfs img.RootfsType = manifest.SquashfsRootfs
} }
// Enable grub2 BIOS iso on x86_64 only
if img.Platform.GetArch() == arch.ARCH_X86_64 {
img.ISOBoot = manifest.Grub2ISOBoot
}
if locale := t.getDefaultImageConfig().Locale; locale != nil { if locale := t.getDefaultImageConfig().Locale; locale != nil {
img.Locale = *locale img.Locale = *locale
} }

View file

@ -16,6 +16,7 @@ import (
"github.com/osbuild/images/pkg/datasizes" "github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/experimentalflags"
"github.com/osbuild/images/pkg/image" "github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform" "github.com/osbuild/images/pkg/platform"
@ -25,7 +26,7 @@ import (
type imageFunc func(workload workload.Workload, t *imageType, bp *blueprint.Blueprint, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error) type imageFunc func(workload workload.Workload, t *imageType, bp *blueprint.Blueprint, 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 packageSetFunc func(t *imageType) (rpmmd.PackageSet, error)
type isoLabelFunc func(t *imageType) string type isoLabelFunc func(t *imageType) string
@ -42,7 +43,7 @@ type imageType struct {
packageSets map[string]packageSetFunc packageSets map[string]packageSetFunc
defaultImageConfig *distro.ImageConfig defaultImageConfig *distro.ImageConfig
defaultInstallerConfig *distro.InstallerConfig defaultInstallerConfig *distro.InstallerConfig
kernelOptions string kernelOptions []string
defaultSize uint64 defaultSize uint64
buildPipelines []string buildPipelines []string
payloadPipelines []string payloadPipelines []string
@ -232,7 +233,11 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
// don't add any static packages if Minimal was selected // don't add any static packages if Minimal was selected
if !bp.Minimal { if !bp.Minimal {
for name, getter := range t.packageSets { for name, getter := range t.packageSets {
staticPackageSets[name] = getter(t) pkgSet, err := getter(t)
if err != nil {
return nil, nil, err
}
staticPackageSets[name] = pkgSet
} }
} }
@ -278,6 +283,16 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
w = cw w = cw
} }
if experimentalflags.Bool("no-fstab") {
if t.defaultImageConfig == nil {
t.defaultImageConfig = &distro.ImageConfig{
MountUnits: common.ToPtr(true),
}
} else {
t.defaultImageConfig.MountUnits = common.ToPtr(true)
}
}
containerSources := make([]container.SourceSpec, len(bp.Containers)) containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx, cont := range bp.Containers { for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{ containerSources[idx] = container.SourceSpec{

View file

@ -5,6 +5,6 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
func packageSetLoader(t *imageType) rpmmd.PackageSet { func packageSetLoader(t *imageType) (rpmmd.PackageSet, error) {
return packagesets.Load(t, "", VersionReplacements()) return packagesets.Load(t, "", VersionReplacements())
} }

View file

@ -12,6 +12,7 @@ import (
// ImageConfig represents a (default) configuration applied to the image payload. // ImageConfig represents a (default) configuration applied to the image payload.
type ImageConfig struct { type ImageConfig struct {
Hostname *string
Timezone *string Timezone *string
TimeSynchronization *osbuild.ChronyStageOptions TimeSynchronization *osbuild.ChronyStageOptions
Locale *string Locale *string
@ -103,6 +104,10 @@ type ImageConfig struct {
// machine id to be set to 'uninitialized' which causes ConditionFirstboot // machine id to be set to 'uninitialized' which causes ConditionFirstboot
// to be triggered in systemd // to be triggered in systemd
MachineIdUninitialized *bool MachineIdUninitialized *bool
// MountUnits creates systemd .mount units to describe the filesystem
// instead of writing to /etc/fstab
MountUnits *bool
} }
// InheritFrom inherits unset values from the provided parent configuration and // InheritFrom inherits unset values from the provided parent configuration and

File diff suppressed because it is too large Load diff

View file

@ -4,13 +4,18 @@ import (
"embed" "embed"
"fmt" "fmt"
"io/fs" "io/fs"
"os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"github.com/osbuild/images/internal/common" "github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/experimentalflags"
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
@ -19,6 +24,15 @@ var data embed.FS
var DataFS fs.FS = data var DataFS fs.FS = data
type toplevelYAML struct {
ImageTypes map[string]imageType `yaml:"image_types"`
Common map[string]any `yaml:".common,omitempty"`
}
type imageType struct {
PackageSets []packageSet `yaml:"package_sets"`
}
type packageSet struct { type packageSet struct {
Include []string `yaml:"include"` Include []string `yaml:"include"`
Exclude []string `yaml:"exclude"` Exclude []string `yaml:"exclude"`
@ -36,7 +50,7 @@ type conditions struct {
// imagetype. By default the imagetype name is used to load the packageset // imagetype. By default the imagetype name is used to load the packageset
// but with "overrideTypeName" this can be overriden (useful for e.g. // but with "overrideTypeName" this can be overriden (useful for e.g.
// installer image types). // installer image types).
func Load(it distro.ImageType, overrideTypeName string, replacements map[string]string) rpmmd.PackageSet { func Load(it distro.ImageType, overrideTypeName string, replacements map[string]string) (rpmmd.PackageSet, error) {
typeName := it.Name() typeName := it.Name()
if overrideTypeName != "" { if overrideTypeName != "" {
typeName = overrideTypeName typeName = overrideTypeName
@ -51,69 +65,109 @@ func Load(it distro.ImageType, overrideTypeName string, replacements map[string]
// distro names, sadly go has no rsplit() so we do it manually // distro names, sadly go has no rsplit() so we do it manually
// XXX: we cannot use distroidparser here because of import cycles // XXX: we cannot use distroidparser here because of import cycles
distroName := distroNameVer[:strings.LastIndex(distroNameVer, "-")] distroName := distroNameVer[:strings.LastIndex(distroNameVer, "-")]
distroVersion := distribution.OsVersion() distroVersion := strings.SplitN(distroNameVer, "-", 2)[1]
distroNameMajorVer := strings.SplitN(distroNameVer, ".", 2)[0]
distroSets, err := DataFS.Open(filepath.Join(distroName, "package_sets.yaml")) // XXX: this is a short term measure, pass a set of
if err != nil { // searchPaths down the stack instead
panic(err) var dataFS fs.FS = DataFS
if overrideDir := experimentalflags.String("yamldir"); overrideDir != "" {
logrus.Warnf("using experimental override dir %q", overrideDir)
dataFS = os.DirFS(overrideDir)
} }
decoder := yaml.NewDecoder(distroSets) // XXX: this is only needed temporary until we have a "distros.yaml"
// that describes some high-level properties of each distro
// (like their yaml dirs)
var baseDir string
switch distroName {
case "rhel":
// rhel yaml files are under ./rhel-$majorVer
baseDir = distroNameMajorVer
case "centos":
// centos yaml is just rhel but we have (sadly) no symlinks
// in "go:embed" so we have to have this slightly ugly
// workaround
baseDir = fmt.Sprintf("rhel-%s", distroVersion)
case "fedora", "test-distro":
// our other distros just have a single yaml dir per distro
// and use condition.version_gt etc
baseDir = distroName
default:
return rpmmd.PackageSet{}, fmt.Errorf("unsupported distro in loader %q (add to loader.go)", distroName)
}
f, err := dataFS.Open(filepath.Join(baseDir, "package_sets.yaml"))
if err != nil {
return rpmmd.PackageSet{}, err
}
defer f.Close()
decoder := yaml.NewDecoder(f)
decoder.KnownFields(true) decoder.KnownFields(true)
var pkgSets map[string]packageSet // each imagetype can have multiple package sets, so that we can
if err := decoder.Decode(&pkgSets); err != nil { // use yaml aliases/anchors to de-duplicate them
panic(err) var toplevel toplevelYAML
if err := decoder.Decode(&toplevel); err != nil {
return rpmmd.PackageSet{}, err
} }
pkgSet, ok := pkgSets[typeName] imgType, ok := toplevel.ImageTypes[typeName]
if !ok { if !ok {
panic(fmt.Sprintf("unknown package set name %q", typeName)) return rpmmd.PackageSet{}, fmt.Errorf("unknown image type name %q", typeName)
}
rpmmdPkgSet := rpmmd.PackageSet{
Include: pkgSet.Include,
Exclude: pkgSet.Exclude,
} }
if pkgSet.Condition != nil { var rpmmdPkgSet rpmmd.PackageSet
// process conditions for _, pkgSet := range imgType.PackageSets {
if archSet, ok := pkgSet.Condition.Architecture[archName]; ok { rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{
rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{ Include: pkgSet.Include,
Include: archSet.Include, Exclude: pkgSet.Exclude,
Exclude: archSet.Exclude, })
})
}
if distroNameSet, ok := pkgSet.Condition.DistroName[distroName]; ok {
rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{
Include: distroNameSet.Include,
Exclude: distroNameSet.Exclude,
})
}
for ltVer, ltSet := range pkgSet.Condition.VersionLessThan { if pkgSet.Condition != nil {
if r, ok := replacements[ltVer]; ok { // process conditions
ltVer = r if archSet, ok := pkgSet.Condition.Architecture[archName]; ok {
}
if common.VersionLessThan(distroVersion, ltVer) {
rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{ rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{
Include: ltSet.Include, Include: archSet.Include,
Exclude: ltSet.Exclude, Exclude: archSet.Exclude,
}) })
} }
} if distroNameSet, ok := pkgSet.Condition.DistroName[distroName]; ok {
for gteqVer, gteqSet := range pkgSet.Condition.VersionGreaterOrEqual {
if r, ok := replacements[gteqVer]; ok {
gteqVer = r
}
if common.VersionGreaterThanOrEqual(distroVersion, gteqVer) {
rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{ rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{
Include: gteqSet.Include, Include: distroNameSet.Include,
Exclude: gteqSet.Exclude, Exclude: distroNameSet.Exclude,
}) })
} }
for ltVer, ltSet := range pkgSet.Condition.VersionLessThan {
if r, ok := replacements[ltVer]; ok {
ltVer = r
}
if common.VersionLessThan(distroVersion, ltVer) {
rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{
Include: ltSet.Include,
Exclude: ltSet.Exclude,
})
}
}
for gteqVer, gteqSet := range pkgSet.Condition.VersionGreaterOrEqual {
if r, ok := replacements[gteqVer]; ok {
gteqVer = r
}
if common.VersionGreaterThanOrEqual(distroVersion, gteqVer) {
rpmmdPkgSet = rpmmdPkgSet.Append(rpmmd.PackageSet{
Include: gteqSet.Include,
Exclude: gteqSet.Exclude,
})
}
}
} }
} }
// mostly for tests
sort.Strings(rpmmdPkgSet.Include)
sort.Strings(rpmmdPkgSet.Exclude)
return rpmmdPkgSet return rpmmdPkgSet, nil
} }

View file

@ -0,0 +1,712 @@
---
.common:
distro_build_pkgset: &distro_build_pkgset
include:
- "dnf"
- "dosfstools"
- "e2fsprogs"
- "glibc"
- "lorax-templates-generic"
- "lorax-templates-rhel"
- "lvm2"
- "policycoreutils"
- "python3-iniparse"
- "qemu-img"
- "selinux-policy-targeted"
- "systemd"
- "tar"
- "xfsprogs"
- "xz"
condition:
architecture:
x86_64:
include:
- "grub2-pc"
ppc64el:
include:
- "grub2-ppc64le"
- "grub2-ppc64le-modules"
sap_pkgset: &sap_pkgset
include:
# RHBZ#2076763
- "@Server"
# SAP System Roles
# https:#access.redhat.com/sites/default/files/attachments/rhel_system_roles_for_sap_1.pdf
- "ansible-core"
- "rhel-system-roles-sap"
# RHBZ#1959813
- "bind-utils"
- "nfs-utils"
- "tcsh"
# RHBZ#1959955
- "uuidd"
# RHBZ#1959923
- "cairo"
- "expect"
- "graphviz"
# "gtk2" # gtk2 is not available in RHEL-10
- "iptraf-ng"
- "krb5-workstation"
- "libaio"
- "libatomic"
- "libicu"
- "libtool-ltdl"
- "lm_sensors"
- "net-tools"
- "numactl"
- "PackageKit-gtk3-module"
- "xorg-x11-xauth"
# RHBZ#1960617
- "tuned-profiles-sap-hana"
# RHBZ#1961168
- "libnsl"
exclude:
- "iwl1000-firmware"
- "iwl100-firmware"
- "iwl105-firmware"
- "iwl135-firmware"
- "iwl2000-firmware"
- "iwl2030-firmware"
- "iwl3160-firmware"
- "iwl5000-firmware"
- "iwl5150-firmware"
- "iwl6000g2a-firmware"
- "iwl6000g2b-firmware"
- "iwl6050-firmware"
- "iwl7260-firmware"
installer_pkgset: &installer_pkgset
include:
- "anaconda-dracut"
- "curl"
- "dracut-config-generic"
- "dracut-network"
- "hostname"
- "iwl100-firmware"
- "iwl1000-firmware"
- "iwl105-firmware"
- "iwl135-firmware"
- "iwl2000-firmware"
- "iwl2030-firmware"
- "iwl3160-firmware"
- "iwl5000-firmware"
- "iwl5150-firmware"
- "iwl6050-firmware"
- "iwl7260-firmware"
- "kernel"
- "less"
- "nfs-utils"
- "openssh-clients"
- "ostree"
- "plymouth"
- "prefixdevname"
- "rng-tools"
- "rpcbind"
- "selinux-policy-targeted"
- "systemd"
- "tar"
- "xfsprogs"
- "xz"
# Extra packages that are required by the dracut stage of all installers.
# These are weak deps of other packages in the list above, but lets be
# explicit about what we need and not rely on the weak deps. Relying
# on hard-dependencies for other modules is OK for now.
#
# TODO: add these dynamically based on the modules enabled by each
# pipeline.
- "mdadm"
- "nss-softokn"
anaconda_boot_pkgset: &anaconda_boot_pkgset
condition:
architecture:
x86_64:
include:
# eficommon
- "efibootmgr"
# XXX: de-dup?
# grub-common
- "grub2-tools"
- "grub2-tools-extra"
- "grub2-tools-minimal"
# arch specific
- "grub2-efi-x64"
- "grub2-efi-x64-cdboot"
- "grub2-pc"
- "grub2-pc-modules"
- "shim-x64"
- "syslinux"
- "syslinux-nonlinux"
aarch64:
include:
# eficommon
- "efibootmgr"
# XXX: de-dup?
# grub-common
- "grub2-tools"
- "grub2-tools-extra"
- "grub2-tools-minimal"
# arch specific
- "grub2-efi-aa64-cdboot"
- "grub2-efi-aa64"
- "shim-aa64"
image_types:
# XXX: not a real pkgset but the "os" pipeline pkgset for image-installer
# find a nicer way to represent this
bare_metal:
package_sets:
- *distro_build_pkgset
- include:
- "@core"
- "chrony"
- "cockpit-system"
- "cockpit-ws"
- "dnf-utils"
- "dosfstools"
- "firewalld"
- "iwl1000-firmware"
- "iwl100-firmware"
- "iwl105-firmware"
- "iwl135-firmware"
- "iwl2000-firmware"
- "iwl2030-firmware"
- "iwl3160-firmware"
- "iwl5000-firmware"
- "iwl5150-firmware"
- "iwl6000g2a-firmware"
- "iwl6000g2b-firmware"
- "iwl6050-firmware"
- "iwl7260-firmware"
- "lvm2"
- "net-tools"
- "nfs-utils"
- "oddjob"
- "oddjob-mkhomedir"
- "policycoreutils"
- "psmisc"
- "python3-jsonschema"
- "qemu-guest-agent"
- "redhat-release"
- "redhat-release-eula"
- "rsync"
- "tar"
- "tcpdump"
- "tuned"
exclude:
- "dracut-config-rescue"
condition:
distro_name:
rhel:
include:
- "subscription-manager-cockpit"
qcow2: &qcow2
package_sets:
- include:
- "@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:
- "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"
- "plymouth"
- "rng-tools"
- "udisks2"
condition:
distro_name:
rhel:
include:
- "insights-client"
- "subscription-manager-cockpit"
oci: *qcow2
vhd: &vhd
package_sets:
- &vhd_pkgset
include:
- "@Server"
- "bzip2"
- "cloud-init"
- "cloud-utils-growpart"
- "dracut-config-generic"
- "efibootmgr"
- "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:
- "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"
condition:
distro_name:
rhel:
include:
- "insights-client"
azure_rhui: *vhd
azure_sap_rhui:
package_sets:
- *vhd_pkgset
- *sap_pkgset
tar:
package_sets:
- include:
- "policycoreutils"
- "selinux-policy-targeted"
exclude:
- "rng-tools"
vmdk: &vmdk
package_sets:
- include:
- "@core"
- "chrony"
- "cloud-init"
- "firewalld"
- "langpacks-en"
- "open-vm-tools"
- "tuned"
exclude:
- "dracut-config-rescue"
- "rng-tools"
ova: *vmdk
ami: &ami
package_sets:
- &ami_pkgset
include:
- "@core"
- "chrony"
- "cloud-init"
- "cloud-utils-growpart"
- "dhcpcd"
- "yum-utils"
- "dracut-config-generic"
- "grub2"
- "langpacks-en"
- "NetworkManager-cloud-setup"
- "redhat-release"
- "redhat-release-eula"
- "rsync"
- "tuned"
- "tar"
exclude:
- "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"
condition:
distro_name:
rhel:
include:
- "insights-client"
ec2: *ami
ec2_ha:
package_sets:
- *ami_pkgset
- include:
- "fence-agents-all"
- "pacemaker"
- "pcs"
ec2_sap:
package_sets:
- *ami_pkgset
- *sap_pkgset
wsl:
package_sets:
- include:
- "alternatives"
- "audit-libs"
- "basesystem"
- "bash"
- "ca-certificates"
- "cloud-init"
- "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:
- "gawk-all-langpacks"
- "glibc-gconv-extra"
- "glibc-langpack-en"
- "openssl-pkcs11"
- "python-unversioned-command"
- "redhat-release-eula"
- "rpm-plugin-systemd-inhibit"
image_installer:
package_sets:
- *installer_pkgset
- *anaconda_boot_pkgset
- include:
- "@hardware-support"
- "alsa-firmware"
- "alsa-tools-firmware"
- "anaconda"
- "anaconda-dracut"
- "anaconda-install-img-deps"
- "anaconda-widgets"
- "audit"
- "bind-utils"
- "bzip2"
- "cryptsetup"
- "curl"
- "dbus-x11"
- "default-fonts-core-sans"
- "default-fonts-other-sans"
- "dejavu-sans-fonts"
- "dejavu-sans-mono-fonts"
- "device-mapper-persistent-data"
- "dmidecode"
- "dnf"
- "dracut-config-generic"
- "dracut-network"
- "efibootmgr"
- "ethtool"
- "fcoe-utils"
- "ftp"
- "gdb-gdbserver"
- "glibc-all-langpacks"
- "gnome-kiosk"
- "google-noto-sans-cjk-ttc-fonts"
- "grub2-tools"
- "grub2-tools-extra"
- "grub2-tools-minimal"
- "grubby"
- "gsettings-desktop-schemas"
- "hdparm"
- "hexedit"
- "hostname"
- "initscripts"
- "ipmitool"
- "iwl1000-firmware"
- "iwl100-firmware"
- "iwl105-firmware"
- "iwl135-firmware"
- "iwl2000-firmware"
- "iwl2030-firmware"
- "iwl3160-firmware"
- "iwl5000-firmware"
- "iwl5150-firmware"
- "iwl6000g2a-firmware"
- "iwl6000g2b-firmware"
- "iwl6050-firmware"
- "iwl7260-firmware"
- "jomolhari-fonts"
- "kbd"
- "kbd-misc"
- "kdump-anaconda-addon"
- "kernel"
- "less"
- "libblockdev-lvm-dbus"
- "libibverbs"
- "librsvg2"
- "linux-firmware"
- "lldpad"
- "lsof"
- "madan-fonts"
- "mtr"
- "mt-st"
- "net-tools"
- "nfs-utils"
- "nmap-ncat"
- "nm-connection-editor"
- "nss-tools"
- "openssh-clients"
- "openssh-server"
# the package is not yet available on c10s / el10
# "oscap-anaconda-addon"
- "ostree"
- "pciutils"
- "perl-interpreter"
- "pigz"
- "plymouth"
- "prefixdevname"
- "python3-pyatspi"
- "rdma-core"
- "redhat-release-eula"
- "rng-tools"
- "rpcbind"
- "rpm-ostree"
- "rsync"
- "rsyslog"
- "selinux-policy-targeted"
- "sg3_utils"
- "sil-padauk-fonts"
- "smartmontools"
- "spice-vdagent"
- "strace"
- "systemd"
- "tar"
- "udisks2"
- "udisks2-iscsi"
- "usbutils"
- "vim-minimal"
- "volume_key"
- "wget"
- "xfsdump"
- "xfsprogs"
- "xz"
condition:
architecture:
x86_64:
include:
- "biosdevname"
- "dmidecode"
- "grub2-tools-efi"
- "memtest86+"
aarch64:
include:
- "dmidecode"
gce:
package_sets:
- include:
- "@core"
- "langpacks-en" # not in Google's KS
- "acpid"
- "dnf-automatic"
- "net-tools"
- "python3"
- "rng-tools"
- "tar"
- "vim"
# GCE guest tools
# TODO: uncomment once the package is available
# the el9 version depends on libboost_regex.so.1.75.0()(64bit), which is not available on el10
# - "google-compute-engine"
- "google-osconfig-agent"
# Requires gdisk which was removed late in the RHEL 10 development cycle
# - "gce-disk-expand"
# cloud-init is a replacement for- "google-compute-engine" remove once the package is available
- "cloud-init"
# Not explicitly included in GCP kickstart, but present on the image
# for time synchronization
- "chrony"
- "timedatex"
# EFI
- "grub2-tools"
- "grub2-tools-minimal"
# Performance tuning
- "tuned"
exclude:
- "alsa-utils"
- "b43-fwcutter"
- "dmraid"
- "dracut-config-rescue"
- "eject"
- "gpm"
- "irqbalance"
- "microcode_ctl"
- "smartmontools"
- "aic94xx-firmware"
- "atmel-firmware"
- "b43-openfwwf"
- "bfa-firmware"
- "ipw2100-firmware"
- "ipw2200-firmware"
- "ivtv-firmware"
- "iwl100-firmware"
- "iwl105-firmware"
- "iwl135-firmware"
- "iwl1000-firmware"
- "iwl2000-firmware"
- "iwl2030-firmware"
- "iwl3160-firmware"
- "iwl3945-firmware"
- "iwl4965-firmware"
- "iwl5000-firmware"
- "iwl5150-firmware"
- "iwl6000-firmware"
- "iwl6000g2a-firmware"
- "iwl6050-firmware"
- "iwl7260-firmware"
- "kernel-firmware"
- "libertas-usb8388-firmware"
- "ql2100-firmware"
- "ql2200-firmware"
- "ql23xx-firmware"
- "ql2400-firmware"
- "ql2500-firmware"
- "rt61pci-firmware"
- "rt73usb-firmware"
- "xorg-x11-drv-ati-firmware"
- "zd1211-firmware"
# RHBZ#2075815
- "qemu-guest-agent"
condition:
distro_name:
rhel:
include:
- "insights-client"

View file

@ -5,6 +5,7 @@ import (
"math/rand" "math/rand"
"github.com/osbuild/images/internal/workload" "github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/blueprint" "github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/customizations/anaconda" "github.com/osbuild/images/pkg/customizations/anaconda"
@ -39,8 +40,8 @@ func osCustomizations(
osc.KernelName = c.GetKernel().Name osc.KernelName = c.GetKernel().Name
var kernelOptions []string var kernelOptions []string
if t.KernelOptions != "" { if len(t.KernelOptions) > 0 {
kernelOptions = append(kernelOptions, t.KernelOptions) kernelOptions = append(kernelOptions, t.KernelOptions...)
} }
if bpKernel := c.GetKernel(); bpKernel.Append != "" { if bpKernel := c.GetKernel(); bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append) kernelOptions = append(kernelOptions, bpKernel.Append)
@ -283,6 +284,10 @@ func osCustomizations(
osc.InstallWeakDeps = *imageConfig.InstallWeakDeps osc.InstallWeakDeps = *imageConfig.InstallWeakDeps
} }
if imageConfig.MountUnits != nil {
osc.MountUnits = *imageConfig.MountUnits
}
return osc, nil return osc, nil
} }
@ -298,8 +303,8 @@ func ostreeDeploymentCustomizations(
deploymentConf := manifest.OSTreeDeploymentCustomizations{} deploymentConf := manifest.OSTreeDeploymentCustomizations{}
var kernelOptions []string var kernelOptions []string
if t.KernelOptions != "" { if len(t.KernelOptions) > 0 {
kernelOptions = append(kernelOptions, t.KernelOptions) kernelOptions = append(kernelOptions, t.KernelOptions...)
} }
if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" { if bpKernel := c.GetKernel(); bpKernel != nil && bpKernel.Append != "" {
kernelOptions = append(kernelOptions, bpKernel.Append) kernelOptions = append(kernelOptions, bpKernel.Append)
@ -357,6 +362,10 @@ func ostreeDeploymentCustomizations(
deploymentConf.CustomFileSystems = append(deploymentConf.CustomFileSystems, fs.Mountpoint) deploymentConf.CustomFileSystems = append(deploymentConf.CustomFileSystems, fs.Mountpoint)
} }
if imageConfig.MountUnits != nil {
deploymentConf.MountUnits = *imageConfig.MountUnits
}
return deploymentConf, nil return deploymentConf, nil
} }
@ -504,6 +513,17 @@ func EdgeInstallerImage(workload workload.Workload,
img.RootfsType = manifest.SquashfsRootfs img.RootfsType = manifest.SquashfsRootfs
} }
// Enable BIOS iso on x86_64 only
// Use grub2 on RHEL10, otherwise use syslinux
// NOTE: Will need to be updated for RHEL11 and later
if img.Platform.GetArch() == arch.ARCH_X86_64 {
if t.Arch().Distro().Releasever() == "10" {
img.ISOBoot = manifest.Grub2ISOBoot
} else {
img.ISOBoot = manifest.SyslinuxISOBoot
}
}
installerConfig, err := t.getDefaultInstallerConfig() installerConfig, err := t.getDefaultInstallerConfig()
if err != nil { if err != nil {
return nil, err return nil, err
@ -730,6 +750,17 @@ func ImageInstallerImage(workload workload.Workload,
img.RootfsType = manifest.SquashfsRootfs img.RootfsType = manifest.SquashfsRootfs
} }
// Enable BIOS iso on x86_64 only
// Use grub2 on RHEL10, otherwise use syslinux
// NOTE: Will need to be updated for RHEL11 and later
if img.Platform.GetArch() == arch.ARCH_X86_64 {
if t.Arch().Distro().Releasever() == "10" {
img.ISOBoot = manifest.Grub2ISOBoot
} else {
img.ISOBoot = manifest.SyslinuxISOBoot
}
}
// put the kickstart file in the root of the iso // put the kickstart file in the root of the iso
img.ISORootKickstart = true img.ISORootKickstart = true

View file

@ -6,6 +6,7 @@ import (
"slices" "slices"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment" "github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/workload" "github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint" "github.com/osbuild/images/pkg/blueprint"
@ -13,6 +14,7 @@ import (
"github.com/osbuild/images/pkg/datasizes" "github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/experimentalflags"
"github.com/osbuild/images/pkg/image" "github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/osbuild"
@ -76,7 +78,7 @@ type ImageType struct {
Compression string // TODO: remove from image definition and make it a transport option Compression string // TODO: remove from image definition and make it a transport option
DefaultImageConfig *distro.ImageConfig DefaultImageConfig *distro.ImageConfig
DefaultInstallerConfig *distro.InstallerConfig DefaultInstallerConfig *distro.InstallerConfig
KernelOptions string KernelOptions []string
DefaultSize uint64 DefaultSize uint64
// bootISO: installable ISO // bootISO: installable ISO
@ -338,6 +340,16 @@ func (t *ImageType) Manifest(bp *blueprint.Blueprint,
} }
} }
if experimentalflags.Bool("no-fstab") {
if t.DefaultImageConfig == nil {
t.DefaultImageConfig = &distro.ImageConfig{
MountUnits: common.ToPtr(true),
}
} else {
t.DefaultImageConfig.MountUnits = common.ToPtr(true)
}
}
source := rand.NewSource(seed) source := rand.NewSource(seed)
// math/rand is good enough in this case // math/rand is good enough in this case
/* #nosec G404 */ /* #nosec G404 */

View file

@ -6,16 +6,29 @@ import (
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
) )
// TODO: move these to the EC2 environment
func amiKernelOptions() []string {
return []string{"console=tty0", "console=ttyS0,115200n8", "nvme_core.io_timeout=4294967295"}
}
func amiAarch64KernelOptions() []string {
return append(amiKernelOptions(), "iommu.strict=0")
}
func amiSapKernelOptions() []string {
return append(amiKernelOptions(), []string{"processor.max_cstate=1", "intel_idle.max_cstate=1"}...)
}
func mkAMIImgTypeX86_64() *rhel.ImageType { func mkAMIImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
"ami", "ami",
"image.raw", "image.raw",
"application/octet-stream", "application/octet-stream",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2PackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -23,7 +36,7 @@ func mkAMIImgTypeX86_64() *rhel.ImageType {
[]string{"image"}, []string{"image"},
) )
it.KernelOptions = amiKernelOptions it.KernelOptions = amiKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64() it.DefaultImageConfig = defaultEc2ImageConfigX86_64()
@ -38,7 +51,7 @@ func mkAMIImgTypeAarch64() *rhel.ImageType {
"image.raw", "image.raw",
"application/octet-stream", "application/octet-stream",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2PackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -46,7 +59,7 @@ func mkAMIImgTypeAarch64() *rhel.ImageType {
[]string{"image"}, []string{"image"},
) )
it.KernelOptions = amiAarch64KernelOptions it.KernelOptions = amiAarch64KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfig() it.DefaultImageConfig = defaultEc2ImageConfig()
@ -62,7 +75,7 @@ func mkEc2ImgTypeX86_64() *rhel.ImageType {
"image.raw.xz", "image.raw.xz",
"application/xz", "application/xz",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2PackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -71,7 +84,7 @@ func mkEc2ImgTypeX86_64() *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = amiKernelOptions it.KernelOptions = amiKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64() it.DefaultImageConfig = defaultEc2ImageConfigX86_64()
@ -87,7 +100,7 @@ func mkEC2ImgTypeAarch64() *rhel.ImageType {
"image.raw.xz", "image.raw.xz",
"application/xz", "application/xz",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ec2PackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -96,7 +109,7 @@ func mkEC2ImgTypeAarch64() *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = amiAarch64KernelOptions it.KernelOptions = amiAarch64KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfig() it.DefaultImageConfig = defaultEc2ImageConfig()
@ -112,7 +125,7 @@ func mkEc2HaImgTypeX86_64() *rhel.ImageType {
"image.raw.xz", "image.raw.xz",
"application/xz", "application/xz",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2HaPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -121,7 +134,7 @@ func mkEc2HaImgTypeX86_64() *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = amiKernelOptions it.KernelOptions = amiKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64() it.DefaultImageConfig = defaultEc2ImageConfigX86_64()
@ -136,7 +149,7 @@ func mkEC2SapImgTypeX86_64(osVersion string) *rhel.ImageType {
"image.raw.xz", "image.raw.xz",
"application/xz", "application/xz",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: rhelEc2SapPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -145,7 +158,7 @@ func mkEC2SapImgTypeX86_64(osVersion string) *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = amiSapKernelOptions it.KernelOptions = amiSapKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64()) it.DefaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64())
@ -156,13 +169,6 @@ func mkEC2SapImgTypeX86_64(osVersion string) *rhel.ImageType {
// IMAGE CONFIG // IMAGE CONFIG
// TODO: move these to the EC2 environment
const (
amiKernelOptions = "console=tty0 console=ttyS0,115200n8 nvme_core.io_timeout=4294967295"
amiAarch64KernelOptions = amiKernelOptions + " iommu.strict=0"
amiSapKernelOptions = amiKernelOptions + " processor.max_cstate=1 intel_idle.max_cstate=1"
)
// default EC2 images config (common for all architectures) // default EC2 images config (common for all architectures)
func defaultEc2ImageConfig() *distro.ImageConfig { func defaultEc2ImageConfig() *distro.ImageConfig {
return &distro.ImageConfig{ return &distro.ImageConfig{
@ -287,84 +293,3 @@ func defaultEc2ImageConfigX86_64() *distro.ImageConfig {
ic := defaultEc2ImageConfig() ic := defaultEc2ImageConfig()
return appendEC2DracutX86_64(ic) return appendEC2DracutX86_64(ic)
} }
// PACKAGE SETS
func ec2PackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cloud-init",
"cloud-utils-growpart",
"dhcpcd",
"yum-utils",
"dracut-config-generic",
"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
}
// rhel-ha-ec2 image package set
func rhelEc2HaPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ec2HaPackageSet := ec2PackageSet(t)
ec2HaPackageSet = ec2HaPackageSet.Append(rpmmd.PackageSet{
Include: []string{
"fence-agents-all",
"pacemaker",
"pcs",
},
})
return ec2HaPackageSet
}
// rhel-sap-ec2 image package set
func rhelEc2SapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
//"libcanberra-gtk2", // libcanberra-gtk2 is not available in RHEL-10
},
}.Append(ec2PackageSet(t)).Append(SapPackageSet(t))
}

View file

@ -8,7 +8,6 @@ import (
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
) )
// Azure image type // Azure image type
@ -18,7 +17,7 @@ func mkAzureImgType(rd *rhel.Distribution) *rhel.ImageType {
"disk.vhd", "disk.vhd",
"application/x-vhd", "application/x-vhd",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -26,7 +25,7 @@ func mkAzureImgType(rd *rhel.Distribution) *rhel.ImageType {
[]string{"vpc"}, []string{"vpc"},
) )
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig(rd) it.DefaultImageConfig = defaultAzureImageConfig(rd)
@ -42,7 +41,7 @@ func mkAzureInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
"disk.vhd.xz", "disk.vhd.xz",
"application/xz", "application/xz",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azurePackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -51,7 +50,7 @@ func mkAzureInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig(rd) it.DefaultImageConfig = defaultAzureImageConfig(rd)
@ -66,7 +65,7 @@ func mkAzureSapInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
"disk.vhd.xz", "disk.vhd.xz",
"application/xz", "application/xz",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: azureSapPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -75,7 +74,7 @@ func mkAzureSapInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = sapAzureImageConfig(rd) it.DefaultImageConfig = sapAzureImageConfig(rd)
@ -84,98 +83,6 @@ func mkAzureSapInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
return it 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",
"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)
}
// Azure SAP image package set
// Includes the common azure package set, the common SAP packages
func azureSapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return azureCommonPackageSet(t).Append(SapPackageSet(t))
}
// PARTITION TABLES // PARTITION TABLES
func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) { func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() { switch t.Arch().Name() {
@ -401,7 +308,9 @@ func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, b
// IMAGE CONFIG // IMAGE CONFIG
// use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT // 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" func defaultAzureKernelOptions() []string {
return []string{"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 // 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
func defaultAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig { func defaultAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig {

View file

@ -1,10 +1,9 @@
package rhel10 package rhel10
import ( import (
"fmt" "github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/packagesets"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
@ -15,12 +14,7 @@ func mkTarImgType() *rhel.ImageType {
"root.tar.xz", "root.tar.xz",
"application/x-tar", "application/x-tar",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet { rhel.OSPkgsKey: packageSetLoader,
return rpmmd.PackageSet{
Include: []string{"policycoreutils", "selinux-policy-targeted"},
Exclude: []string{"rng-tools"},
}
},
}, },
rhel.TarImage, rhel.TarImage,
[]string{"build"}, []string{"build"},
@ -35,8 +29,10 @@ func mkImageInstallerImgType() *rhel.ImageType {
"installer.iso", "installer.iso",
"application/x-iso9660-image", "application/x-iso9660-image",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: bareMetalPackageSet, rhel.OSPkgsKey: func(t *rhel.ImageType) rpmmd.PackageSet {
rhel.InstallerPkgsKey: anacondaPackageSet, return common.Must(packagesets.Load(t, "bare-metal", nil))
},
rhel.InstallerPkgsKey: packageSetLoader,
}, },
rhel.ImageInstallerImage, rhel.ImageInstallerImage,
[]string{"build"}, []string{"build"},
@ -63,268 +59,3 @@ func mkImageInstallerImgType() *rhel.ImageType {
return it return it
} }
// PACKAGE SETS
func bareMetalPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"chrony",
"cockpit-system",
"cockpit-ws",
"dnf-utils",
"dosfstools",
"firewalld",
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6000g2a-firmware",
"iwl6000g2b-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
"lvm2",
"net-tools",
"nfs-utils",
"oddjob",
"oddjob-mkhomedir",
"policycoreutils",
"psmisc",
"python3-jsonschema",
"qemu-guest-agent",
"redhat-release",
"redhat-release-eula",
"rsync",
"tar",
"tcpdump",
"tuned",
},
Exclude: []string{
"dracut-config-rescue",
},
}.Append(distroBuildPackageSet(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 installerPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"anaconda-dracut",
"curl",
"dracut-config-generic",
"dracut-network",
"hostname",
"iwl100-firmware",
"iwl1000-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
"kernel",
"less",
"nfs-utils",
"openssh-clients",
"ostree",
"plymouth",
"prefixdevname",
"rng-tools",
"rpcbind",
"selinux-policy-targeted",
"systemd",
"tar",
"xfsprogs",
"xz",
},
}
ps = ps.Append(rpmmd.PackageSet{
// Extra packages that are required by the dracut stage of all installers.
// These are weak deps of other packages in the list above, but lets be
// explicit about what we need and not rely on the weak deps. Relying
// on hard-dependencies for other modules is OK for now.
//
// TODO: add these dynamically based on the modules enabled by each
// pipeline.
Include: []string{
"mdadm",
"nss-softokn",
},
})
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"biosdevname",
},
})
}
return ps
}
func anacondaPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
// common installer packages
ps := installerPackageSet(t)
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"@hardware-support",
"alsa-firmware",
"alsa-tools-firmware",
"anaconda",
"anaconda-dracut",
"anaconda-install-img-deps",
"anaconda-widgets",
"audit",
"bind-utils",
"bzip2",
"cryptsetup",
"curl",
"dbus-x11",
"default-fonts-core-sans",
"default-fonts-other-sans",
"dejavu-sans-fonts",
"dejavu-sans-mono-fonts",
"device-mapper-persistent-data",
"dmidecode",
"dnf",
"dracut-config-generic",
"dracut-network",
"efibootmgr",
"ethtool",
"fcoe-utils",
"ftp",
"gdb-gdbserver",
"glibc-all-langpacks",
"gnome-kiosk",
"google-noto-sans-cjk-ttc-fonts",
"grub2-tools",
"grub2-tools-extra",
"grub2-tools-minimal",
"grubby",
"gsettings-desktop-schemas",
"hdparm",
"hexedit",
"hostname",
"initscripts",
"ipmitool",
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6000g2a-firmware",
"iwl6000g2b-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
"jomolhari-fonts",
"kbd",
"kbd-misc",
"kdump-anaconda-addon",
"kernel",
"less",
"libblockdev-lvm-dbus",
"libibverbs",
"librsvg2",
"linux-firmware",
"lldpad",
"lsof",
"madan-fonts",
"mtr",
"mt-st",
"net-tools",
"nfs-utils",
"nmap-ncat",
"nm-connection-editor",
"nss-tools",
"openssh-clients",
"openssh-server",
// the package is not yet available on c10s / el10
//"oscap-anaconda-addon",
"ostree",
"pciutils",
"perl-interpreter",
"pigz",
"plymouth",
"prefixdevname",
"python3-pyatspi",
"rdma-core",
"redhat-release-eula",
"rng-tools",
"rpcbind",
"rpm-ostree",
"rsync",
"rsyslog",
"selinux-policy-targeted",
"sg3_utils",
"sil-padauk-fonts",
"smartmontools",
"spice-vdagent",
"strace",
"systemd",
"tar",
"udisks2",
"udisks2-iscsi",
"usbutils",
"vim-minimal",
"volume_key",
"wget",
"xfsdump",
"xfsprogs",
"xz",
},
})
ps = ps.Append(anacondaBootPackageSet(t))
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"biosdevname",
"dmidecode",
"grub2-tools-efi",
"memtest86+",
},
})
case arch.ARCH_AARCH64.String():
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"dmidecode",
},
})
default:
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps
}

View file

@ -6,10 +6,11 @@ import (
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
) )
const gceKernelOptions = "biosdevname=0 scsi_mod.use_blk_mq=Y console=ttyS0,38400n8d" func gceKernelOptions() []string {
return []string{"biosdevname=0", "scsi_mod.use_blk_mq=Y", "console=ttyS0,38400n8d"}
}
func mkGCEImageType() *rhel.ImageType { func mkGCEImageType() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -17,7 +18,7 @@ func mkGCEImageType() *rhel.ImageType {
"image.tar.gz", "image.tar.gz",
"application/gzip", "application/gzip",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: gcePackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -26,7 +27,7 @@ func mkGCEImageType() *rhel.ImageType {
) )
it.DefaultImageConfig = baseGCEImageConfig() it.DefaultImageConfig = baseGCEImageConfig()
it.KernelOptions = gceKernelOptions it.KernelOptions = gceKernelOptions()
it.DefaultSize = 20 * datasizes.GibiByte it.DefaultSize = 20 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only // TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
@ -135,92 +136,3 @@ func baseGCEImageConfig() *distro.ImageConfig {
return ic return ic
} }
func gceCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{
Include: []string{
"@core",
"langpacks-en", // not in Google's KS
"acpid",
"dnf-automatic",
"net-tools",
"python3",
"rng-tools",
"tar",
"vim",
// GCE guest tools
// TODO: uncomment once the package is available
// the el9 version depends on libboost_regex.so.1.75.0()(64bit), which is not available on el10
//"google-compute-engine",
"google-osconfig-agent",
// Requires gdisk which was removed late in the RHEL 10 development cycle
// "gce-disk-expand",
// cloud-init is a replacement for "google-compute-engine", remove once the package is available
"cloud-init",
// Not explicitly included in GCP kickstart, but present on the image
// for time synchronization
"chrony",
"timedatex",
// EFI
"grub2-tools",
"grub2-tools-minimal",
// Performance tuning
"tuned",
},
Exclude: []string{
"alsa-utils",
"b43-fwcutter",
"dmraid",
"dracut-config-rescue",
"eject",
"gpm",
"irqbalance",
"microcode_ctl",
"smartmontools",
"aic94xx-firmware",
"atmel-firmware",
"b43-openfwwf",
"bfa-firmware",
"ipw2100-firmware",
"ipw2200-firmware",
"ivtv-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl1000-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl3945-firmware",
"iwl4965-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6000-firmware",
"iwl6000g2a-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
"kernel-firmware",
"libertas-usb8388-firmware",
"ql2100-firmware",
"ql2200-firmware",
"ql23xx-firmware",
"ql2400-firmware",
"ql2500-firmware",
"rt61pci-firmware",
"rt73usb-firmware",
"xorg-x11-drv-ati-firmware",
"zd1211-firmware",
// RHBZ#2075815
"qemu-guest-agent",
},
}.Append(distroSpecificPackageSet(t))
return ps
}
// GCE image
func gcePackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return gceCommonPackageSet(t)
}

View file

@ -3,130 +3,12 @@ package rhel10
// This file defines package sets that are used by more than one image type. // This file defines package sets that are used by more than one image type.
import ( import (
"fmt" "github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro/packagesets"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
// BUILD PACKAGE SETS func packageSetLoader(t *rhel.ImageType) rpmmd.PackageSet {
return common.Must(packagesets.Load(t, "", nil))
// 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",
},
}
}
// installer boot package sets, needed for booting and
// also in the build host
func anacondaBootPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{}
grubCommon := rpmmd.PackageSet{
Include: []string{
"grub2-tools",
"grub2-tools-extra",
"grub2-tools-minimal",
},
}
efiCommon := rpmmd.PackageSet{
Include: []string{
"efibootmgr",
},
}
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
ps = ps.Append(grubCommon)
ps = ps.Append(efiCommon)
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"grub2-efi-x64",
"grub2-efi-x64-cdboot",
"grub2-pc",
"grub2-pc-modules",
"shim-x64",
"syslinux",
"syslinux-nonlinux",
},
})
case arch.ARCH_AARCH64.String():
ps = ps.Append(grubCommon)
ps = ps.Append(efiCommon)
ps = ps.Append(rpmmd.PackageSet{
Include: []string{
"grub2-efi-aa64-cdboot",
"grub2-efi-aa64",
"shim-aa64",
},
})
default:
panic(fmt.Sprintf("unsupported arch: %s", t.Arch().Name()))
}
return ps
}
// 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

@ -6,7 +6,6 @@ import (
"github.com/osbuild/images/pkg/datasizes" "github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
) )
func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType { func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType {
@ -15,7 +14,7 @@ func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType {
"disk.qcow2", "disk.qcow2",
"application/x-qemu-disk", "application/x-qemu-disk",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -24,7 +23,7 @@ func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType {
) )
it.DefaultImageConfig = qcowImageConfig(d) it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check"}
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -38,7 +37,7 @@ func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
"disk.qcow2", "disk.qcow2",
"application/x-qemu-disk", "application/x-qemu-disk",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: qcow2CommonPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -47,7 +46,7 @@ func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
) )
it.DefaultImageConfig = qcowImageConfig(d) it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check"}
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -55,80 +54,6 @@ func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
return it 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",
"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 qcowImageConfig(d *rhel.Distribution) *distro.ImageConfig { func qcowImageConfig(d *rhel.Distribution) *distro.ImageConfig {
ic := &distro.ImageConfig{ ic := &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"), DefaultTarget: common.ToPtr("multi-user.target"),

View file

@ -2,9 +2,7 @@ package rhel10
import ( import (
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
) )
// sapImageConfig returns the SAP specific ImageConfig data // sapImageConfig returns the SAP specific ImageConfig data
@ -118,57 +116,3 @@ func sapImageConfig(osVersion string) *distro.ImageConfig {
}, },
} }
} }
func SapPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
return rpmmd.PackageSet{
Include: []string{
// RHBZ#2076763
"@Server",
// SAP System Roles
// https://access.redhat.com/sites/default/files/attachments/rhel_system_roles_for_sap_1.pdf
"ansible-core",
"rhel-system-roles-sap",
// RHBZ#1959813
"bind-utils",
"nfs-utils",
"tcsh",
// RHBZ#1959955
"uuidd",
// RHBZ#1959923
"cairo",
"expect",
"graphviz",
//"gtk2", // gtk2 is not available in RHEL-10
"iptraf-ng",
"krb5-workstation",
"libaio",
"libatomic",
"libicu",
"libtool-ltdl",
"lm_sensors",
"net-tools",
"numactl",
"PackageKit-gtk3-module",
"xorg-x11-xauth",
// RHBZ#1960617
"tuned-profiles-sap-hana",
// RHBZ#1961168
"libnsl",
},
Exclude: []string{
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6000g2a-firmware",
"iwl6000g2b-firmware",
"iwl6050-firmware",
"iwl7260-firmware",
},
}
}

View file

@ -5,7 +5,6 @@ import (
"github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"
) )
func mkWSLImgType() *rhel.ImageType { func mkWSLImgType() *rhel.ImageType {
@ -14,7 +13,7 @@ func mkWSLImgType() *rhel.ImageType {
"disk.tar.gz", "disk.tar.gz",
"application/x-tar", "application/x-tar",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ubiCommonPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.TarImage, rhel.TarImage,
[]string{"build"}, []string{"build"},
@ -23,6 +22,20 @@ func mkWSLImgType() *rhel.ImageType {
) )
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "99_wsl.cfg",
Config: osbuild.CloudInitConfigFile{
DatasourceList: []string{
"WSL",
"None",
},
Network: &osbuild.CloudInitConfigNetwork{
Config: "disabled",
},
},
},
},
NoSElinux: common.ToPtr(true), NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{ WSLConfig: &osbuild.WSLConfStageOptions{
Boot: osbuild.WSLConfBootOptions{ Boot: osbuild.WSLConfBootOptions{
@ -33,63 +46,3 @@ func mkWSLImgType() *rhel.ImageType {
return it 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

@ -3,10 +3,11 @@ package rhel10
import ( import (
"github.com/osbuild/images/pkg/datasizes" "github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
) )
const vmdkKernelOptions = "ro" func vmdkKernelOptions() []string {
return []string{"ro"}
}
func mkVMDKImgType() *rhel.ImageType { func mkVMDKImgType() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -14,7 +15,7 @@ func mkVMDKImgType() *rhel.ImageType {
"disk.vmdk", "disk.vmdk",
"application/x-vmdk", "application/x-vmdk",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -22,7 +23,7 @@ func mkVMDKImgType() *rhel.ImageType {
[]string{"vmdk"}, []string{"vmdk"},
) )
it.KernelOptions = vmdkKernelOptions it.KernelOptions = vmdkKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -36,7 +37,7 @@ func mkOVAImgType() *rhel.ImageType {
"image.ova", "image.ova",
"application/ovf", "application/ovf",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: vmdkCommonPackageSet, rhel.OSPkgsKey: packageSetLoader,
}, },
rhel.DiskImage, rhel.DiskImage,
[]string{"build"}, []string{"build"},
@ -44,30 +45,10 @@ func mkOVAImgType() *rhel.ImageType {
[]string{"archive"}, []string{"archive"},
) )
it.KernelOptions = vmdkKernelOptions it.KernelOptions = vmdkKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
return it 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

@ -14,9 +14,9 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
const ( func ec2KernelOptions() []string {
ec2KernelOptions = "ro console=tty0 console=ttyS0,115200n8 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto LANG=en_US.UTF-8" return []string{"ro", "console=tty0", "console=ttyS0,115200n8", "net.ifnames=0", "rd.blacklist=nouveau", "nvme_core.io_timeout=4294967295", "crashkernel=auto", "LANG=en_US.UTF-8"}
) }
func mkEc2ImgTypeX86_64() *rhel.ImageType { func mkEc2ImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -37,7 +37,7 @@ func mkEc2ImgTypeX86_64() *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = ec2ImageConfig() it.DefaultImageConfig = ec2ImageConfig()
it.KernelOptions = ec2KernelOptions it.KernelOptions = ec2KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables

View file

@ -32,7 +32,7 @@ func mkAzureRhuiImgType() *rhel.ImageType {
it.DiskImageVPCForceSize = common.ToPtr(false) it.DiskImageVPCForceSize = common.ToPtr(false)
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = "ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y" it.KernelOptions = []string{"ro", "crashkernel=auto", "console=tty1", "console=ttyS0", "earlyprintk=ttyS0", "rootdelay=300", "scsi_mod.use_blk_mq=y"}
it.DefaultImageConfig = azureDefaultImgConfig it.DefaultImageConfig = azureDefaultImgConfig
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte

View file

@ -27,7 +27,7 @@ func mkQcow2ImgType() *rhel.ImageType {
// all RHEL 7 images should use sgdisk // all RHEL 7 images should use sgdisk
it.DiskImagePartTool = common.ToPtr(osbuild.PTSgdisk) it.DiskImagePartTool = common.ToPtr(osbuild.PTSgdisk)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check", "net.ifnames=0", "crashkernel=auto"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = qcow2DefaultImgConfig it.DefaultImageConfig = qcow2DefaultImgConfig

View file

@ -10,11 +10,17 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
const ( func amiX86KernelOptions() []string {
amiX86KernelOptions = "console=tty0 console=ttyS0,115200n8 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto" return []string{"console=tty0", "console=ttyS0,115200n8", "net.ifnames=0", "rd.blacklist=nouveau", "nvme_core.io_timeout=4294967295", "crashkernel=auto"}
amiAarch64KernelOptions = "console=tty0 console=ttyS0,115200n8 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 iommu.strict=0 crashkernel=auto" }
amiSapKernelOptions = "console=tty0 console=ttyS0,115200n8 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto processor.max_cstate=1 intel_idle.max_cstate=1"
) func amiAarch64KernelOptions() []string {
return []string{"console=tty0", "console=ttyS0,115200n8", "net.ifnames=0", "rd.blacklist=nouveau", "nvme_core.io_timeout=4294967295", "iommu.strict=0", "crashkernel=auto"}
}
func amiSapKernelOptions() []string {
return []string{"console=tty0", "console=ttyS0,115200n8", "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 { func mkAmiImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -31,7 +37,7 @@ func mkAmiImgTypeX86_64() *rhel.ImageType {
) )
it.DefaultImageConfig = defaultAMIImageConfigX86_64() it.DefaultImageConfig = defaultAMIImageConfigX86_64()
it.KernelOptions = amiX86KernelOptions it.KernelOptions = amiX86KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables
@ -55,7 +61,7 @@ func mkEc2ImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultEc2ImageConfigX86_64(rd) it.DefaultImageConfig = defaultEc2ImageConfigX86_64(rd)
it.KernelOptions = amiX86KernelOptions it.KernelOptions = amiX86KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables
@ -79,7 +85,7 @@ func mkEc2HaImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultEc2ImageConfigX86_64(rd) it.DefaultImageConfig = defaultEc2ImageConfigX86_64(rd)
it.KernelOptions = amiX86KernelOptions it.KernelOptions = amiX86KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables
@ -102,7 +108,7 @@ func mkAmiImgTypeAarch64() *rhel.ImageType {
) )
it.DefaultImageConfig = defaultAMIImageConfig() it.DefaultImageConfig = defaultAMIImageConfig()
it.KernelOptions = amiAarch64KernelOptions it.KernelOptions = amiAarch64KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables
@ -126,7 +132,7 @@ func mkEc2ImgTypeAarch64(rd *rhel.Distribution) *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultEc2ImageConfig(rd) it.DefaultImageConfig = defaultEc2ImageConfig(rd)
it.KernelOptions = amiAarch64KernelOptions it.KernelOptions = amiAarch64KernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables
@ -150,7 +156,7 @@ func mkEc2SapImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultEc2SapImageConfigX86_64(rd) it.DefaultImageConfig = defaultEc2SapImageConfigX86_64(rd)
it.KernelOptions = amiSapKernelOptions it.KernelOptions = amiSapKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables it.BasePartitionTables = ec2PartitionTables

View file

@ -14,7 +14,9 @@ import (
) )
// use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT // 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 defaultAzureKernelOptions() []string {
return []string{"ro", "loglevel=3", "crashkernel=auto", "console=tty1", "console=ttyS0", "earlyprintk=ttyS0", "rootdelay=300"}
}
func mkAzureRhuiImgType() *rhel.ImageType { func mkAzureRhuiImgType() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -32,7 +34,7 @@ func mkAzureRhuiImgType() *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(defaultVhdImageConfig()) it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(defaultVhdImageConfig())
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables it.BasePartitionTables = azureRhuiBasePartitionTables
@ -56,7 +58,7 @@ func mkAzureSapRhuiImgType(rd *rhel.Distribution) *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd)) it.DefaultImageConfig = defaultAzureRhuiImageConfig.InheritFrom(sapAzureImageConfig(rd))
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables it.BasePartitionTables = azureRhuiBasePartitionTables
@ -79,7 +81,7 @@ func mkAzureByosImgType() *rhel.ImageType {
) )
it.DefaultImageConfig = defaultAzureByosImageConfig.InheritFrom(defaultVhdImageConfig()) it.DefaultImageConfig = defaultAzureByosImageConfig.InheritFrom(defaultVhdImageConfig())
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -103,7 +105,7 @@ func mkAzureImgType() *rhel.ImageType {
) )
it.DefaultImageConfig = defaultVhdImageConfig() it.DefaultImageConfig = defaultVhdImageConfig()
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -127,7 +129,7 @@ func mkAzureEap7RhuiImgType() *rhel.ImageType {
it.Compression = "xz" it.Compression = "xz"
it.DefaultImageConfig = defaultAzureEapImageConfig.InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig)) it.DefaultImageConfig = defaultAzureEapImageConfig.InheritFrom(defaultAzureRhuiImageConfig.InheritFrom(defaultAzureImageConfig))
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables it.BasePartitionTables = azureRhuiBasePartitionTables

View file

@ -81,7 +81,7 @@ func mkEdgeRawImgType() *rhel.ImageType {
it.NameAliases = []string{"rhel-edge-raw-image"} it.NameAliases = []string{"rhel-edge-raw-image"}
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = "modprobe.blacklist=vc4" it.KernelOptions = []string{"modprobe.blacklist=vc4"}
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
Keyboard: &osbuild.KeymapStageOptions{ Keyboard: &osbuild.KeymapStageOptions{
Keymap: "us", Keymap: "us",
@ -162,7 +162,7 @@ func mkEdgeSimplifiedInstallerImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.NameAliases = []string{"rhel-edge-simplified-installer"} it.NameAliases = []string{"rhel-edge-simplified-installer"}
it.KernelOptions = "modprobe.blacklist=vc4" it.KernelOptions = []string{"modprobe.blacklist=vc4"}
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
EnabledServices: edgeServices(rd), EnabledServices: edgeServices(rd),
Keyboard: &osbuild.KeymapStageOptions{ Keyboard: &osbuild.KeymapStageOptions{
@ -212,7 +212,7 @@ func mkMinimalRawImgType() *rhel.ImageType {
// requires a kickstart file in the root directory. // requires a kickstart file in the root directory.
Files: []*fsnode.File{initialSetupKickstart()}, Files: []*fsnode.File{initialSetupKickstart()},
} }
it.KernelOptions = "ro" it.KernelOptions = []string{"ro"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 2 * datasizes.GibiByte it.DefaultSize = 2 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables

View file

@ -10,7 +10,9 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
const gceKernelOptions = "net.ifnames=0 biosdevname=0 scsi_mod.use_blk_mq=Y crashkernel=auto console=ttyS0,38400n8d" func gceKernelOptions() []string {
return []string{"net.ifnames=0", "biosdevname=0", "scsi_mod.use_blk_mq=Y", "crashkernel=auto", "console=ttyS0,38400n8d"}
}
func mkGceImgType(rd distro.Distro) *rhel.ImageType { func mkGceImgType(rd distro.Distro) *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -27,7 +29,7 @@ func mkGceImgType(rd distro.Distro) *rhel.ImageType {
) )
it.DefaultImageConfig = defaultGceByosImageConfig(rd) it.DefaultImageConfig = defaultGceByosImageConfig(rd)
it.KernelOptions = gceKernelOptions it.KernelOptions = gceKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 20 * datasizes.GibiByte it.DefaultSize = 20 * datasizes.GibiByte
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only // TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
@ -51,7 +53,7 @@ func mkGceRhuiImgType(rd distro.Distro) *rhel.ImageType {
) )
it.DefaultImageConfig = defaultGceRhuiImageConfig(rd) it.DefaultImageConfig = defaultGceRhuiImageConfig(rd)
it.KernelOptions = gceKernelOptions it.KernelOptions = gceKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 20 * datasizes.GibiByte it.DefaultSize = 20 * datasizes.GibiByte
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only // TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only

View file

@ -24,7 +24,7 @@ func mkQcow2ImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.DefaultImageConfig = qcowImageConfig(rd) it.DefaultImageConfig = qcowImageConfig(rd)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check", "net.ifnames=0", "crashkernel=auto"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -47,7 +47,7 @@ func mkOCIImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.DefaultImageConfig = qcowImageConfig(rd) it.DefaultImageConfig = qcowImageConfig(rd)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check", "net.ifnames=0", "crashkernel=auto"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -69,7 +69,7 @@ func mkOpenstackImgType() *rhel.ImageType {
[]string{"qcow2"}, []string{"qcow2"},
) )
it.KernelOptions = "ro net.ifnames=0" it.KernelOptions = []string{"ro", "net.ifnames=0"}
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables

View file

@ -14,7 +14,7 @@ func mkWslImgType() *rhel.ImageType {
"disk.tar.gz", "disk.tar.gz",
"application/x-tar", "application/x-tar",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ubiCommonPackageSet, rhel.OSPkgsKey: wslPackageSet,
}, },
rhel.TarImage, rhel.TarImage,
[]string{"build"}, []string{"build"},
@ -23,6 +23,20 @@ func mkWslImgType() *rhel.ImageType {
) )
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "99_wsl.cfg",
Config: osbuild.CloudInitConfigFile{
DatasourceList: []string{
"WSL",
"None",
},
Network: &osbuild.CloudInitConfigNetwork{
Config: "disabled",
},
},
},
},
Locale: common.ToPtr("en_US.UTF-8"), Locale: common.ToPtr("en_US.UTF-8"),
NoSElinux: common.ToPtr(true), NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{ WSLConfig: &osbuild.WSLConfStageOptions{
@ -35,7 +49,7 @@ func mkWslImgType() *rhel.ImageType {
return it return it
} }
func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet { func wslPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{ ps := rpmmd.PackageSet{
Include: []string{ Include: []string{
"alternatives", "alternatives",
@ -44,6 +58,7 @@ func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
"bash", "bash",
"brotli", "brotli",
"ca-certificates", "ca-certificates",
"cloud-init",
"coreutils-single", "coreutils-single",
"crypto-policies-scripts", "crypto-policies-scripts",
"curl", "curl",
@ -87,7 +102,6 @@ func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
"alsa-tools-firmware", "alsa-tools-firmware",
"biosdevname", "biosdevname",
"cpio", "cpio",
"diffutils",
"dnf-plugin-spacewalk", "dnf-plugin-spacewalk",
"dracut", "dracut",
"elfutils-debuginfod-client", "elfutils-debuginfod-client",
@ -112,18 +126,15 @@ func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
"libkcapi", "libkcapi",
"libkcapi-hmaccalc", "libkcapi-hmaccalc",
"libsecret", "libsecret",
"libselinux-utils",
"libxkbcommon", "libxkbcommon",
"libertas-sd8787-firmware", "libertas-sd8787-firmware",
"memstrack", "memstrack",
"nss", "nss",
"openssl",
"openssl-pkcs11", "openssl-pkcs11",
"os-prober", "os-prober",
"pigz", "pigz",
"pinentry", "pinentry",
"plymouth", "plymouth",
"policycoreutils",
"python3-unbound", "python3-unbound",
"redhat-release-eula", "redhat-release-eula",
"rng-tools", "rng-tools",

View file

@ -6,7 +6,9 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
const vmdkKernelOptions = "ro net.ifnames=0" func vmdkKernelOptions() []string {
return []string{"ro", "net.ifnames=0"}
}
func mkVmdkImgType() *rhel.ImageType { func mkVmdkImgType() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -22,7 +24,7 @@ func mkVmdkImgType() *rhel.ImageType {
[]string{"vmdk"}, []string{"vmdk"},
) )
it.KernelOptions = vmdkKernelOptions it.KernelOptions = vmdkKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -44,7 +46,7 @@ func mkOvaImgType() *rhel.ImageType {
[]string{"archive"}, []string{"archive"},
) )
it.KernelOptions = vmdkKernelOptions it.KernelOptions = vmdkKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables

View file

@ -10,7 +10,10 @@ import (
) )
// TODO: move these to the EC2 environment // TODO: move these to the EC2 environment
const amiKernelOptions = "console=tty0 console=ttyS0,115200n8 net.ifnames=0 nvme_core.io_timeout=4294967295"
func amiKernelOptions() []string {
return []string{"console=tty0", "console=ttyS0,115200n8", "net.ifnames=0", "nvme_core.io_timeout=4294967295"}
}
// default EC2 images config (common for all architectures) // default EC2 images config (common for all architectures)
func defaultEc2ImageConfig() *distro.ImageConfig { func defaultEc2ImageConfig() *distro.ImageConfig {
@ -275,7 +278,7 @@ func mkEc2ImgTypeX86_64() *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = amiKernelOptions it.KernelOptions = amiKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64() it.DefaultImageConfig = defaultEc2ImageConfigX86_64()
@ -298,7 +301,7 @@ func mkAMIImgTypeX86_64() *rhel.ImageType {
[]string{"image"}, []string{"image"},
) )
it.KernelOptions = amiKernelOptions it.KernelOptions = amiKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64() it.DefaultImageConfig = defaultEc2ImageConfigX86_64()
@ -322,7 +325,7 @@ func mkEC2SapImgTypeX86_64(osVersion string) *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 nvme_core.io_timeout=4294967295 processor.max_cstate=1 intel_idle.max_cstate=1" it.KernelOptions = []string{"console=ttyS0,115200n8", "console=tty0", "net.ifnames=0", "nvme_core.io_timeout=4294967295", "processor.max_cstate=1", "intel_idle.max_cstate=1"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64()) it.DefaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64())
@ -346,7 +349,7 @@ func mkEc2HaImgTypeX86_64() *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = amiKernelOptions it.KernelOptions = amiKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfigX86_64() it.DefaultImageConfig = defaultEc2ImageConfigX86_64()
@ -369,7 +372,7 @@ func mkAMIImgTypeAarch64() *rhel.ImageType {
[]string{"image"}, []string{"image"},
) )
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 nvme_core.io_timeout=4294967295 iommu.strict=0" it.KernelOptions = []string{"console=ttyS0,115200n8", "console=tty0", "net.ifnames=0", "nvme_core.io_timeout=4294967295", "iommu.strict=0"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfig() it.DefaultImageConfig = defaultEc2ImageConfig()
@ -393,7 +396,7 @@ func mkEC2ImgTypeAarch64() *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = "console=ttyS0,115200n8 console=tty0 net.ifnames=0 nvme_core.io_timeout=4294967295 iommu.strict=0" it.KernelOptions = []string{"console=ttyS0,115200n8", "console=tty0", "net.ifnames=0", "nvme_core.io_timeout=4294967295", "iommu.strict=0"}
it.Bootable = true it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = defaultEc2ImageConfig() it.DefaultImageConfig = defaultEc2ImageConfig()

View file

@ -26,7 +26,7 @@ func mkAzureImgType(rd *rhel.Distribution) *rhel.ImageType {
[]string{"vpc"}, []string{"vpc"},
) )
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig(rd) it.DefaultImageConfig = defaultAzureImageConfig(rd)
@ -51,7 +51,7 @@ func mkAzureInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = defaultAzureImageConfig(rd) it.DefaultImageConfig = defaultAzureImageConfig(rd)
@ -75,7 +75,7 @@ func mkAzureSapInternalImgType(rd *rhel.Distribution) *rhel.ImageType {
) )
it.Compression = "xz" it.Compression = "xz"
it.KernelOptions = defaultAzureKernelOptions it.KernelOptions = defaultAzureKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = sapAzureImageConfig(rd) it.DefaultImageConfig = sapAzureImageConfig(rd)
@ -413,7 +413,9 @@ func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, b
// IMAGE CONFIG // IMAGE CONFIG
// use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT // 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" func defaultAzureKernelOptions() []string {
return []string{"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 // 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
func defaultAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig { func defaultAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig {

View file

@ -110,9 +110,9 @@ func mkEdgeRawImgType(d *rhel.Distribution) *rhel.ImageType {
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal") it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
} }
it.KernelOptions = "modprobe.blacklist=vc4" it.KernelOptions = []string{"modprobe.blacklist=vc4"}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() { if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip" it.KernelOptions = append(it.KernelOptions, "rw", "coreos.no_persist_ip")
} }
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
@ -213,9 +213,9 @@ func mkEdgeSimplifiedInstallerImgType(d *rhel.Distribution) *rhel.ImageType {
it.BasePartitionTables = edgeBasePartitionTables it.BasePartitionTables = edgeBasePartitionTables
it.UnsupportedPartitioningModes = []disk.PartitioningMode{disk.RawPartitioningMode} it.UnsupportedPartitioningModes = []disk.PartitioningMode{disk.RawPartitioningMode}
it.KernelOptions = "modprobe.blacklist=vc4" it.KernelOptions = []string{"modprobe.blacklist=vc4"}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() { if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip" it.KernelOptions = append(it.KernelOptions, "rw", "coreos.no_persist_ip")
} }
return it return it
@ -245,9 +245,9 @@ func mkEdgeAMIImgType(d *rhel.Distribution) *rhel.ImageType {
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal") it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
} }
it.KernelOptions = amiKernelOptions + " modprobe.blacklist=vc4" it.KernelOptions = append(amiKernelOptions(), "modprobe.blacklist=vc4")
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() { if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip" it.KernelOptions = append(it.KernelOptions, "rw", "coreos.no_persist_ip")
} }
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
@ -284,9 +284,9 @@ func mkEdgeVsphereImgType(d *rhel.Distribution) *rhel.ImageType {
it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal") it.DefaultImageConfig.IgnitionPlatform = common.ToPtr("metal")
} }
it.KernelOptions = "modprobe.blacklist=vc4" it.KernelOptions = []string{"modprobe.blacklist=vc4"}
if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() { if common.VersionGreaterThanOrEqual(d.OsVersion(), "9.2") || !d.IsRHEL() {
it.KernelOptions += " rw coreos.no_persist_ip" it.KernelOptions = append(it.KernelOptions, "rw", "coreos.no_persist_ip")
} }
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
@ -320,7 +320,7 @@ func mkMinimalrawImgType() *rhel.ImageType {
// requires a kickstart file in the root directory. // requires a kickstart file in the root directory.
Files: []*fsnode.File{initialSetupKickstart()}, Files: []*fsnode.File{initialSetupKickstart()},
} }
it.KernelOptions = "ro" it.KernelOptions = []string{"ro"}
it.DefaultSize = 2 * datasizes.GibiByte it.DefaultSize = 2 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = minimalrawPartitionTables it.BasePartitionTables = minimalrawPartitionTables

View file

@ -9,7 +9,9 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
const gceKernelOptions = "net.ifnames=0 biosdevname=0 scsi_mod.use_blk_mq=Y console=ttyS0,38400n8d" func gceKernelOptions() []string {
return []string{"net.ifnames=0", "biosdevname=0", "scsi_mod.use_blk_mq=Y", "console=ttyS0,38400n8d"}
}
func mkGCEImageType() *rhel.ImageType { func mkGCEImageType() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -29,7 +31,7 @@ func mkGCEImageType() *rhel.ImageType {
// The configuration for non-RHUI images does not touch the RHSM configuration at all. // The configuration for non-RHUI images does not touch the RHSM configuration at all.
// https://issues.redhat.com/browse/COMPOSER-2157 // https://issues.redhat.com/browse/COMPOSER-2157
it.DefaultImageConfig = baseGCEImageConfig() it.DefaultImageConfig = baseGCEImageConfig()
it.KernelOptions = gceKernelOptions it.KernelOptions = gceKernelOptions()
it.DefaultSize = 20 * datasizes.GibiByte it.DefaultSize = 20 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only // TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only

View file

@ -24,7 +24,7 @@ func mkQcow2ImgType(d *rhel.Distribution) *rhel.ImageType {
) )
it.DefaultImageConfig = qcowImageConfig(d) it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check", "net.ifnames=0"}
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -47,7 +47,7 @@ func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
) )
it.DefaultImageConfig = qcowImageConfig(d) it.DefaultImageConfig = qcowImageConfig(d)
it.KernelOptions = "console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0" it.KernelOptions = []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check", "net.ifnames=0"}
it.DefaultSize = 10 * datasizes.GibiByte it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -72,7 +72,7 @@ func mkOpenstackImgType() *rhel.ImageType {
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"), Locale: common.ToPtr("en_US.UTF-8"),
} }
it.KernelOptions = "ro net.ifnames=0" it.KernelOptions = []string{"ro", "net.ifnames=0"}
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.Bootable = true it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables

View file

@ -14,7 +14,7 @@ func mkWSLImgType() *rhel.ImageType {
"disk.tar.gz", "disk.tar.gz",
"application/x-tar", "application/x-tar",
map[string]rhel.PackageSetFunc{ map[string]rhel.PackageSetFunc{
rhel.OSPkgsKey: ubiCommonPackageSet, rhel.OSPkgsKey: wslPackageSet,
}, },
rhel.TarImage, rhel.TarImage,
[]string{"build"}, []string{"build"},
@ -23,6 +23,20 @@ func mkWSLImgType() *rhel.ImageType {
) )
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "99_wsl.cfg",
Config: osbuild.CloudInitConfigFile{
DatasourceList: []string{
"WSL",
"None",
},
Network: &osbuild.CloudInitConfigNetwork{
Config: "disabled",
},
},
},
},
Locale: common.ToPtr("en_US.UTF-8"), Locale: common.ToPtr("en_US.UTF-8"),
NoSElinux: common.ToPtr(true), NoSElinux: common.ToPtr(true),
WSLConfig: &osbuild.WSLConfStageOptions{ WSLConfig: &osbuild.WSLConfStageOptions{
@ -35,7 +49,7 @@ func mkWSLImgType() *rhel.ImageType {
return it return it
} }
func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet { func wslPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
ps := rpmmd.PackageSet{ ps := rpmmd.PackageSet{
Include: []string{ Include: []string{
"alternatives", "alternatives",
@ -43,6 +57,7 @@ func ubiCommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet {
"basesystem", "basesystem",
"bash", "bash",
"ca-certificates", "ca-certificates",
"cloud-init",
"coreutils-single", "coreutils-single",
"crypto-policies-scripts", "crypto-policies-scripts",
"curl-minimal", "curl-minimal",

View file

@ -8,7 +8,9 @@ import (
"github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/rpmmd"
) )
const vmdkKernelOptions = "ro net.ifnames=0" func vmdkKernelOptions() []string {
return []string{"ro", "net.ifnames=0"}
}
func mkVMDKImgType() *rhel.ImageType { func mkVMDKImgType() *rhel.ImageType {
it := rhel.NewImageType( it := rhel.NewImageType(
@ -27,7 +29,7 @@ func mkVMDKImgType() *rhel.ImageType {
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"), Locale: common.ToPtr("en_US.UTF-8"),
} }
it.KernelOptions = vmdkKernelOptions it.KernelOptions = vmdkKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables
@ -52,7 +54,7 @@ func mkOVAImgType() *rhel.ImageType {
it.DefaultImageConfig = &distro.ImageConfig{ it.DefaultImageConfig = &distro.ImageConfig{
Locale: common.ToPtr("en_US.UTF-8"), Locale: common.ToPtr("en_US.UTF-8"),
} }
it.KernelOptions = vmdkKernelOptions it.KernelOptions = vmdkKernelOptions()
it.Bootable = true it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables it.BasePartitionTables = defaultBasePartitionTables

View file

@ -24,6 +24,7 @@ type AnacondaContainerInstaller struct {
RootfsCompression string RootfsCompression string
RootfsType manifest.RootfsType RootfsType manifest.RootfsType
ISOBoot manifest.ISOBootType
ISOLabel string ISOLabel string
Product string Product string
@ -131,9 +132,6 @@ func (img *AnacondaContainerInstaller) InstantiateManifest(m *manifest.Manifest,
bootTreePipeline.KernelOpts = append(bootTreePipeline.KernelOpts, "fips=1") bootTreePipeline.KernelOpts = append(bootTreePipeline.KernelOpts, "fips=1")
} }
// enable ISOLinux on x86_64 only
isoLinuxEnabled := img.Platform.GetArch() == arch.ARCH_X86_64
isoTreePipeline := manifest.NewAnacondaInstallerISOTree(buildPipeline, anacondaPipeline, rootfsImagePipeline, bootTreePipeline) isoTreePipeline := manifest.NewAnacondaInstallerISOTree(buildPipeline, anacondaPipeline, rootfsImagePipeline, bootTreePipeline)
isoTreePipeline.PartitionTable = efiBootPartitionTable(rng) isoTreePipeline.PartitionTable = efiBootPartitionTable(rng)
isoTreePipeline.Release = img.Release isoTreePipeline.Release = img.Release
@ -147,14 +145,14 @@ func (img *AnacondaContainerInstaller) InstantiateManifest(m *manifest.Manifest,
isoTreePipeline.PayloadRemoveSignatures = img.ContainerRemoveSignatures isoTreePipeline.PayloadRemoveSignatures = img.ContainerRemoveSignatures
isoTreePipeline.ContainerSource = &img.ContainerSource isoTreePipeline.ContainerSource = &img.ContainerSource
isoTreePipeline.ISOLinux = isoLinuxEnabled isoTreePipeline.ISOBoot = img.ISOBoot
if img.FIPS { if img.FIPS {
isoTreePipeline.KernelOpts = append(isoTreePipeline.KernelOpts, "fips=1") isoTreePipeline.KernelOpts = append(isoTreePipeline.KernelOpts, "fips=1")
} }
isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel) isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel)
isoPipeline.SetFilename(img.Filename) isoPipeline.SetFilename(img.Filename)
isoPipeline.ISOLinux = isoLinuxEnabled isoPipeline.ISOBoot = img.ISOBoot
artifact := isoPipeline.Export() artifact := isoPipeline.Export()
return artifact, nil return artifact, nil

View file

@ -25,6 +25,7 @@ type AnacondaLiveInstaller struct {
RootfsCompression string RootfsCompression string
RootfsType manifest.RootfsType RootfsType manifest.RootfsType
ISOBoot manifest.ISOBootType
ISOLabel string ISOLabel string
Product string Product string
@ -105,22 +106,19 @@ func (img *AnacondaLiveInstaller) InstantiateManifest(m *manifest.Manifest,
bootTreePipeline.KernelOpts = kernelOpts bootTreePipeline.KernelOpts = kernelOpts
// enable ISOLinux on x86_64 only
isoLinuxEnabled := img.Platform.GetArch() == arch.ARCH_X86_64
isoTreePipeline := manifest.NewAnacondaInstallerISOTree(buildPipeline, livePipeline, rootfsImagePipeline, bootTreePipeline) isoTreePipeline := manifest.NewAnacondaInstallerISOTree(buildPipeline, livePipeline, rootfsImagePipeline, bootTreePipeline)
isoTreePipeline.PartitionTable = efiBootPartitionTable(rng) isoTreePipeline.PartitionTable = efiBootPartitionTable(rng)
isoTreePipeline.Release = img.Release isoTreePipeline.Release = img.Release
isoTreePipeline.KernelOpts = kernelOpts isoTreePipeline.KernelOpts = kernelOpts
isoTreePipeline.ISOLinux = isoLinuxEnabled isoTreePipeline.ISOBoot = img.ISOBoot
isoTreePipeline.RootfsCompression = img.RootfsCompression isoTreePipeline.RootfsCompression = img.RootfsCompression
isoTreePipeline.RootfsType = img.RootfsType isoTreePipeline.RootfsType = img.RootfsType
isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel) isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel)
isoPipeline.SetFilename(img.Filename) isoPipeline.SetFilename(img.Filename)
isoPipeline.ISOLinux = isoLinuxEnabled isoPipeline.ISOBoot = img.ISOBoot
artifact := isoPipeline.Export() artifact := isoPipeline.Export()

View file

@ -30,6 +30,7 @@ type AnacondaOSTreeInstaller struct {
RootfsCompression string RootfsCompression string
RootfsType manifest.RootfsType RootfsType manifest.RootfsType
ISOBoot manifest.ISOBootType
ISOLabel string ISOLabel string
Product string Product string
@ -133,9 +134,6 @@ func (img *AnacondaOSTreeInstaller) InstantiateManifest(m *manifest.Manifest,
bootTreePipeline.KernelOpts = append(bootTreePipeline.KernelOpts, "fips=1") bootTreePipeline.KernelOpts = append(bootTreePipeline.KernelOpts, "fips=1")
} }
// enable ISOLinux on x86_64 only
isoLinuxEnabled := img.Platform.GetArch() == arch.ARCH_X86_64
var subscriptionPipeline *manifest.Subscription var subscriptionPipeline *manifest.Subscription
if img.Subscription != nil { if img.Subscription != nil {
// pipeline that will create subscription service and key file to be copied out // pipeline that will create subscription service and key file to be copied out
@ -152,7 +150,7 @@ func (img *AnacondaOSTreeInstaller) InstantiateManifest(m *manifest.Manifest,
isoTreePipeline.PayloadPath = "/ostree/repo" isoTreePipeline.PayloadPath = "/ostree/repo"
isoTreePipeline.OSTreeCommitSource = &img.Commit isoTreePipeline.OSTreeCommitSource = &img.Commit
isoTreePipeline.ISOLinux = isoLinuxEnabled isoTreePipeline.ISOBoot = img.ISOBoot
if img.FIPS { if img.FIPS {
isoTreePipeline.KernelOpts = append(isoTreePipeline.KernelOpts, "fips=1") isoTreePipeline.KernelOpts = append(isoTreePipeline.KernelOpts, "fips=1")
} }
@ -160,7 +158,7 @@ func (img *AnacondaOSTreeInstaller) InstantiateManifest(m *manifest.Manifest,
isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel) isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel)
isoPipeline.SetFilename(img.Filename) isoPipeline.SetFilename(img.Filename)
isoPipeline.ISOLinux = isoLinuxEnabled isoPipeline.ISOBoot = img.ISOBoot
artifact := isoPipeline.Export() artifact := isoPipeline.Export()
return artifact, nil return artifact, nil

View file

@ -58,6 +58,7 @@ type AnacondaTarInstaller struct {
RootfsCompression string RootfsCompression string
RootfsType manifest.RootfsType RootfsType manifest.RootfsType
ISOBoot manifest.ISOBootType
ISOLabel string ISOLabel string
Product string Product string
@ -184,9 +185,6 @@ func (img *AnacondaTarInstaller) InstantiateManifest(m *manifest.Manifest,
osPipeline.Environment = img.Environment osPipeline.Environment = img.Environment
osPipeline.Workload = img.Workload osPipeline.Workload = img.Workload
// enable ISOLinux on x86_64 only
isoLinuxEnabled := img.Platform.GetArch() == arch.ARCH_X86_64
isoTreePipeline := manifest.NewAnacondaInstallerISOTree(buildPipeline, anacondaPipeline, rootfsImagePipeline, bootTreePipeline) isoTreePipeline := manifest.NewAnacondaInstallerISOTree(buildPipeline, anacondaPipeline, rootfsImagePipeline, bootTreePipeline)
// TODO: the partition table is required - make it a ctor arg or set a default one in the pipeline // TODO: the partition table is required - make it a ctor arg or set a default one in the pipeline
isoTreePipeline.PartitionTable = efiBootPartitionTable(rng) isoTreePipeline.PartitionTable = efiBootPartitionTable(rng)
@ -206,11 +204,11 @@ func (img *AnacondaTarInstaller) InstantiateManifest(m *manifest.Manifest,
isoTreePipeline.KernelOpts = append(isoTreePipeline.KernelOpts, "fips=1") isoTreePipeline.KernelOpts = append(isoTreePipeline.KernelOpts, "fips=1")
} }
isoTreePipeline.ISOLinux = isoLinuxEnabled isoTreePipeline.ISOBoot = img.ISOBoot
isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel) isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, img.ISOLabel)
isoPipeline.SetFilename(img.Filename) isoPipeline.SetFilename(img.Filename)
isoPipeline.ISOLinux = isoLinuxEnabled isoPipeline.ISOBoot = img.ISOBoot
artifact := isoPipeline.Export() artifact := isoPipeline.Export()

View file

@ -68,6 +68,7 @@ func (img *BootcDiskImage) InstantiateManifestFromContainers(m *manifest.Manifes
rawImage.Directories = img.Directories rawImage.Directories = img.Directories
rawImage.KernelOptionsAppend = img.KernelOptionsAppend rawImage.KernelOptionsAppend = img.KernelOptionsAppend
rawImage.SELinux = img.SELinux rawImage.SELinux = img.SELinux
rawImage.MountUnits = true // always use mount units for bootc disk images
// In BIB, we export multiple images from the same pipeline so we use the // 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 // filename as the basename for each export and set the extensions based on

View file

@ -156,7 +156,9 @@ func (img *OSTreeSimplifiedInstaller) InstantiateManifest(m *manifest.Manifest,
isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, isoLabel) isoPipeline := manifest.NewISO(buildPipeline, isoTreePipeline, isoLabel)
isoPipeline.SetFilename(img.Filename) isoPipeline.SetFilename(img.Filename)
isoPipeline.ISOLinux = isoLinuxEnabled if isoLinuxEnabled {
isoPipeline.ISOBoot = manifest.SyslinuxISOBoot
}
artifact := isoPipeline.Export() artifact := isoPipeline.Export()
return artifact, nil return artifact, nil

View file

@ -25,6 +25,15 @@ const ( // Rootfs type enum
ErofsRootfs // Create a plain erofs rootfs ErofsRootfs // Create a plain erofs rootfs
) )
type ISOBootType uint64
// These constants are used by the ISO images to control the type of bootable iso
const ( // ISOBoot type enum
Grub2UEFIOnlyISOBoot ISOBootType = iota // Only boot with grub2 UEFI
SyslinuxISOBoot // Boot with grub2 UEFI and syslinux/isolinux BIOS
Grub2ISOBoot // Boot with grub2 UEFI and grub2 BIOS
)
// An AnacondaInstallerISOTree represents a tree containing the anaconda installer, // An AnacondaInstallerISOTree represents a tree containing the anaconda installer,
// configuration in terms of a kickstart file, as well as an embedded // configuration in terms of a kickstart file, as well as an embedded
// payload to be installed, this payload can either be an ostree // payload to be installed, this payload can either be an ostree
@ -62,8 +71,8 @@ type AnacondaInstallerISOTree struct {
// Kernel options for the ISO image // Kernel options for the ISO image
KernelOpts []string KernelOpts []string
// Enable ISOLinux stage // ISOBoot selects the type of boot support on the iso
ISOLinux bool ISOBoot ISOBootType
Kickstart *kickstart.Options Kickstart *kickstart.Options
@ -145,6 +154,11 @@ func (p *AnacondaInstallerISOTree) getBuildPackages(_ Distro) []string {
default: default:
} }
if p.ISOBoot == Grub2ISOBoot {
// Needed for the i386-pc directory of modules needed by grub2 BIOS booting
packages = append(packages, "grub2-pc-modules")
}
if p.OSTreeCommitSource != nil { if p.OSTreeCommitSource != nil {
packages = append(packages, "rpm-ostree") packages = append(packages, "rpm-ostree")
} }
@ -342,8 +356,8 @@ func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline {
default: default:
} }
if p.ISOLinux { if p.ISOBoot == SyslinuxISOBoot {
isoLinuxOptions := &osbuild.ISOLinuxStageOptions{ options := &osbuild.ISOLinuxStageOptions{
Product: osbuild.ISOLinuxProduct{ Product: osbuild.ISOLinuxProduct{
Name: p.anacondaPipeline.product, Name: p.anacondaPipeline.product,
Version: p.anacondaPipeline.version, Version: p.anacondaPipeline.version,
@ -354,8 +368,26 @@ func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline {
}, },
} }
isoLinuxStage := osbuild.NewISOLinuxStage(isoLinuxOptions, p.anacondaPipeline.Name()) stage := osbuild.NewISOLinuxStage(options, p.anacondaPipeline.Name())
pipeline.AddStage(isoLinuxStage) pipeline.AddStage(stage)
} else if p.ISOBoot == Grub2ISOBoot {
options := &osbuild.Grub2ISOLegacyStageOptions{
Product: osbuild.Product{
Name: p.anacondaPipeline.product,
Version: p.anacondaPipeline.version,
},
Kernel: osbuild.ISOKernel{
Dir: "/images/pxeboot",
Opts: kernelOpts,
},
ISOLabel: p.isoLabel,
}
stage := osbuild.NewGrub2ISOLegacyStage(options)
pipeline.AddStage(stage)
// Add a stage to create the eltorito.img file for grub2 BIOS boot support
pipeline.AddStage(osbuild.NewGrub2InstStage(osbuild.NewGrub2InstISO9660StageOption("images/eltorito.img", "/boot/grub2")))
} }
filename := "images/efiboot.img" filename := "images/efiboot.img"

View file

@ -0,0 +1,22 @@
package manifest
import (
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/osbuild"
)
// filesystemConfigStages generates either an org.osbuild.fstab stage or a
// collection of org.osbuild.systemd.unit.create stages for .mount and .swap
// units (and an org.osbuild.systemd stage to enable them) depending on the
// pipeline configuration.
func filesystemConfigStages(pt *disk.PartitionTable, mountUnits bool) ([]*osbuild.Stage, error) {
if mountUnits {
return osbuild.GenSystemdMountStages(pt)
} else {
opts, err := osbuild.NewFSTabStageOptions(pt)
if err != nil {
return nil, err
}
return []*osbuild.Stage{osbuild.NewFSTabStage(opts)}, nil
}
}

View file

@ -9,7 +9,7 @@ import (
// an existing ISOTreePipeline. // an existing ISOTreePipeline.
type ISO struct { type ISO struct {
Base Base
ISOLinux bool ISOBoot ISOBootType
filename string filename string
treePipeline Pipeline treePipeline Pipeline
@ -45,13 +45,13 @@ func (p *ISO) getBuildPackages(Distro) []string {
func (p *ISO) serialize() osbuild.Pipeline { func (p *ISO) serialize() osbuild.Pipeline {
pipeline := p.Base.serialize() pipeline := p.Base.serialize()
pipeline.AddStage(osbuild.NewXorrisofsStage(xorrisofsStageOptions(p.Filename(), p.isoLabel, p.ISOLinux), p.treePipeline.Name())) pipeline.AddStage(osbuild.NewXorrisofsStage(xorrisofsStageOptions(p.Filename(), p.isoLabel, p.ISOBoot), p.treePipeline.Name()))
pipeline.AddStage(osbuild.NewImplantisomd5Stage(&osbuild.Implantisomd5StageOptions{Filename: p.Filename()})) pipeline.AddStage(osbuild.NewImplantisomd5Stage(&osbuild.Implantisomd5StageOptions{Filename: p.Filename()}))
return pipeline return pipeline
} }
func xorrisofsStageOptions(filename, isolabel string, isolinux bool) *osbuild.XorrisofsStageOptions { func xorrisofsStageOptions(filename, isolabel string, isoboot ISOBootType) *osbuild.XorrisofsStageOptions {
options := &osbuild.XorrisofsStageOptions{ options := &osbuild.XorrisofsStageOptions{
Filename: filename, Filename: filename,
VolID: isolabel, VolID: isolabel,
@ -60,13 +60,20 @@ func xorrisofsStageOptions(filename, isolabel string, isolinux bool) *osbuild.Xo
ISOLevel: 3, ISOLevel: 3,
} }
if isolinux { if isoboot == SyslinuxISOBoot {
// Syslinux BIOS ISO creation
options.Boot = &osbuild.XorrisofsBoot{ options.Boot = &osbuild.XorrisofsBoot{
Image: "isolinux/isolinux.bin", Image: "isolinux/isolinux.bin",
Catalog: "isolinux/boot.cat", Catalog: "isolinux/boot.cat",
} }
options.IsohybridMBR = "/usr/share/syslinux/isohdpfx.bin" options.IsohybridMBR = "/usr/share/syslinux/isohdpfx.bin"
} else if isoboot == Grub2ISOBoot {
// grub2 BIOS ISO creation
options.Boot = &osbuild.XorrisofsBoot{
Image: "images/eltorito.img",
Catalog: "boot.cat",
}
options.Grub2MBR = "/usr/lib/grub/i386-pc/boot_hybrid.img"
} }
return options return options

View file

@ -157,6 +157,10 @@ type OSCustomizations struct {
// Determines if the machine id should be set to "uninitialized" which allows // Determines if the machine id should be set to "uninitialized" which allows
// "ConditionFirstBoot" to work in systemd // "ConditionFirstBoot" to work in systemd
MachineIdUninitialized bool MachineIdUninitialized bool
// MountUnits creates systemd .mount units to describe the filesystem
// instead of writing to /etc/fstab
MountUnits bool
} }
// OS represents the filesystem tree of the target image. This roughly // OS represents the filesystem tree of the target image. This roughly
@ -476,7 +480,9 @@ func (p *OS) serialize() osbuild.Pipeline {
} }
} }
pipeline.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: p.Language})) if p.Language != "" {
pipeline.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: p.Language}))
}
if p.Keyboard != nil { if p.Keyboard != nil {
keymapOptions := &osbuild.KeymapStageOptions{Keymap: *p.Keyboard} keymapOptions := &osbuild.KeymapStageOptions{Keymap: *p.Keyboard}
@ -489,7 +495,10 @@ func (p *OS) serialize() osbuild.Pipeline {
if p.Hostname != "" { if p.Hostname != "" {
pipeline.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: p.Hostname})) pipeline.AddStage(osbuild.NewHostnameStage(&osbuild.HostnameStageOptions{Hostname: p.Hostname}))
} }
pipeline.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: p.Timezone}))
if p.Timezone != "" {
pipeline.AddStage(osbuild.NewTimezoneStage(&osbuild.TimezoneStageOptions{Zone: p.Timezone}))
}
if len(p.NTPServers) > 0 { if len(p.NTPServers) > 0 {
chronyOptions := &osbuild.ChronyStageOptions{Servers: p.NTPServers} chronyOptions := &osbuild.ChronyStageOptions{Servers: p.NTPServers}
@ -633,7 +642,10 @@ func (p *OS) serialize() osbuild.Pipeline {
} }
if pt := p.PartitionTable; pt != nil { if pt := p.PartitionTable; pt != nil {
kernelOptions := osbuild.GenImageKernelOptions(p.PartitionTable) rootUUID, kernelOptions, err := osbuild.GenImageKernelOptions(p.PartitionTable, p.MountUnits)
if err != nil {
panic(err)
}
kernelOptions = append(kernelOptions, p.KernelOptionsAppend...) kernelOptions = append(kernelOptions, p.KernelOptionsAppend...)
if p.FIPS { if p.FIPS {
@ -644,15 +656,11 @@ func (p *OS) serialize() osbuild.Pipeline {
})) }))
} }
if !p.KernelOptionsBootloader || p.platform.GetArch() == arch.ARCH_S390X { fsCfgStages, err := filesystemConfigStages(pt, p.MountUnits)
pipeline = prependKernelCmdlineStage(pipeline, strings.Join(kernelOptions, " "), pt)
}
opts, err := osbuild.NewFSTabStageOptions(pt)
if err != nil { if err != nil {
panic(err) panic(err)
} }
pipeline.AddStage(osbuild.NewFSTabStage(opts)) pipeline.AddStages(fsCfgStages...)
var bootloader *osbuild.Stage var bootloader *osbuild.Stage
switch p.platform.GetArch() { switch p.platform.GetArch() {
@ -708,6 +716,10 @@ func (p *OS) serialize() osbuild.Pipeline {
} }
pipeline.AddStage(bootloader) pipeline.AddStage(bootloader)
if !p.KernelOptionsBootloader || p.platform.GetArch() == arch.ARCH_S390X {
pipeline = prependKernelCmdlineStage(pipeline, rootUUID, kernelOptions)
}
} }
if p.RHSMFacts != nil { if p.RHSMFacts != nil {
@ -890,13 +902,8 @@ func (p *OS) serialize() osbuild.Pipeline {
return pipeline return pipeline
} }
func prependKernelCmdlineStage(pipeline osbuild.Pipeline, kernelOptions string, pt *disk.PartitionTable) osbuild.Pipeline { func prependKernelCmdlineStage(pipeline osbuild.Pipeline, rootUUID string, kernelOptions []string) osbuild.Pipeline {
rootFs := pt.FindMountable("/") kernelStage := osbuild.NewKernelCmdlineStage(osbuild.NewKernelCmdlineStageOptions(rootUUID, strings.Join(kernelOptions, " ")))
if rootFs == nil {
panic("root filesystem must be defined for kernel-cmdline stage, this is a programming error")
}
rootFsUUID := rootFs.GetFSSpec().UUID
kernelStage := osbuild.NewKernelCmdlineStage(osbuild.NewKernelCmdlineStageOptions(rootFsUUID, kernelOptions))
pipeline.Stages = append([]*osbuild.Stage{kernelStage}, pipeline.Stages...) pipeline.Stages = append([]*osbuild.Stage{kernelStage}, pipeline.Stages...)
return pipeline return pipeline
} }

View file

@ -42,6 +42,10 @@ type OSTreeDeploymentCustomizations struct {
// Lock the root account in the deployment unless the user defined root // Lock the root account in the deployment unless the user defined root
// user options in the build configuration. // user options in the build configuration.
LockRoot bool LockRoot bool
// MountUnits creates systemd .mount units to describe the filesystem
// instead of writing to /etc/fstab
MountUnits bool
} }
// OSTreeDeployment represents the filesystem tree of a target image based // OSTreeDeployment represents the filesystem tree of a target image based
@ -289,7 +293,10 @@ func (p *OSTreeDeployment) serialize() osbuild.Pipeline {
}, },
}, },
})) }))
kernelOpts := osbuild.GenImageKernelOptions(p.PartitionTable) _, kernelOpts, err := osbuild.GenImageKernelOptions(p.PartitionTable, p.MountUnits)
if err != nil {
panic(err)
}
kernelOpts = append(kernelOpts, p.KernelOptionsAppend...) kernelOpts = append(kernelOpts, p.KernelOptionsAppend...)
if p.IgnitionPlatform != "" { if p.IgnitionPlatform != "" {
@ -329,13 +336,14 @@ func (p *OSTreeDeployment) serialize() osbuild.Pipeline {
configStage.MountOSTree(p.osName, ref, 0) configStage.MountOSTree(p.osName, ref, 0)
pipeline.AddStage(configStage) pipeline.AddStage(configStage)
fstabOptions, err := osbuild.NewFSTabStageOptions(p.PartitionTable) fsCfgStages, err := filesystemConfigStages(p.PartitionTable, p.MountUnits)
if err != nil { if err != nil {
panic(err) panic(err)
} }
fstabStage := osbuild.NewFSTabStage(fstabOptions) for _, stage := range fsCfgStages {
fstabStage.MountOSTree(p.osName, ref, 0) stage.MountOSTree(p.osName, ref, 0)
pipeline.AddStage(fstabStage) pipeline.AddStage(stage)
}
if len(p.Groups) > 0 { if len(p.Groups) > 0 {
grpStage := osbuild.GenGroupsStage(p.Groups) grpStage := osbuild.GenGroupsStage(p.Groups)

View file

@ -44,6 +44,10 @@ type RawBootcImage struct {
// SELinux policy, when set it enables the labeling of the tree with the // SELinux policy, when set it enables the labeling of the tree with the
// selected profile // selected profile
SELinux string SELinux string
// MountUnits creates systemd .mount units to describe the filesystem
// instead of writing to /etc/fstab
MountUnits bool
} }
func (p RawBootcImage) Filename() string { func (p RawBootcImage) Filename() string {
@ -168,17 +172,15 @@ func (p *RawBootcImage) serialize() osbuild.Pipeline {
mounts = append(mounts, *osbuild.NewOSTreeDeploymentMountDefault("ostree.deployment", osbuild.OSTreeMountSourceMount)) mounts = append(mounts, *osbuild.NewOSTreeDeploymentMountDefault("ostree.deployment", osbuild.OSTreeMountSourceMount))
mounts = append(mounts, *osbuild.NewBindMount("bind-ostree-deployment-to-tree", "mount://", "tree://")) mounts = append(mounts, *osbuild.NewBindMount("bind-ostree-deployment-to-tree", "mount://", "tree://"))
// we always include the fstab stage fsCfgStages, err := filesystemConfigStages(pt, p.MountUnits)
// XXX: see issue#756 - if we stop doing this, conditionally
// apply selinux again
fstabOpts, err := osbuild.NewFSTabStageOptions(pt)
if err != nil { if err != nil {
panic(err) panic(err)
} }
fstabStage := osbuild.NewFSTabStage(fstabOpts) for _, stage := range fsCfgStages {
fstabStage.Mounts = mounts stage.Mounts = mounts
fstabStage.Devices = devices stage.Devices = devices
pipeline.AddStage(fstabStage) pipeline.AddStage(stage)
}
// customize the image // customize the image
if len(p.Groups) > 0 { if len(p.Groups) > 0 {

View file

@ -30,6 +30,7 @@ type CloudInitConfigFile struct {
Datasource *CloudInitConfigDatasource `json:"datasource,omitempty"` Datasource *CloudInitConfigDatasource `json:"datasource,omitempty"`
DatasourceList []string `json:"datasource_list,omitempty"` DatasourceList []string `json:"datasource_list,omitempty"`
Output *CloudInitConfigOutput `json:"output,omitempty"` Output *CloudInitConfigOutput `json:"output,omitempty"`
Network *CloudInitConfigNetwork `json:"network,omitempty"`
} }
// Represents the 'system_info' configuration section // Represents the 'system_info' configuration section
@ -69,6 +70,10 @@ type CloudInitConfigDefaultUser struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
} }
type CloudInitConfigNetwork struct {
Config string `json:"config"`
}
func (c CloudInitConfigFile) validate() error { func (c CloudInitConfigFile) validate() error {
if c.SystemInfo == nil && c.Reporting == nil && c.Datasource == nil && len(c.DatasourceList) == 0 && c.Output == nil { if c.SystemInfo == nil && c.Reporting == nil && c.Datasource == nil && len(c.DatasourceList) == 0 && c.Output == nil {
return fmt.Errorf("at least one cloud-init configuration option must be specified") return fmt.Errorf("at least one cloud-init configuration option must be specified")
@ -89,7 +94,7 @@ func (c CloudInitConfigFile) validate() error {
} }
} }
allowedDatasources := []string{"Azure", "Ec2", "None"} allowedDatasources := []string{"Azure", "Ec2", "WSL", "NoCloud", "None"}
if len(c.DatasourceList) > 0 { if len(c.DatasourceList) > 0 {
for _, d := range c.DatasourceList { for _, d := range c.DatasourceList {
if !slices.Contains(allowedDatasources, d) { if !slices.Contains(allowedDatasources, d) {
@ -102,6 +107,11 @@ func (c CloudInitConfigFile) validate() error {
return err return err
} }
} }
if c.Network != nil {
if err := c.Network.validate(); err != nil {
return err
}
}
return nil return nil
} }
@ -160,3 +170,10 @@ func (du CloudInitConfigDefaultUser) validate() error {
} }
return nil return nil
} }
func (n CloudInitConfigNetwork) validate() error {
if n.Config != "disabled" {
return fmt.Errorf("Network config must be set to disabled if the network section is specified")
}
return nil
}

View file

@ -111,16 +111,42 @@ func GenImageFinishStages(pt *disk.PartitionTable, filename string) []*Stage {
return GenDeviceFinishStages(pt, filename) return GenDeviceFinishStages(pt, filename)
} }
func GenImageKernelOptions(pt *disk.PartitionTable) []string { func GenImageKernelOptions(pt *disk.PartitionTable, mountUnits bool) (string, []string, error) {
cmdline := make([]string, 0) cmdline := make([]string, 0)
rootFs := pt.FindMountable("/")
if rootFs == nil {
return "", nil, fmt.Errorf("root filesystem must be defined for kernel-cmdline stage, this is a programming error")
}
rootFsUUID := rootFs.GetFSSpec().UUID
// if /usr is on a separate filesystem, it needs to be defined in the
// kernel cmdline options for autodiscovery (when there's no /etc/fstab)
// see:
// - https://github.com/systemd/systemd/issues/24027
// - https://github.com/systemd/systemd/pull/33397
if usrFs := pt.FindMountable("/usr"); usrFs != nil && mountUnits {
fsOptions, err := usrFs.GetFSTabOptions()
if err != nil {
panic(fmt.Sprintf("error getting filesystem options for /usr mountpoint: %s", err))
}
cmdline = append(
cmdline,
fmt.Sprintf("mount.usr=UUID=%s", usrFs.GetFSSpec().UUID),
fmt.Sprintf("mount.usrfstype=%s", usrFs.GetFSType()),
fmt.Sprintf("mount.usrflags=%s", fsOptions.MntOps),
)
}
genOptions := func(e disk.Entity, path []disk.Entity) error { genOptions := func(e disk.Entity, path []disk.Entity) error {
switch ent := e.(type) { switch ent := e.(type) {
case *disk.LUKSContainer: case *disk.LUKSContainer:
karg := "luks.uuid=" + ent.UUID karg := "luks.uuid=" + ent.UUID
cmdline = append(cmdline, karg) cmdline = append(cmdline, karg)
case *disk.BtrfsSubvolume: case *disk.BtrfsSubvolume:
if ent.Mountpoint == "/" { if ent.Mountpoint == "/" && !mountUnits {
// if we're using mount units, the rootflags will be added
// separately (below)
karg := "rootflags=subvol=" + ent.Name karg := "rootflags=subvol=" + ent.Name
cmdline = append(cmdline, karg) cmdline = append(cmdline, karg)
} }
@ -128,6 +154,36 @@ func GenImageKernelOptions(pt *disk.PartitionTable) []string {
return nil return nil
} }
if mountUnits {
// The systemd-remount-fs service reads /etc/fstab to discover mount
// options for / and /usr. Without an /etc/fstab, / and /usr do not get
// remounted, which means if they are mounted read-only in the initrd,
// they will remain read-only. Flip the option if we're using only
// mount units, otherwise the filesystems will stay mounted 'ro'.
//
// See https://www.freedesktop.org/software/systemd/man/latest/systemd-remount-fs.service.html
for idx := range cmdline {
// TODO: consider removing 'ro' from static image configurations
// and adding either 'ro' or 'rw' here based on the value of
// mountUnits.
if cmdline[idx] == "ro" {
cmdline[idx] = "rw"
break
}
}
// set the rootflags for the same reason as above
fsOptions, err := rootFs.GetFSTabOptions()
if err != nil {
panic(fmt.Sprintf("error getting filesystem options for / mountpoint: %s", err))
}
// if the options are just 'defaults', there's no need to add rootflags
if fsOptions.MntOps != "defaults" {
cmdline = append(cmdline, fmt.Sprintf("rootflags=%s", fsOptions.MntOps))
}
}
_ = pt.ForEachEntity(genOptions) _ = pt.ForEachEntity(genOptions)
return cmdline return rootFsUUID, cmdline, nil
} }

View file

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/disk"
) )
@ -16,7 +17,7 @@ type Grub2InstStageOptions struct {
// Platform of the target system // Platform of the target system
Platform string `json:"platform"` Platform string `json:"platform"`
Location uint64 `json:"location"` Location *uint64 `json:"location,omitempty"`
// How to obtain the GRUB core image // How to obtain the GRUB core image
Core CoreMkImage `json:"core"` Core CoreMkImage `json:"core"`
@ -41,12 +42,12 @@ type CoreMkImage struct {
// Grub2 config on a specific partition, e.g. (,gpt3)/boot // Grub2 config on a specific partition, e.g. (,gpt3)/boot
type PrefixPartition struct { type PrefixPartition struct {
Type string `json:"type"` Type string `json:"type,omitempty"`
PartLabel string `json:"partlabel"` PartLabel string `json:"partlabel,omitempty"`
// The partition number, starting at zero // The partition number, starting at zero
Number uint `json:"number"` Number *uint `json:"number,omitempty"`
// Location of the grub config inside the partition // Location of the grub config inside the partition
Path string `json:"path"` Path string `json:"path"`
@ -81,15 +82,18 @@ func (options Grub2InstStageOptions) MarshalJSON() ([]byte, error) {
if !valueIn(g2options.Core.PartLabel, []string{"gpt", "dos"}) { if !valueIn(g2options.Core.PartLabel, []string{"gpt", "dos"}) {
return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for core.partlabel", g2options.Core.PartLabel) return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for core.partlabel", g2options.Core.PartLabel)
} }
if !valueIn(g2options.Core.Filesystem, []string{"ext4", "xfs", "btrfs"}) { if !valueIn(g2options.Core.Filesystem, []string{"ext4", "xfs", "btrfs", "iso9660"}) {
return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for core.filesystem", g2options.Core.Filesystem) return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for core.filesystem", g2options.Core.Filesystem)
} }
if g2options.Prefix.Type != "partition" { // iso9660 doesn't use Prefix.Type, Prefix.PartLabel, or Prefix.Number
return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for prefix.type", g2options.Prefix.Type) if g2options.Core.Filesystem != "iso9660" {
} if g2options.Prefix.Type != "partition" {
if !valueIn(g2options.Prefix.PartLabel, []string{"gpt", "dos"}) { return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for prefix.type", g2options.Prefix.Type)
return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for core.partlabel", g2options.Core.PartLabel) }
if !valueIn(g2options.Prefix.PartLabel, []string{"gpt", "dos"}) {
return nil, fmt.Errorf("org.osbuild.grub2.inst: invalid value %q for core.partlabel", g2options.Core.PartLabel)
}
} }
return json.Marshal(g2options) return json.Marshal(g2options)
@ -152,15 +156,32 @@ func NewGrub2InstStageOption(filename string, pt *disk.PartitionTable, platform
PartLabel: pt.Type.String(), PartLabel: pt.Type.String(),
// bootidx can't be negative after check with rootIdx above: // bootidx can't be negative after check with rootIdx above:
// nolint:gosec // nolint:gosec
Number: uint(bootIdx), Number: common.ToPtr(uint(bootIdx)),
Path: prefixPath, Path: prefixPath,
} }
return &Grub2InstStageOptions{ return &Grub2InstStageOptions{
Filename: filename, Filename: filename,
Platform: platform, Platform: platform,
Location: coreLocation, Location: common.ToPtr(coreLocation),
Core: core, Core: core,
Prefix: prefix, Prefix: prefix,
} }
} }
// NewGrub2InstISO9660StageOption returns the options needed to create the eltoritio.img
// for use on an iso
func NewGrub2InstISO9660StageOption(filename, prefix string) *Grub2InstStageOptions {
return &Grub2InstStageOptions{
Filename: filename,
Platform: "i386-pc",
Core: CoreMkImage{
Type: "mkimage",
PartLabel: "gpt",
Filesystem: "iso9660",
},
Prefix: PrefixPartition{
Path: prefix,
},
}
}

View file

@ -0,0 +1,50 @@
package osbuild
import "fmt"
const grub2isoLegacyStageType = "org.osbuild.grub2.iso.legacy"
type Grub2ISOLegacyStageOptions struct {
Product Product `json:"product"`
Kernel ISOKernel `json:"kernel"`
ISOLabel string `json:"isolabel"`
}
func (Grub2ISOLegacyStageOptions) isStageOptions() {}
func (o Grub2ISOLegacyStageOptions) validate() error {
// The stage schema marks product.name, product.version, kernel.dir, and
// isolabel as required. Empty values are technically valid according to
// the schema, but here we will consider them invalid.
if o.Product.Name == "" {
return fmt.Errorf("%s: product.name option is required", grub2isoLegacyStageType)
}
if o.Product.Version == "" {
return fmt.Errorf("%s: product.version option is required", grub2isoLegacyStageType)
}
if o.Kernel.Dir == "" {
return fmt.Errorf("%s: kernel.dir option is required", grub2isoLegacyStageType)
}
if o.ISOLabel == "" {
return fmt.Errorf("%s: isolabel option is required", grub2isoLegacyStageType)
}
return nil
}
// Assemble a file system tree for a bootable ISO
func NewGrub2ISOLegacyStage(options *Grub2ISOLegacyStageOptions) *Stage {
if err := options.validate(); err != nil {
panic(err)
}
return &Stage{
Type: grub2isoLegacyStageType,
Options: options,
}
}

View file

@ -1,5 +1,13 @@
package osbuild package osbuild
import (
"regexp"
"strings"
)
// vfat volume-id is a 32-bit hex number (mkfs.vfat(8))
const fatVolIDRegex = `^[a-fA-F0-9]{8}$`
type MkfsFATStageOptions struct { type MkfsFATStageOptions struct {
VolID string `json:"volid"` VolID string `json:"volid"`
Label string `json:"label,omitempty"` Label string `json:"label,omitempty"`
@ -15,3 +23,13 @@ func NewMkfsFATStage(options *MkfsFATStageOptions, devices map[string]Device) *S
Devices: devices, Devices: devices,
} }
} }
func isFATVolID(id string) bool {
// Internally, we generate FAT volume IDs with a dash (-) in the middle.
// This is also how they're represented by udev (in /dev/disk/by-uuid). The
// mkfs.vfat command doesn't accept dashes, which is why we remove them
// when generating the mkfs stage in mkfs_stage.go. This check removes all
// dashes to determine if the given id is a valid vfat volid.
volidre := regexp.MustCompile(fatVolIDRegex)
return volidre.MatchString(strings.Replace(id, "-", "", -1))
}

View file

@ -4,8 +4,15 @@ import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"regexp" "regexp"
"slices"
"strings"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/disk"
) )
const unitFilenameRegex = "^[\\w:.\\\\-]+[@]{0,1}[\\w:.\\\\-]*\\.(service|mount|socket|swap)$"
type SystemdServiceType string type SystemdServiceType string
type SystemdUnitPath string type SystemdUnitPath string
@ -51,6 +58,13 @@ type MountSection struct {
Options string `json:"Options,omitempty"` Options string `json:"Options,omitempty"`
} }
type SwapSection struct {
What string `json:"What"`
Priority *int `json:"Priority,omitempty"`
Options string `json:"Options,omitempty"`
TimeoutSec string `json:"TimeoutSec,omitempty"`
}
type SocketSection struct { type SocketSection struct {
Service string `json:"Service,omitempty"` Service string `json:"Service,omitempty"`
ListenStream string `json:"ListenStream,omitempty"` ListenStream string `json:"ListenStream,omitempty"`
@ -73,10 +87,11 @@ type InstallSection struct {
type SystemdUnit struct { type SystemdUnit struct {
Unit *UnitSection `json:"Unit"` Unit *UnitSection `json:"Unit"`
Service *ServiceSection `json:"Service"` Service *ServiceSection `json:"Service,omitempty"`
Mount *MountSection `json:"Mount,omitempty"` Mount *MountSection `json:"Mount,omitempty"`
Socket *SocketSection `json:"Socket,omitempty"` Socket *SocketSection `json:"Socket,omitempty"`
Install *InstallSection `json:"Install"` Swap *SwapSection `json:"Swap,omitempty"`
Install *InstallSection `json:"Install,omitempty"`
} }
type SystemdUnitCreateStageOptions struct { type SystemdUnitCreateStageOptions struct {
@ -102,6 +117,9 @@ func (o *SystemdUnitCreateStageOptions) validateService() error {
if o.Config.Socket != nil { if o.Config.Socket != nil {
return fmt.Errorf("systemd service unit %q contains invalid section Socket", o.Filename) return fmt.Errorf("systemd service unit %q contains invalid section Socket", o.Filename)
} }
if o.Config.Swap != nil {
return fmt.Errorf("systemd service unit %q contains invalid section Swap", o.Filename)
}
vre := regexp.MustCompile(envVarRegex) vre := regexp.MustCompile(envVarRegex)
if service := o.Config.Service; service != nil { if service := o.Config.Service; service != nil {
@ -119,12 +137,19 @@ func (o *SystemdUnitCreateStageOptions) validateMount() error {
if o.Config.Mount == nil { if o.Config.Mount == nil {
return fmt.Errorf("systemd mount unit %q requires a Mount section", o.Filename) return fmt.Errorf("systemd mount unit %q requires a Mount section", o.Filename)
} }
if o.Config.Swap != nil {
return fmt.Errorf("systemd mount unit %q contains invalid section Swap", o.Filename)
}
if o.Config.Service != nil { if o.Config.Service != nil {
return fmt.Errorf("systemd mount unit %q contains invalid section Service", o.Filename) return fmt.Errorf("systemd mount unit %q contains invalid section Service", o.Filename)
} }
if o.Config.Socket != nil { if o.Config.Socket != nil {
return fmt.Errorf("systemd mount unit %q contains invalid section Socket", o.Filename) return fmt.Errorf("systemd mount unit %q contains invalid section Socket", o.Filename)
} }
if o.Config.Swap != nil {
return fmt.Errorf("systemd mount unit %q contains invalid section Swap", o.Filename)
}
if o.Config.Mount.What == "" { if o.Config.Mount.What == "" {
return fmt.Errorf("What option for Mount section of systemd unit %q is required", o.Filename) return fmt.Errorf("What option for Mount section of systemd unit %q is required", o.Filename)
@ -136,24 +161,47 @@ func (o *SystemdUnitCreateStageOptions) validateMount() error {
return nil return nil
} }
func (o *SystemdUnitCreateStageOptions) validateSwap() error {
if o.Config.Swap == nil {
return fmt.Errorf("systemd swap unit %q requires a Swap section", o.Filename)
}
if o.Config.Mount != nil {
return fmt.Errorf("systemd swap unit %q contains invalid section Mount", o.Filename)
}
if o.Config.Service != nil {
return fmt.Errorf("systemd swap unit %q contains invalid section Service", o.Filename)
}
if o.Config.Socket != nil {
return fmt.Errorf("systemd swap unit %q contains invalid section Socket", o.Filename)
}
return nil
}
func (o *SystemdUnitCreateStageOptions) validateSocket() error { func (o *SystemdUnitCreateStageOptions) validateSocket() error {
if o.Config.Socket == nil { if o.Config.Socket == nil {
return fmt.Errorf("systemd socket unit %q requires a Socket section", o.Filename) return fmt.Errorf("systemd socket unit %q requires a Socket section", o.Filename)
} }
if o.Config.Mount != nil { if o.Config.Mount != nil {
return fmt.Errorf("systemd socket unit %q contains invalid section Mount", o.Filename) return fmt.Errorf("systemd socket unit %q contains invalid section Mount", o.Filename)
} }
if o.Config.Service != nil { if o.Config.Service != nil {
return fmt.Errorf("systemd socket unit %q contains invalid section Service", o.Filename) return fmt.Errorf("systemd socket unit %q contains invalid section Service", o.Filename)
} }
if o.Config.Swap != nil {
return fmt.Errorf("systemd socket unit %q contains invalid section Swap", o.Filename)
}
return nil return nil
} }
func (o *SystemdUnitCreateStageOptions) validate() error { func (o *SystemdUnitCreateStageOptions) validate() error {
fre := regexp.MustCompile(filenameRegex) fre := regexp.MustCompile(unitFilenameRegex)
if !fre.MatchString(o.Filename) { if !fre.MatchString(o.Filename) {
return fmt.Errorf("invalid filename %q for systemd unit: does not conform to schema (%s)", o.Filename, filenameRegex) return fmt.Errorf("invalid filename %q for systemd unit: does not conform to schema (%s)", o.Filename, unitFilenameRegex)
} }
switch filepath.Ext(o.Filename) { switch filepath.Ext(o.Filename) {
@ -161,10 +209,13 @@ func (o *SystemdUnitCreateStageOptions) validate() error {
return o.validateService() return o.validateService()
case ".mount": case ".mount":
return o.validateMount() return o.validateMount()
case ".swap":
return o.validateSwap()
case ".socket": case ".socket":
return o.validateSocket() return o.validateSocket()
default: default:
return fmt.Errorf("invalid filename %q for systemd unit: extension must be one of .service, .mount, or .socket", o.Filename) // this should be caught by the regex
return fmt.Errorf("invalid filename %q for systemd unit: extension must be one of .service, .mount, .swap, or .socket", o.Filename)
} }
} }
@ -177,3 +228,98 @@ func NewSystemdUnitCreateStage(options *SystemdUnitCreateStageOptions) *Stage {
Options: options, Options: options,
} }
} }
// GenSystemdMountStages generates a collection of
// org.osbuild.systemd.unit.create stages with options to create systemd mount
// units, one for each mountpoint in the partition table.
func GenSystemdMountStages(pt *disk.PartitionTable) ([]*Stage, error) {
mountStages := make([]*Stage, 0)
unitNames := make([]string, 0)
genOption := func(ent disk.FSTabEntity, path []disk.Entity) error {
fsSpec := ent.GetFSSpec()
fsOptions, err := ent.GetFSTabOptions()
if err != nil {
return err
}
options := &SystemdUnitCreateStageOptions{
Config: SystemdUnit{
Unit: &UnitSection{
// Adds the following dependencies for mount units (systemd.mount(5)):
// - Before=umount.target
// - Conflicts=umount.target
// - After=local-fs-pre.target
// - Before=local-fs.target
// and the following for swap units (systemd.swap(5)):
// - Before=umount.target
// - Conflicts=umount.target
DefaultDependencies: common.ToPtr(true),
},
Install: &InstallSection{
WantedBy: []string{"multi-user.target"},
},
},
}
device := filepath.Join("/dev/disk/by-uuid", strings.ToLower(fsSpec.UUID))
if isFATVolID(fsSpec.UUID) {
// vfat IDs aren't lowercased
device = filepath.Join("/dev/disk/by-uuid", fsSpec.UUID)
}
switch ent.GetFSType() {
case "swap":
options.Filename = fmt.Sprintf("%s.swap", pathEscape(device))
options.Config.Swap = &SwapSection{
What: device,
Options: fsOptions.MntOps,
}
default:
options.Filename = fmt.Sprintf("%s.mount", pathEscape(ent.GetFSFile()))
options.Config.Mount = &MountSection{
What: device,
Where: ent.GetFSFile(),
Type: ent.GetFSType(),
Options: fsOptions.MntOps,
}
}
mountStages = append(mountStages, NewSystemdUnitCreateStage(options))
unitNames = append(unitNames, options.Filename)
return nil
}
err := pt.ForEachFSTabEntity(genOption)
if err != nil {
return nil, err
}
// sort the entries by filename for stable ordering
slices.SortFunc(mountStages, func(a, b *Stage) int {
optsa := a.Options.(*SystemdUnitCreateStageOptions)
optsb := b.Options.(*SystemdUnitCreateStageOptions)
// this sorter is not guaranteed to be stable, but the unit Filenames
// are unique
switch {
case optsa.Filename < optsb.Filename:
return -1
case optsa.Filename > optsb.Filename:
return 1
}
panic(fmt.Sprintf("error sorting systemd unit mount stages: possible duplicate mount unit filenames: %q %q", optsa.Filename, optsb.Filename))
})
// sort the unit names for the systemd (enable) stage for stable ordering
slices.Sort(unitNames)
if len(unitNames) > 0 {
enableStage := NewSystemdStage(&SystemdStageOptions{
EnabledServices: unitNames,
})
mountStages = append(mountStages, enableStage)
}
return mountStages, nil
}

View file

@ -19,6 +19,11 @@ type XorrisofsStageOptions struct {
// The ISO 9660 version (limits data size and filenames; min: 1, max: 4) // The ISO 9660 version (limits data size and filenames; min: 1, max: 4)
ISOLevel int `json:"isolevel,omitempty"` ISOLevel int `json:"isolevel,omitempty"`
// Path to grub2 hybrid mbr boot image
// This will cause the created iso to use grub2 instead of syslinux/isolinux
// when booting on BIOS systems.
Grub2MBR string `json:"grub2mbr,omitempty"`
} }
type XorrisofsBoot struct { type XorrisofsBoot struct {

2
vendor/modules.txt vendored
View file

@ -1045,7 +1045,7 @@ github.com/oracle/oci-go-sdk/v54/identity
github.com/oracle/oci-go-sdk/v54/objectstorage github.com/oracle/oci-go-sdk/v54/objectstorage
github.com/oracle/oci-go-sdk/v54/objectstorage/transfer github.com/oracle/oci-go-sdk/v54/objectstorage/transfer
github.com/oracle/oci-go-sdk/v54/workrequests github.com/oracle/oci-go-sdk/v54/workrequests
# github.com/osbuild/images v0.123.0 # github.com/osbuild/images v0.124.0
## explicit; go 1.22.8 ## explicit; go 1.22.8
github.com/osbuild/images/data/dependencies github.com/osbuild/images/data/dependencies
github.com/osbuild/images/data/repositories github.com/osbuild/images/data/repositories