diff --git a/go.mod b/go.mod index 969136e52..ba9aa9550 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/labstack/gommon v0.4.2 github.com/openshift-online/ocm-sdk-go v0.1.438 github.com/oracle/oci-go-sdk/v54 v54.0.0 - github.com/osbuild/images v0.102.0 + github.com/osbuild/images v0.105.0 github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d github.com/osbuild/pulp-client v0.1.0 github.com/prometheus/client_golang v1.20.2 diff --git a/go.sum b/go.sum index 506763949..1bf75a4bb 100644 --- a/go.sum +++ b/go.sum @@ -534,8 +534,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/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/osbuild/images v0.102.0 h1:RQuxZM2w/afCa+Q8mrEG9S60Zbi4j9aSFoFUKFo/Tkk= -github.com/osbuild/images v0.102.0/go.mod h1:4bNmMQOVadIKVC1q8zsLO8tdEQFH90zIp+MQBQUnCiE= +github.com/osbuild/images v0.105.0 h1:KVFKmBhxDzpdZuzLfM84TpfNP40feC5DjRKn+OJcOZ8= +github.com/osbuild/images v0.105.0/go.mod h1:4bNmMQOVadIKVC1q8zsLO8tdEQFH90zIp+MQBQUnCiE= 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/pulp-client v0.1.0 h1:L0C4ezBJGTamN3BKdv+rKLuq/WxXJbsFwz/Hj7aEmJ8= diff --git a/vendor/github.com/osbuild/images/pkg/blueprint/ca_customizations.go b/vendor/github.com/osbuild/images/pkg/blueprint/ca_customizations.go deleted file mode 100644 index 560bac66f..000000000 --- a/vendor/github.com/osbuild/images/pkg/blueprint/ca_customizations.go +++ /dev/null @@ -1,5 +0,0 @@ -package blueprint - -type CACustomization struct { - PEMCerts []string `json:"pem_certs,omitempty" toml:"pem_certs,omitempty"` -} diff --git a/vendor/github.com/osbuild/images/pkg/blueprint/customizations.go b/vendor/github.com/osbuild/images/pkg/blueprint/customizations.go index b863e61bd..bcb1f9899 100644 --- a/vendor/github.com/osbuild/images/pkg/blueprint/customizations.go +++ b/vendor/github.com/osbuild/images/pkg/blueprint/customizations.go @@ -33,7 +33,7 @@ type Customizations struct { Installer *InstallerCustomization `json:"installer,omitempty" toml:"installer,omitempty"` RPM *RPMCustomization `json:"rpm,omitempty" toml:"rpm,omitempty"` RHSM *RHSMCustomization `json:"rhsm,omitempty" toml:"rhsm,omitempty"` - CACerts *CACustomization `json:"cacerts,omitempty" toml:"ca,omitempty"` + CACerts *CACustomization `json:"cacerts,omitempty" toml:"cacerts,omitempty"` } type IgnitionCustomization struct { @@ -144,6 +144,10 @@ type ContainerStorageCustomization struct { StoragePath *string `json:"destination-path,omitempty" toml:"destination-path,omitempty"` } +type CACustomization struct { + PEMCerts []string `json:"pem_certs,omitempty" toml:"pem_certs,omitempty"` +} + type CustomizationError struct { Message string } @@ -441,16 +445,14 @@ func (c *Customizations) GetRHSM() *RHSMCustomization { } func (c *Customizations) checkCACerts() error { - if c == nil { + if c == nil || c.CACerts == nil { return nil } - if c.CACerts != nil { - for _, bundle := range c.CACerts.PEMCerts { - _, err := cert.ParseCerts(bundle) - if err != nil { - return err - } + for _, bundle := range c.CACerts.PEMCerts { + _, err := cert.ParseCerts(bundle) + if err != nil { + return err } } diff --git a/vendor/github.com/osbuild/images/pkg/blueprint/disk_customizations.go b/vendor/github.com/osbuild/images/pkg/blueprint/disk_customizations.go index 0fd360bfb..769e96db3 100644 --- a/vendor/github.com/osbuild/images/pkg/blueprint/disk_customizations.go +++ b/vendor/github.com/osbuild/images/pkg/blueprint/disk_customizations.go @@ -75,6 +75,9 @@ type PartitionCustomization struct { // - Does not define a size. The size is defined by its container: a // partition ([PartitionCustomization]) or LVM logical volume // ([LVCustomization]). +// +// Setting the FSType to "swap" creates a swap area (and the Mountpoint must be +// empty). type FilesystemTypedCustomization struct { Mountpoint string `json:"mountpoint" toml:"mountpoint"` Label string `json:"label,omitempty" toml:"label,omitempty"` @@ -332,6 +335,7 @@ func (v *PartitionCustomization) UnmarshalTOML(data any) error { // - Plain filesystem types are valid for the partition type // - All non-empty properties are valid for the partition type (e.g. // LogicalVolumes is empty when the type is "plain" or "btrfs") +// - Filesystems with FSType set to "swap" do not specify a mountpoint. // // Note that in *addition* consumers should also call // ValidateLayoutConstraints() to validate that the policy for disk @@ -450,6 +454,14 @@ var validPlainFSTypes = []string{ } func (p *PartitionCustomization) validatePlain(mountpoints map[string]bool) error { + if p.FSType == "swap" { + // make sure the mountpoint is empty and return + if p.Mountpoint != "" { + return fmt.Errorf("mountpoint for swap partition must be empty (got %q)", p.Mountpoint) + } + return nil + } + if err := validateMountpoint(p.Mountpoint); err != nil { return err } @@ -490,6 +502,13 @@ func (p *PartitionCustomization) validateLVM(mountpoints, vgnames map[string]boo } lvnames[lv.Name] = true + if lv.FSType == "swap" { + // make sure the mountpoint is empty and return + if lv.Mountpoint != "" { + return fmt.Errorf("mountpoint for swap logical volume with name %q in volume group %q must be empty", lv.Name, p.Name) + } + return nil + } if err := validateMountpoint(lv.Mountpoint); err != nil { return fmt.Errorf("invalid logical volume customization: %w", err) } @@ -560,7 +579,9 @@ func CheckDiskMountpointsPolicy(partitioning *DiskCustomization, mountpointAllow mountpoints = append(mountpoints, part.Mountpoint) } for _, lv := range part.LogicalVolumes { - mountpoints = append(mountpoints, lv.Mountpoint) + if lv.Mountpoint != "" { + mountpoints = append(mountpoints, lv.Mountpoint) + } } for _, subvol := range part.Subvolumes { mountpoints = append(mountpoints, subvol.Mountpoint) diff --git a/vendor/github.com/osbuild/images/pkg/disk/btrfs.go b/vendor/github.com/osbuild/images/pkg/disk/btrfs.go index 80243bd4b..991cbc055 100644 --- a/vendor/github.com/osbuild/images/pkg/disk/btrfs.go +++ b/vendor/github.com/osbuild/images/pkg/disk/btrfs.go @@ -155,6 +155,10 @@ func (bs *BtrfsSubvolume) GetMountpoint() string { return bs.Mountpoint } +func (bs *BtrfsSubvolume) GetFSFile() string { + return bs.GetMountpoint() +} + func (bs *BtrfsSubvolume) GetFSType() string { return "btrfs" } diff --git a/vendor/github.com/osbuild/images/pkg/disk/disk.go b/vendor/github.com/osbuild/images/pkg/disk/disk.go index fdfd027cb..576687f06 100644 --- a/vendor/github.com/osbuild/images/pkg/disk/disk.go +++ b/vendor/github.com/osbuild/images/pkg/disk/disk.go @@ -56,6 +56,8 @@ const ( RootPartitionUUID = "6264D520-3FB9-423F-8AB8-7A0A8E3D3562" + SwapPartitionGUID = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F" + // Extended Boot Loader Partition XBootLDRPartitionGUID = "BC13C2FF-59E6-4262-A352-B275FD6F7172" @@ -70,6 +72,9 @@ const ( // Partition type ID for ESP on dos DosESPID = "ef00" + + // Partition type ID for swap + DosSwapID = "82" ) // pt type -> type -> ID mapping for convenience @@ -80,6 +85,7 @@ var idMap = map[PartitionTableType]map[string]string{ "data": DosLinuxTypeID, "esp": DosESPID, "lvm": DosLinuxTypeID, + "swap": DosSwapID, }, PT_GPT: { "bios": BIOSBootPartitionGUID, @@ -87,6 +93,7 @@ var idMap = map[PartitionTableType]map[string]string{ "data": FilesystemDataGUID, "esp": EFISystemPartitionGUID, "lvm": LVMPartitionGUID, + "swap": SwapPartitionGUID, }, } @@ -248,13 +255,21 @@ type Mountable interface { // GetMountPoint returns the path of the mount point. GetMountpoint() string - // GetFSType returns the file system type, e.g. 'xfs'. - GetFSType() string + FSTabEntity +} - // GetFSSpec returns the file system spec information. +// FSTabEntity describes any entity that can appear in the fstab file. +type FSTabEntity interface { + // FSSpec for the entity (UUID and Label); the first field of fstab(5). GetFSSpec() FSSpec - // GetFSTabOptions returns options for mounting the entity. + // The mount point (target) for a filesystem or "none" for swap areas; the second field of fstab(5). + GetFSFile() string + + // The type of the filesystem or swap for swap areas; the third field of fstab(5). + GetFSType() string + + // The mount options, freq, and passno for the entity; the fourth fifth, and sixth fields of fstab(5) respectively. GetFSTabOptions() (FSTabOptions, error) } diff --git a/vendor/github.com/osbuild/images/pkg/disk/filesystem.go b/vendor/github.com/osbuild/images/pkg/disk/filesystem.go index c5a3bd75b..fa4856ad1 100644 --- a/vendor/github.com/osbuild/images/pkg/disk/filesystem.go +++ b/vendor/github.com/osbuild/images/pkg/disk/filesystem.go @@ -55,6 +55,10 @@ func (fs *Filesystem) GetMountpoint() string { return fs.Mountpoint } +func (fs *Filesystem) GetFSFile() string { + return fs.GetMountpoint() +} + func (fs *Filesystem) GetFSType() string { if fs == nil { return "" diff --git a/vendor/github.com/osbuild/images/pkg/disk/lvm.go b/vendor/github.com/osbuild/images/pkg/disk/lvm.go index 54fc2523d..21bcc06cd 100644 --- a/vendor/github.com/osbuild/images/pkg/disk/lvm.go +++ b/vendor/github.com/osbuild/images/pkg/disk/lvm.go @@ -110,12 +110,15 @@ func (vg *LVMVolumeGroup) CreateLogicalVolume(lvName string, size uint64, payloa if lvName == "" { // generate a name based on the payload's mountpoint - mntble, ok := payload.(Mountable) - if !ok { - return nil, fmt.Errorf("could not create logical volume: no name provided and payload is not mountable") + switch ent := payload.(type) { + case Mountable: + lvName = ent.GetMountpoint() + case *Swap: + lvName = "swap" + default: + return nil, fmt.Errorf("could not create logical volume: no name provided and payload %T is not mountable or swap", payload) } - mountpoint := mntble.GetMountpoint() - autoName, err := vg.genLVName(mountpoint) + autoName, err := vg.genLVName(lvName) if err != nil { return nil, err } @@ -133,8 +136,7 @@ func (vg *LVMVolumeGroup) CreateLogicalVolume(lvName string, size uint64, payloa return &vg.LogicalVolumes[len(vg.LogicalVolumes)-1], nil } -func (vg *LVMVolumeGroup) AlignUp(size uint64) uint64 { - +func alignUp(size uint64) uint64 { if size%LVMDefaultExtentSize != 0 { size += LVMDefaultExtentSize - size%LVMDefaultExtentSize } @@ -142,6 +144,10 @@ func (vg *LVMVolumeGroup) AlignUp(size uint64) uint64 { return size } +func (vg *LVMVolumeGroup) AlignUp(size uint64) uint64 { + return alignUp(size) +} + func (vg *LVMVolumeGroup) MetadataSize() uint64 { if vg == nil { return 0 @@ -211,7 +217,7 @@ func (lv *LVMLogicalVolume) EnsureSize(s uint64) bool { panic("LVMLogicalVolume.EnsureSize: nil entity") } if s > lv.Size { - lv.Size = s + lv.Size = alignUp(s) return true } return false diff --git a/vendor/github.com/osbuild/images/pkg/disk/partition_table.go b/vendor/github.com/osbuild/images/pkg/disk/partition_table.go index 978b34d7f..1fc4199af 100644 --- a/vendor/github.com/osbuild/images/pkg/disk/partition_table.go +++ b/vendor/github.com/osbuild/images/pkg/disk/partition_table.go @@ -590,6 +590,32 @@ func (pt *PartitionTable) ForEachMountable(cb MountableCallback) error { return forEachMountable(pt, []Entity{pt}, cb) } +type FSTabEntityCallback func(mnt FSTabEntity, path []Entity) error + +func forEachFSTabEntity(c Container, path []Entity, cb FSTabEntityCallback) error { + for idx := uint(0); idx < c.GetItemCount(); idx++ { + child := c.GetChild(idx) + childPath := append(path, child) + var err error + switch ent := child.(type) { + case FSTabEntity: + err = cb(ent, childPath) + case Container: + err = forEachFSTabEntity(ent, childPath, cb) + } + if err != nil { + return err + } + } + return nil +} + +// ForEachFSTabEntity runs the provided callback function on each FSTabEntity +// in the PartitionTable. +func (pt *PartitionTable) ForEachFSTabEntity(cb FSTabEntityCallback) error { + return forEachFSTabEntity(pt, []Entity{pt}, cb) +} + // FindMountable returns the Mountable entity with the given mountpoint in the // PartitionTable. Returns nil if no Entity has the target as a Mountpoint. func (pt *PartitionTable) FindMountable(mountpoint string) Mountable { @@ -812,18 +838,23 @@ type partitionTableFeatures struct { FAT bool EXT4 bool LUKS bool + Swap bool } -// features examines all of the PartitionTable entities -// and returns a struct with flags set for each feature used +// features examines all of the PartitionTable entities and returns a struct +// with flags set for each feature used. The meaning of "feature" here is quite +// broad. Most disk Entity types are represented by a feature and the existence +// of at least one type in the partition table means the feature is +// represented. For Filesystem entities, there is a separate feature for each +// filesystem type func (pt *PartitionTable) features() partitionTableFeatures { var ptFeatures partitionTableFeatures introspectPT := func(e Entity, path []Entity) error { switch ent := e.(type) { - case *LVMLogicalVolume: + case *LVMVolumeGroup, *LVMLogicalVolume: ptFeatures.LVM = true - case *Btrfs: + case *Btrfs, *BtrfsSubvolume: ptFeatures.Btrfs = true case *Filesystem: switch ent.GetFSType() { @@ -836,8 +867,14 @@ func (pt *PartitionTable) features() partitionTableFeatures { case "ext4": ptFeatures.EXT4 = true } + case *Swap: + ptFeatures.Swap = true case *LUKSContainer: ptFeatures.LUKS = true + case *PartitionTable, *Partition: + // nothing to do + default: + panic(fmt.Errorf("unknown entity type %T", e)) } return nil } @@ -1254,25 +1291,43 @@ func addPlainPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz if err != nil { return fmt.Errorf("error creating partition with mountpoint %q: %w", partition.Mountpoint, err) } - // all user-defined partitions are data partitions except boot - typeName := "data" - if partition.Mountpoint == "/boot" { + + // all user-defined partitions are data partitions except boot and swap + var typeName string + switch { + case partition.Mountpoint == "/boot": typeName = "boot" + case fstype == "swap": + typeName = "swap" + default: + typeName = "data" } + partType, err := getPartitionTypeIDfor(pt.Type, typeName) if err != nil { return fmt.Errorf("error getting partition type ID for %q: %w", partition.Mountpoint, err) } - newpart := Partition{ - Type: partType, - Bootable: false, - Size: partition.MinSize, - Payload: &Filesystem{ + + var payload PayloadEntity + switch typeName { + case "swap": + payload = &Swap{ + Label: partition.Label, + FSTabOptions: "defaults", // TODO: add customization + } + default: + payload = &Filesystem{ Type: fstype, Label: partition.Label, Mountpoint: partition.Mountpoint, FSTabOptions: "defaults", // TODO: add customization - }, + } + } + + newpart := Partition{ + Type: partType, + Size: partition.MinSize, + Payload: payload, } pt.Partitions = append(pt.Partitions, newpart) return nil @@ -1310,11 +1365,21 @@ func addLVMPartition(pt *PartitionTable, partition blueprint.PartitionCustomizat if err != nil { return fmt.Errorf("error creating logical volume %q (%s): %w", lv.Name, lv.Mountpoint, err) } - newfs := &Filesystem{ - Type: fstype, - Label: lv.Label, - Mountpoint: lv.Mountpoint, - FSTabOptions: "defaults", // TODO: add customization + + var newfs PayloadEntity + switch fstype { + case "swap": + newfs = &Swap{ + Label: lv.Label, + FSTabOptions: "defaults", // TODO: add customization + } + default: + newfs = &Filesystem{ + Type: fstype, + Label: lv.Label, + Mountpoint: lv.Mountpoint, + FSTabOptions: "defaults", // TODO: add customization + } } if _, err := newvg.CreateLogicalVolume(lv.Name, lv.MinSize, newfs); err != nil { return fmt.Errorf("error creating logical volume %q (%s): %w", lv.Name, lv.Mountpoint, err) diff --git a/vendor/github.com/osbuild/images/pkg/disk/swap.go b/vendor/github.com/osbuild/images/pkg/disk/swap.go new file mode 100644 index 000000000..42c605063 --- /dev/null +++ b/vendor/github.com/osbuild/images/pkg/disk/swap.go @@ -0,0 +1,77 @@ +package disk + +import ( + "math/rand" + "reflect" + + "github.com/google/uuid" +) + +// Swap defines the payload for a swap partition. It's similar to a +// [Filesystem] but with fewer fields. It is a [PayloadEntity] and also a +// [FSTabEntity]. +type Swap struct { + UUID string + Label string + + // The fourth field of fstab(5); fs_mntops + FSTabOptions string +} + +func init() { + payloadEntityMap["swap"] = reflect.TypeOf(Swap{}) +} + +func (s *Swap) EntityName() string { + return "swap" +} + +func (s *Swap) Clone() Entity { + if s == nil { + return nil + } + + return &Swap{ + UUID: s.UUID, + Label: s.Label, + FSTabOptions: s.FSTabOptions, + } +} + +// For swap, the fs_file entry in the fstab is always "none". +func (s *Swap) GetFSFile() string { + return "none" +} + +// For swap, the fs_vfstype entry in the fstab is always "swap". +func (s *Swap) GetFSType() string { + return "swap" +} + +func (s *Swap) GetFSSpec() FSSpec { + if s == nil { + return FSSpec{} + } + return FSSpec{ + UUID: s.UUID, + Label: s.Label, + } +} + +// For swap, the Freq and PassNo are always 0. +func (s *Swap) GetFSTabOptions() (FSTabOptions, error) { + if s == nil { + return FSTabOptions{}, nil + } + return FSTabOptions{ + MntOps: s.FSTabOptions, + Freq: 0, + PassNo: 0, + }, nil +} + +func (s *Swap) GenUUID(rng *rand.Rand) { + if s.UUID == "" { + s.UUID = uuid.Must(newRandomUUIDFromReader(rng)).String() + } +} diff --git a/vendor/github.com/osbuild/images/pkg/distro/fedora/imagetype.go b/vendor/github.com/osbuild/images/pkg/distro/fedora/imagetype.go index 8738158d1..6f2a52e03 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/fedora/imagetype.go +++ b/vendor/github.com/osbuild/images/pkg/distro/fedora/imagetype.go @@ -288,31 +288,36 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint, // checkOptions checks the validity and compatibility of options and customizations for the image type. // Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices). func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) { - customizations := bp.Customizations + var warnings []string + + if !t.rpmOstree && options.OSTree != nil { + return warnings, fmt.Errorf("OSTree is not supported for %q", t.Name()) + } + // we do not support embedding containers on ostree-derived images, only on commits themselves if len(bp.Containers) > 0 && t.rpmOstree && (t.name != "iot-commit" && t.name != "iot-container") { - return nil, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name) + return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name) } if options.OSTree != nil { if err := options.OSTree.Validate(); err != nil { - return nil, err + return warnings, err } } if t.bootISO && t.rpmOstree { // ostree-based ISOs require a URL from which to pull a payload commit if options.OSTree == nil || options.OSTree.URL == "" { - return nil, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.name) + return warnings, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.name) } } if t.name == "iot-raw-image" || t.name == "iot-qcow2-image" { allowed := []string{"User", "Group", "Directories", "Files", "Services", "FIPS"} if err := customizations.CheckAllowed(allowed...); err != nil { - return nil, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", ")) + return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", ")) } // TODO: consider additional checks, such as those in "edge-simplified-installer" in RHEL distros } @@ -323,16 +328,16 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp if t.name == "iot-simplified-installer" { allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS"} if err := customizations.CheckAllowed(allowed...); err != nil { - return nil, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", ")) + return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", ")) } if customizations.GetInstallationDevice() == "" { - return nil, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name) + return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name) } // FDO is optional, but when specified has some restrictions if customizations.GetFDO() != nil { if customizations.GetFDO().ManufacturingServerURL == "" { - return nil, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to when using FDO", t.name) + return warnings, fmt.Errorf("boot ISO image type %q requires specifying FDO.ManufacturingServerURL configuration to install to when using FDO", t.name) } var diunSet int if customizations.GetFDO().DiunPubKeyHash != "" { @@ -345,66 +350,69 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp diunSet++ } if diunSet != 1 { - return nil, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to when using FDO", t.name) + return warnings, fmt.Errorf("boot ISO image type %q requires specifying one of [FDO.DiunPubKeyHash,FDO.DiunPubKeyInsecure,FDO.DiunPubKeyRootCerts] configuration to install to when using FDO", t.name) } } // ignition is optional, we might be using FDO if customizations.GetIgnition() != nil { if customizations.GetIgnition().Embedded != nil && customizations.GetIgnition().FirstBoot != nil { - return nil, fmt.Errorf("both ignition embedded and firstboot configurations found") + return warnings, fmt.Errorf("both ignition embedded and firstboot configurations found") } if customizations.GetIgnition().FirstBoot != nil && customizations.GetIgnition().FirstBoot.ProvisioningURL == "" { - return nil, fmt.Errorf("ignition.firstboot requires a provisioning url") + return warnings, fmt.Errorf("ignition.firstboot requires a provisioning url") } } } else if t.name == "iot-installer" || t.name == "image-installer" { // "Installer" is actually not allowed for image-installer right now, but this is checked at the end allowed := []string{"User", "Group", "FIPS", "Installer", "Timezone", "Locale"} if err := customizations.CheckAllowed(allowed...); err != nil { - return nil, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", ")) + return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", ")) } } else if t.name == "live-installer" { allowed := []string{"Installer"} if err := customizations.CheckAllowed(allowed...); err != nil { - return nil, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name) + return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name) } } } if kernelOpts := customizations.GetKernel(); kernelOpts.Append != "" && t.rpmOstree { - return nil, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types") + return warnings, fmt.Errorf("kernel boot parameter customizations are not supported for ostree types") } mountpoints := customizations.GetFilesystems() partitioning, err := customizations.GetPartitioning() if err != nil { - return nil, err + return warnings, err } if (len(mountpoints) > 0 || partitioning != nil) && t.rpmOstree { - return nil, fmt.Errorf("Custom mountpoints and partitioning are not supported for ostree types") + return warnings, fmt.Errorf("Custom mountpoints and partitioning are not supported for ostree types") } if len(mountpoints) > 0 && partitioning != nil { - return nil, fmt.Errorf("partitioning customizations cannot be used with custom filesystems (mountpoints)") + return warnings, fmt.Errorf("partitioning customizations cannot be used with custom filesystems (mountpoints)") } if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil { - return nil, err + return warnings, err } if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil { + return warnings, err + } + if err := partitioning.ValidateLayoutConstraints(); err != nil { return nil, err } if osc := customizations.GetOpenSCAP(); osc != nil { supported := oscap.IsProfileAllowed(osc.ProfileID, oscapProfileAllowList) if !supported { - return nil, fmt.Errorf("OpenSCAP unsupported profile: %s", osc.ProfileID) + return warnings, fmt.Errorf("OpenSCAP unsupported profile: %s", osc.ProfileID) } if t.rpmOstree { - return nil, fmt.Errorf("OpenSCAP customizations are not supported for ostree types") + return warnings, fmt.Errorf("OpenSCAP customizations are not supported for ostree types") } if osc.ProfileID == "" { - return nil, fmt.Errorf("OpenSCAP profile cannot be empty") + return warnings, fmt.Errorf("OpenSCAP profile cannot be empty") } } @@ -414,7 +422,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp err = blueprint.ValidateDirFileCustomizations(dc, fc) if err != nil { - return nil, err + return warnings, err } dcp := policies.CustomDirectoriesPolicies @@ -427,33 +435,32 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp) if err != nil { - return nil, err + return warnings, err } err = blueprint.CheckFileCustomizationsPolicy(fc, fcp) if err != nil { - return nil, err + return warnings, err } // check if repository customizations are valid _, err = customizations.GetRepositories() if err != nil { - return nil, err + return warnings, err } if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() { - w := fmt.Sprintln(common.FIPSEnabledImageWarning) - return []string{w}, nil + warnings = append(warnings, fmt.Sprintln(common.FIPSEnabledImageWarning)) } instCust, err := customizations.GetInstaller() if err != nil { - return nil, err + return warnings, err } if instCust != nil { // only supported by the Anaconda installer if slices.Index([]string{"iot-installer"}, t.name) == -1 { - return nil, fmt.Errorf("installer customizations are not supported for %q", t.Name()) + return warnings, fmt.Errorf("installer customizations are not supported for %q", t.Name()) } // NOTE: the image type check is redundant with the check above, but @@ -464,17 +471,9 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp instCust.Kickstart != nil && len(instCust.Kickstart.Contents) > 0 && (customizations.GetUsers() != nil || customizations.GetGroups() != nil) { - return nil, fmt.Errorf("iot-installer installer.kickstart.contents are not supported in combination with users or groups") + return warnings, fmt.Errorf("iot-installer installer.kickstart.contents are not supported in combination with users or groups") } } - diskc, err := customizations.GetPartitioning() - if err != nil { - return nil, err - } - if err := diskc.ValidateLayoutConstraints(); err != nil { - return nil, fmt.Errorf("cannot use disk customization: %w", err) - } - - return nil, nil + return warnings, nil } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/images.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/images.go index 806463b92..8aec7770e 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/images.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/images.go @@ -377,7 +377,7 @@ func DiskImage(workload workload.Workload, img.Workload = workload img.Compression = t.Compression // TODO: move generation into LiveImage - pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng) + pt, err := t.GetPartitionTable(customizations, options, rng) if err != nil { return nil, err } @@ -567,7 +567,7 @@ func EdgeRawImage(workload workload.Workload, img.OSName = "rhel-edge" // TODO: move generation into LiveImage - pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng) + pt, err := t.GetPartitionTable(customizations, options, rng) if err != nil { return nil, err } @@ -609,7 +609,7 @@ func EdgeSimplifiedInstallerImage(workload workload.Workload, rawImg.OSName = "rhel-edge" // TODO: move generation into LiveImage - pt, err := t.GetPartitionTable(customizations.GetFilesystems(), options, rng) + pt, err := t.GetPartitionTable(customizations, options, rng) if err != nil { return nil, err } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/imagetype.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/imagetype.go index 15b63f67c..b01cc4553 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/imagetype.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/imagetype.go @@ -39,6 +39,12 @@ const ( BlueprintPkgsKey = "blueprint" ) +// Default directory size minimums for all image types. +var requiredDirectorySizes = map[string]uint64{ + "/": 1 * datasizes.GiB, + "/usr": 2 * datasizes.GiB, +} + type ImageFunc func(workload workload.Workload, t *ImageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.SourceSpec, rng *rand.Rand) (image.ImageKind, error) type PackageSetFunc func(t *ImageType) rpmmd.PackageSet @@ -180,7 +186,7 @@ func (t *ImageType) BootMode() platform.BootMode { } func (t *ImageType) GetPartitionTable( - mountpoints []blueprint.FilesystemCustomization, + customizations *blueprint.Customizations, options distro.ImageOptions, rng *rand.Rand, ) (*disk.PartitionTable, error) { @@ -193,8 +199,29 @@ func (t *ImageType) GetPartitionTable( } imageSize := t.Size(options.Size) + partitioning, err := customizations.GetPartitioning() + if err != nil { + return nil, err + } + if partitioning != nil { + // Use the new custom partition table to create a PT fully based on the user's customizations. + // This overrides FilesystemCustomizations, but we should never have both defined. + if options.Size > 0 { + // user specified a size on the command line, so let's override the + // customization with the calculated/rounded imageSize + partitioning.MinSize = imageSize + } - return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, options.PartitioningMode, nil, rng) + partOptions := &disk.CustomPartitionTableOptions{ + PartitionTableType: basePartitionTable.Type, // PT type is not customizable, it is determined by the base PT for an image type or architecture + BootMode: t.BootMode(), + DefaultFSType: disk.FS_XFS, // default fs type for RHEL + RequiredMinSizes: requiredDirectorySizes, + } + return disk.NewCustomPartitionTable(partitioning, partOptions, rng) + } + + return disk.NewPartitionTable(&basePartitionTable, customizations.GetFilesystems(), imageSize, options.PartitioningMode, nil, rng) } func (t *ImageType) getDefaultImageConfig() *distro.ImageConfig { @@ -333,6 +360,10 @@ func (t *ImageType) Manifest(bp *blueprint.Blueprint, // checkOptions checks the validity and compatibility of options and customizations for the image type. // Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices). func (t *ImageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) { + if !t.RPMOSTree && options.OSTree != nil { + return nil, fmt.Errorf("OSTree is not supported for %q", t.Name()) + } + if t.arch.distro.CheckOptions != nil { return t.arch.distro.CheckOptions(t, bp, options) } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/ami.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/ami.go index 61b0c7613..2358791e9 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/ami.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/ami.go @@ -9,11 +9,162 @@ import ( "github.com/osbuild/images/pkg/rpmmd" ) +func mkAMIImgTypeX86_64() *rhel.ImageType { + it := rhel.NewImageType( + "ami", + "image.raw", + "application/octet-stream", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: ec2PackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image"}, + []string{"image"}, + ) + + it.KernelOptions = amiKernelOptions + it.Bootable = true + it.DefaultSize = 10 * datasizes.GibiByte + it.DefaultImageConfig = defaultEc2ImageConfigX86_64() + it.BasePartitionTables = defaultBasePartitionTables + + return it +} + +func mkAMIImgTypeAarch64() *rhel.ImageType { + it := rhel.NewImageType( + "ami", + "image.raw", + "application/octet-stream", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: ec2PackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image"}, + []string{"image"}, + ) + + it.KernelOptions = amiAarch64KernelOptions + it.Bootable = true + it.DefaultSize = 10 * datasizes.GibiByte + it.DefaultImageConfig = defaultEc2ImageConfig() + it.BasePartitionTables = defaultBasePartitionTables + + return it +} + +// RHEL internal-only x86_64 EC2 image type +func mkEc2ImgTypeX86_64() *rhel.ImageType { + it := rhel.NewImageType( + "ec2", + "image.raw.xz", + "application/xz", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: ec2PackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image", "xz"}, + []string{"xz"}, + ) + + it.Compression = "xz" + it.KernelOptions = amiKernelOptions + it.Bootable = true + it.DefaultSize = 10 * datasizes.GibiByte + it.DefaultImageConfig = defaultEc2ImageConfigX86_64() + it.BasePartitionTables = defaultBasePartitionTables + + return it +} + +// RHEL internal-only aarch64 EC2 image type +func mkEC2ImgTypeAarch64() *rhel.ImageType { + it := rhel.NewImageType( + "ec2", + "image.raw.xz", + "application/xz", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: ec2PackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image", "xz"}, + []string{"xz"}, + ) + + it.Compression = "xz" + it.KernelOptions = amiAarch64KernelOptions + it.Bootable = true + it.DefaultSize = 10 * datasizes.GibiByte + it.DefaultImageConfig = defaultEc2ImageConfig() + it.BasePartitionTables = defaultBasePartitionTables + + return it +} + +// RHEL internal-only x86_64 EC2 HA image type +func mkEc2HaImgTypeX86_64() *rhel.ImageType { + it := rhel.NewImageType( + "ec2-ha", + "image.raw.xz", + "application/xz", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: rhelEc2HaPackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image", "xz"}, + []string{"xz"}, + ) + + it.Compression = "xz" + it.KernelOptions = amiKernelOptions + it.Bootable = true + it.DefaultSize = 10 * datasizes.GibiByte + it.DefaultImageConfig = defaultEc2ImageConfigX86_64() + it.BasePartitionTables = defaultBasePartitionTables + + return it +} + +func mkEC2SapImgTypeX86_64(osVersion string) *rhel.ImageType { + it := rhel.NewImageType( + "ec2-sap", + "image.raw.xz", + "application/xz", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: rhelEc2SapPackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image", "xz"}, + []string{"xz"}, + ) + + it.Compression = "xz" + it.KernelOptions = amiSapKernelOptions + it.Bootable = true + it.DefaultSize = 10 * datasizes.GibiByte + it.DefaultImageConfig = sapImageConfig(osVersion).InheritFrom(defaultEc2ImageConfigX86_64()) + it.BasePartitionTables = defaultBasePartitionTables + + return it +} + +// IMAGE CONFIG + // TODO: move these to the EC2 environment -const amiKernelOptions = "console=tty0 console=ttyS0,115200n8 nvme_core.io_timeout=4294967295" +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) -func baseEc2ImageConfig() *distro.ImageConfig { +func defaultEc2ImageConfig() *distro.ImageConfig { return &distro.ImageConfig{ Locale: common.ToPtr("en_US.UTF-8"), Timezone: common.ToPtr("UTC"), @@ -120,32 +271,28 @@ func baseEc2ImageConfig() *distro.ImageConfig { } } -// Default AMI (custom image built by users) images config. -// The configuration does not touch the RHSM configuration at all. -// https://issues.redhat.com/browse/COMPOSER-2157 -func defaultAMIImageConfig() *distro.ImageConfig { - return baseEc2ImageConfig() +func appendEC2DracutX86_64(ic *distro.ImageConfig) *distro.ImageConfig { + ic.DracutConf = append(ic.DracutConf, + &osbuild.DracutConfStageOptions{ + Filename: "ec2.conf", + Config: osbuild.DracutConfigFile{ + AddDrivers: []string{ + "nvme", + "xen-blkfront", + }, + }, + }) + return ic } -// Default AMI x86_64 (custom image built by users) images config. -// The configuration does not touch the RHSM configuration at all. -// https://issues.redhat.com/browse/COMPOSER-2157 -func defaultAMIImageConfigX86_64() *distro.ImageConfig { - ic := defaultAMIImageConfig() +func defaultEc2ImageConfigX86_64() *distro.ImageConfig { + ic := defaultEc2ImageConfig() return appendEC2DracutX86_64(ic) } -// common ec2 image build package set -func ec2BuildPackageSet(t *rhel.ImageType) rpmmd.PackageSet { - return distroBuildPackageSet(t).Append( - rpmmd.PackageSet{ - Include: []string{ - "python3-pyyaml", - }, - }) -} +// PACKAGE SETS -func ec2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet { +func ec2PackageSet(t *rhel.ImageType) rpmmd.PackageSet { ps := rpmmd.PackageSet{ Include: []string{ "@core", @@ -202,63 +349,24 @@ func ec2CommonPackageSet(t *rhel.ImageType) rpmmd.PackageSet { return ps } -func mkAMIImgTypeX86_64() *rhel.ImageType { - it := rhel.NewImageType( - "ami", - "image.raw", - "application/octet-stream", - map[string]rhel.PackageSetFunc{ - rhel.OSPkgsKey: ec2CommonPackageSet, +// 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", }, - rhel.DiskImage, - []string{"build"}, - []string{"os", "image"}, - []string{"image"}, - ) - - it.KernelOptions = amiKernelOptions - it.Bootable = true - it.DefaultSize = 10 * datasizes.GibiByte - it.DefaultImageConfig = defaultAMIImageConfigX86_64() - it.BasePartitionTables = defaultBasePartitionTables - - return it + }) + return ec2HaPackageSet } -func mkAMIImgTypeAarch64() *rhel.ImageType { - it := rhel.NewImageType( - "ami", - "image.raw", - "application/octet-stream", - map[string]rhel.PackageSetFunc{ - rhel.BuildPkgsKey: ec2BuildPackageSet, - rhel.OSPkgsKey: ec2CommonPackageSet, +// 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 }, - rhel.DiskImage, - []string{"build"}, - []string{"os", "image"}, - []string{"image"}, - ) - - it.KernelOptions = "console=ttyS0,115200n8 console=tty0 nvme_core.io_timeout=4294967295 iommu.strict=0" - it.Bootable = true - it.DefaultSize = 10 * datasizes.GibiByte - it.DefaultImageConfig = defaultAMIImageConfig() - it.BasePartitionTables = defaultBasePartitionTables - - return it -} - -func appendEC2DracutX86_64(ic *distro.ImageConfig) *distro.ImageConfig { - ic.DracutConf = append(ic.DracutConf, - &osbuild.DracutConfStageOptions{ - Filename: "ec2.conf", - Config: osbuild.DracutConfigFile{ - AddDrivers: []string{ - "nvme", - "xen-blkfront", - }, - }, - }) - return ic + }.Append(ec2PackageSet(t)).Append(SapPackageSet(t)) } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/azure.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/azure.go index 610b1c5c2..7f1083288 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/azure.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/azure.go @@ -2,15 +2,17 @@ package rhel10 import ( "github.com/osbuild/images/internal/common" + "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/datasizes" + "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/distro" "github.com/osbuild/images/pkg/distro/rhel" "github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/rpmmd" ) -// Azure non-RHEL image type -func mkAzureImgType() *rhel.ImageType { +// Azure image type +func mkAzureImgType(rd *rhel.Distribution) *rhel.ImageType { it := rhel.NewImageType( "vhd", "disk.vhd", @@ -27,32 +29,57 @@ func mkAzureImgType() *rhel.ImageType { it.KernelOptions = defaultAzureKernelOptions it.Bootable = true it.DefaultSize = 4 * datasizes.GibiByte - it.DefaultImageConfig = defaultAzureImageConfig + it.DefaultImageConfig = defaultAzureImageConfig(rd) it.BasePartitionTables = defaultBasePartitionTables return it } -// Azure BYOS image type -func mkAzureByosImgType(rd distro.Distro) *rhel.ImageType { +// Azure RHEL-internal image type +func mkAzureInternalImgType(rd *rhel.Distribution) *rhel.ImageType { it := rhel.NewImageType( - "vhd", - "disk.vhd", - "application/x-vhd", + "azure-rhui", + "disk.vhd.xz", + "application/xz", map[string]rhel.PackageSetFunc{ rhel.OSPkgsKey: azurePackageSet, }, rhel.DiskImage, []string{"build"}, - []string{"os", "image", "vpc"}, - []string{"vpc"}, + []string{"os", "image", "vpc", "xz"}, + []string{"xz"}, ) + it.Compression = "xz" it.KernelOptions = defaultAzureKernelOptions it.Bootable = true - it.DefaultSize = 4 * datasizes.GibiByte - it.DefaultImageConfig = defaultAzureImageConfig - it.BasePartitionTables = defaultBasePartitionTables + it.DefaultSize = 64 * datasizes.GibiByte + it.DefaultImageConfig = defaultAzureImageConfig(rd) + it.BasePartitionTables = azureInternalBasePartitionTables + + return it +} + +func mkAzureSapInternalImgType(rd *rhel.Distribution) *rhel.ImageType { + it := rhel.NewImageType( + "azure-sap-rhui", + "disk.vhd.xz", + "application/xz", + map[string]rhel.PackageSetFunc{ + rhel.OSPkgsKey: azureSapPackageSet, + }, + rhel.DiskImage, + []string{"build"}, + []string{"os", "image", "vpc", "xz"}, + []string{"xz"}, + ) + + it.Compression = "xz" + it.KernelOptions = defaultAzureKernelOptions + it.Bootable = true + it.DefaultSize = 64 * datasizes.GibiByte + it.DefaultImageConfig = sapAzureImageConfig(rd) + it.BasePartitionTables = azureInternalBasePartitionTables return it } @@ -143,161 +170,401 @@ 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 +func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) { + switch t.Arch().Name() { + case arch.ARCH_X86_64.String(): + return disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: disk.PT_GPT, + Size: 64 * datasizes.GibiByte, + Partitions: []disk.Partition{ + { + Size: 500 * datasizes.MebiByte, + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Payload: &disk.Filesystem{ + Type: "vfat", + UUID: disk.EFIFilesystemUUID, + Mountpoint: "/boot/efi", + FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", + FSTabFreq: 0, + FSTabPassNo: 2, + }, + }, + // NB: we currently don't support /boot on LVM + { + Size: 1 * datasizes.GibiByte, + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Payload: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2 * datasizes.MebiByte, + Bootable: true, + Type: disk.BIOSBootPartitionGUID, + UUID: disk.BIOSBootPartitionUUID, + }, + { + Type: disk.LVMPartitionGUID, + UUID: disk.RootPartitionUUID, + Payload: &disk.LVMVolumeGroup{ + Name: "rootvg", + Description: "built with lvm2 and osbuild", + LogicalVolumes: []disk.LVMLogicalVolume{ + { + Size: 1 * datasizes.GibiByte, + Name: "homelv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "home", + Mountpoint: "/home", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2 * datasizes.GibiByte, + Name: "rootlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2 * datasizes.GibiByte, + Name: "tmplv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "tmp", + Mountpoint: "/tmp", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 10 * datasizes.GibiByte, + Name: "usrlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "usr", + Mountpoint: "/usr", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 10 * datasizes.GibiByte, + Name: "varlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "var", + Mountpoint: "/var", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, + }, + }, + }, true + case arch.ARCH_AARCH64.String(): + return disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: disk.PT_GPT, + Size: 64 * datasizes.GibiByte, + Partitions: []disk.Partition{ + { + Size: 500 * datasizes.MebiByte, + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Payload: &disk.Filesystem{ + Type: "vfat", + UUID: disk.EFIFilesystemUUID, + Mountpoint: "/boot/efi", + FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", + FSTabFreq: 0, + FSTabPassNo: 2, + }, + }, + // NB: we currently don't support /boot on LVM + { + Size: 1 * datasizes.GibiByte, + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Payload: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Type: disk.LVMPartitionGUID, + UUID: disk.RootPartitionUUID, + Payload: &disk.LVMVolumeGroup{ + Name: "rootvg", + Description: "built with lvm2 and osbuild", + LogicalVolumes: []disk.LVMLogicalVolume{ + { + Size: 1 * datasizes.GibiByte, + Name: "homelv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "home", + Mountpoint: "/home", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2 * datasizes.GibiByte, + Name: "rootlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2 * datasizes.GibiByte, + Name: "tmplv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "tmp", + Mountpoint: "/tmp", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 10 * datasizes.GibiByte, + Name: "usrlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "usr", + Mountpoint: "/usr", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 10 * datasizes.GibiByte, + Name: "varlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "var", + Mountpoint: "/var", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, + }, + }, + }, true + default: + return disk.PartitionTable{}, false + } +} + // IMAGE CONFIG // use loglevel=3 as described in the RHEL documentation and used in existing RHEL images built by MSFT const defaultAzureKernelOptions = "ro loglevel=3 console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300" // based on https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/deploying_rhel_9_on_microsoft_azure/assembly_deploying-a-rhel-image-as-a-virtual-machine-on-microsoft-azure_cloud-content-azure#making-configuration-changes_configure-the-image-azure -var defaultAzureImageConfig = &distro.ImageConfig{ - Timezone: common.ToPtr("Etc/UTC"), - Locale: common.ToPtr("en_US.UTF-8"), - Keyboard: &osbuild.KeymapStageOptions{ - Keymap: "us", - X11Keymap: &osbuild.X11KeymapOptions{ - Layouts: []string{"us"}, - }, - }, - Sysconfig: []*osbuild.SysconfigStageOptions{ - { - Kernel: &osbuild.SysconfigKernelOptions{ - UpdateDefault: true, - DefaultKernel: "kernel-core", - }, - Network: &osbuild.SysconfigNetworkOptions{ - Networking: true, - NoZeroConf: true, +func defaultAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig { + ic := &distro.ImageConfig{ + Timezone: common.ToPtr("Etc/UTC"), + Locale: common.ToPtr("en_US.UTF-8"), + Keyboard: &osbuild.KeymapStageOptions{ + Keymap: "us", + X11Keymap: &osbuild.X11KeymapOptions{ + Layouts: []string{"us"}, }, }, - }, - EnabledServices: []string{ - "firewalld", - "nm-cloud-setup.service", - "nm-cloud-setup.timer", - "sshd", - "waagent", - }, - SshdConfig: &osbuild.SshdConfigStageOptions{ - Config: osbuild.SshdConfigConfig{ - ClientAliveInterval: common.ToPtr(180), - }, - }, - Modprobe: []*osbuild.ModprobeStageOptions{ - { - Filename: "blacklist-amdgpu.conf", - Commands: osbuild.ModprobeConfigCmdList{ - osbuild.NewModprobeConfigCmdBlacklist("amdgpu"), + Sysconfig: []*osbuild.SysconfigStageOptions{ + { + Kernel: &osbuild.SysconfigKernelOptions{ + UpdateDefault: true, + DefaultKernel: "kernel-core", + }, + Network: &osbuild.SysconfigNetworkOptions{ + Networking: true, + NoZeroConf: true, + }, }, }, - { - Filename: "blacklist-intel-cstate.conf", - Commands: osbuild.ModprobeConfigCmdList{ - osbuild.NewModprobeConfigCmdBlacklist("intel_cstate"), + EnabledServices: []string{ + "firewalld", + "nm-cloud-setup.service", + "nm-cloud-setup.timer", + "sshd", + "waagent", + }, + SshdConfig: &osbuild.SshdConfigStageOptions{ + Config: osbuild.SshdConfigConfig{ + ClientAliveInterval: common.ToPtr(180), }, }, - { - Filename: "blacklist-floppy.conf", - Commands: osbuild.ModprobeConfigCmdList{ - osbuild.NewModprobeConfigCmdBlacklist("floppy"), + Modprobe: []*osbuild.ModprobeStageOptions{ + { + Filename: "blacklist-amdgpu.conf", + Commands: osbuild.ModprobeConfigCmdList{ + osbuild.NewModprobeConfigCmdBlacklist("amdgpu"), + }, + }, + { + Filename: "blacklist-intel-cstate.conf", + Commands: osbuild.ModprobeConfigCmdList{ + osbuild.NewModprobeConfigCmdBlacklist("intel_cstate"), + }, + }, + { + Filename: "blacklist-floppy.conf", + Commands: osbuild.ModprobeConfigCmdList{ + osbuild.NewModprobeConfigCmdBlacklist("floppy"), + }, + }, + { + Filename: "blacklist-nouveau.conf", + Commands: osbuild.ModprobeConfigCmdList{ + osbuild.NewModprobeConfigCmdBlacklist("nouveau"), + osbuild.NewModprobeConfigCmdBlacklist("lbm-nouveau"), + }, + }, + { + Filename: "blacklist-skylake-edac.conf", + Commands: osbuild.ModprobeConfigCmdList{ + osbuild.NewModprobeConfigCmdBlacklist("skx_edac"), + }, }, }, - { - Filename: "blacklist-nouveau.conf", - Commands: osbuild.ModprobeConfigCmdList{ - osbuild.NewModprobeConfigCmdBlacklist("nouveau"), - osbuild.NewModprobeConfigCmdBlacklist("lbm-nouveau"), - }, - }, - { - Filename: "blacklist-skylake-edac.conf", - Commands: osbuild.ModprobeConfigCmdList{ - osbuild.NewModprobeConfigCmdBlacklist("skx_edac"), - }, - }, - }, - CloudInit: []*osbuild.CloudInitStageOptions{ - { - Filename: "10-azure-kvp.cfg", - Config: osbuild.CloudInitConfigFile{ - Reporting: &osbuild.CloudInitConfigReporting{ - Logging: &osbuild.CloudInitConfigReportingHandlers{ - Type: "log", + CloudInit: []*osbuild.CloudInitStageOptions{ + { + Filename: "10-azure-kvp.cfg", + Config: osbuild.CloudInitConfigFile{ + Reporting: &osbuild.CloudInitConfigReporting{ + Logging: &osbuild.CloudInitConfigReportingHandlers{ + Type: "log", + }, + Telemetry: &osbuild.CloudInitConfigReportingHandlers{ + Type: "hyperv", + }, }, - Telemetry: &osbuild.CloudInitConfigReportingHandlers{ - Type: "hyperv", + }, + }, + { + Filename: "91-azure_datasource.cfg", + Config: osbuild.CloudInitConfigFile{ + Datasource: &osbuild.CloudInitConfigDatasource{ + Azure: &osbuild.CloudInitConfigDatasourceAzure{ + ApplyNetworkConfig: false, + }, + }, + DatasourceList: []string{ + "Azure", }, }, }, }, - { - Filename: "91-azure_datasource.cfg", - Config: osbuild.CloudInitConfigFile{ - Datasource: &osbuild.CloudInitConfigDatasource{ - Azure: &osbuild.CloudInitConfigDatasourceAzure{ - ApplyNetworkConfig: false, + PwQuality: &osbuild.PwqualityConfStageOptions{ + Config: osbuild.PwqualityConfConfig{ + Minlen: common.ToPtr(6), + Minclass: common.ToPtr(3), + Dcredit: common.ToPtr(0), + Ucredit: common.ToPtr(0), + Lcredit: common.ToPtr(0), + Ocredit: common.ToPtr(0), + }, + }, + WAAgentConfig: &osbuild.WAAgentConfStageOptions{ + Config: osbuild.WAAgentConfig{ + RDFormat: common.ToPtr(false), + RDEnableSwap: common.ToPtr(false), + }, + }, + Grub2Config: &osbuild.GRUB2Config{ + DisableRecovery: common.ToPtr(true), + DisableSubmenu: common.ToPtr(true), + Distributor: "$(sed 's, release .*$,,g' /etc/system-release)", + Terminal: []string{"serial", "console"}, + Serial: "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1", + Timeout: 10, + TimeoutStyle: osbuild.GRUB2ConfigTimeoutStyleCountdown, + }, + UdevRules: &osbuild.UdevRulesStageOptions{ + Filename: "/etc/udev/rules.d/68-azure-sriov-nm-unmanaged.rules", + Rules: osbuild.UdevRules{ + osbuild.UdevRuleComment{ + Comment: []string{ + "Accelerated Networking on Azure exposes a new SRIOV interface to the VM.", + "This interface is transparently bonded to the synthetic interface,", + "so NetworkManager should just ignore any SRIOV interfaces.", }, }, - DatasourceList: []string{ - "Azure", + osbuild.NewUdevRule( + []osbuild.UdevKV{ + {K: "SUBSYSTEM", O: "==", V: "net"}, + {K: "DRIVERS", O: "==", V: "hv_pci"}, + {K: "ACTION", O: "==", V: "add"}, + {K: "ENV", A: "NM_UNMANAGED", O: "=", V: "1"}, + }, + ), + }, + }, + SystemdUnit: []*osbuild.SystemdUnitStageOptions{ + { + Unit: "nm-cloud-setup.service", + Dropin: "10-rh-enable-for-azure.conf", + Config: osbuild.SystemdServiceUnitDropin{ + Service: &osbuild.SystemdUnitServiceSection{ + Environment: []osbuild.EnvironmentVariable{{Key: "NM_CLOUD_SETUP_AZURE", Value: "yes"}}, + }, }, }, }, - }, - PwQuality: &osbuild.PwqualityConfStageOptions{ - Config: osbuild.PwqualityConfConfig{ - Minlen: common.ToPtr(6), - Minclass: common.ToPtr(3), - Dcredit: common.ToPtr(0), - Ucredit: common.ToPtr(0), - Lcredit: common.ToPtr(0), - Ocredit: common.ToPtr(0), - }, - }, - WAAgentConfig: &osbuild.WAAgentConfStageOptions{ - Config: osbuild.WAAgentConfig{ - RDFormat: common.ToPtr(false), - RDEnableSwap: common.ToPtr(false), - }, - }, - Grub2Config: &osbuild.GRUB2Config{ - DisableRecovery: common.ToPtr(true), - DisableSubmenu: common.ToPtr(true), - Distributor: "$(sed 's, release .*$,,g' /etc/system-release)", - Terminal: []string{"serial", "console"}, - Serial: "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1", - Timeout: 10, - TimeoutStyle: osbuild.GRUB2ConfigTimeoutStyleCountdown, - }, - UdevRules: &osbuild.UdevRulesStageOptions{ - Filename: "/etc/udev/rules.d/68-azure-sriov-nm-unmanaged.rules", - Rules: osbuild.UdevRules{ - osbuild.UdevRuleComment{ - Comment: []string{ - "Accelerated Networking on Azure exposes a new SRIOV interface to the VM.", - "This interface is transparently bonded to the synthetic interface,", - "so NetworkManager should just ignore any SRIOV interfaces.", - }, - }, - osbuild.NewUdevRule( - []osbuild.UdevKV{ - {K: "SUBSYSTEM", O: "==", V: "net"}, - {K: "DRIVERS", O: "==", V: "hv_pci"}, - {K: "ACTION", O: "==", V: "add"}, - {K: "ENV", A: "NM_UNMANAGED", O: "=", V: "1"}, - }, - ), - }, - }, - SystemdUnit: []*osbuild.SystemdUnitStageOptions{ - { - Unit: "nm-cloud-setup.service", - Dropin: "10-rh-enable-for-azure.conf", - Config: osbuild.SystemdServiceUnitDropin{ - Service: &osbuild.SystemdUnitServiceSection{ - Environment: []osbuild.EnvironmentVariable{{Key: "NM_CLOUD_SETUP_AZURE", Value: "yes"}}, - }, - }, - }, - }, - DefaultTarget: common.ToPtr("multi-user.target"), + DefaultTarget: common.ToPtr("multi-user.target"), + } + + if rd.IsRHEL() { + ic.GPGKeyFiles = append(ic.GPGKeyFiles, "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release") + } + + return ic +} + +func sapAzureImageConfig(rd *rhel.Distribution) *distro.ImageConfig { + return sapImageConfig(rd.OsVersion()).InheritFrom(defaultAzureImageConfig(rd)) } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/distro.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/distro.go index 3d4c243e3..a5cd9b909 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/distro.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/distro.go @@ -183,13 +183,14 @@ func newDistro(name string, major, minor int) *rhel.Distribution { mkAMIImgTypeX86_64(), ) - aarch64.AddImageTypes( - &platform.Aarch64{ - UEFIVendor: rd.Vendor(), - BasePlatform: platform.BasePlatform{ - ImageFormat: platform.FORMAT_RAW, - }, + ec2Aarch64Platform := &platform.Aarch64{ + UEFIVendor: rd.Vendor(), + BasePlatform: platform.BasePlatform{ + ImageFormat: platform.FORMAT_RAW, }, + } + aarch64.AddImageTypes( + ec2Aarch64Platform, mkAMIImgTypeAarch64(), ) @@ -208,13 +209,8 @@ func newDistro(name string, major, minor int) *rhel.Distribution { }, } - if rd.IsRHEL() { // RHEL-only (non-CentOS) image types - x86_64.AddImageTypes(azureX64Platform, mkAzureByosImgType(rd)) - aarch64.AddImageTypes(azureAarch64Platform, mkAzureByosImgType(rd)) - } else { - x86_64.AddImageTypes(azureX64Platform, mkAzureImgType()) - aarch64.AddImageTypes(azureAarch64Platform, mkAzureImgType()) - } + x86_64.AddImageTypes(azureX64Platform, mkAzureImgType(rd)) + aarch64.AddImageTypes(azureAarch64Platform, mkAzureImgType(rd)) gceX86Platform := &platform.X86{ UEFIVendor: rd.Vendor(), @@ -258,6 +254,16 @@ func newDistro(name string, major, minor int) *rhel.Distribution { mkImageInstallerImgType(), ) + if rd.IsRHEL() { // RHEL-only (non-CentOS) image types + x86_64.AddImageTypes(azureX64Platform, mkAzureInternalImgType(rd)) + aarch64.AddImageTypes(azureAarch64Platform, mkAzureInternalImgType(rd)) + + x86_64.AddImageTypes(azureX64Platform, mkAzureSapInternalImgType(rd)) + + x86_64.AddImageTypes(ec2X86Platform, mkEc2ImgTypeX86_64(), mkEc2HaImgTypeX86_64(), mkEC2SapImgTypeX86_64(rd.OsVersion())) + aarch64.AddImageTypes(ec2Aarch64Platform, mkEC2ImgTypeAarch64()) + } + rd.AddArches(x86_64, aarch64, ppc64le, s390x) return rd } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/options.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/options.go index b77d1c611..059830a43 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/options.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/options.go @@ -2,7 +2,6 @@ package rhel10 import ( "fmt" - "log" "slices" @@ -27,9 +26,24 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima } mountpoints := customizations.GetFilesystems() - - err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies) + partitioning, err := customizations.GetPartitioning() if err != nil { + return nil, err + } + + if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil { + return warnings, err + } + + if len(mountpoints) > 0 && partitioning != nil { + return nil, fmt.Errorf("partitioning customizations cannot be used with custom filesystems (mountpoints)") + } + + if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil { + return warnings, err + } + + if err := partitioning.ValidateLayoutConstraints(); err != nil { return warnings, err } @@ -76,9 +90,7 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima } if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() { - w := fmt.Sprintln(common.FIPSEnabledImageWarning) - log.Print(w) - warnings = append(warnings, w) + warnings = append(warnings, fmt.Sprintln(common.FIPSEnabledImageWarning)) } instCust, err := customizations.GetInstaller() diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/sap.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/sap.go new file mode 100644 index 000000000..1290bb2d6 --- /dev/null +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel10/sap.go @@ -0,0 +1,174 @@ +package rhel10 + +import ( + "github.com/osbuild/images/pkg/distro" + "github.com/osbuild/images/pkg/distro/rhel" + "github.com/osbuild/images/pkg/osbuild" + "github.com/osbuild/images/pkg/rpmmd" +) + +// sapImageConfig returns the SAP specific ImageConfig data +func sapImageConfig(osVersion string) *distro.ImageConfig { + return &distro.ImageConfig{ + SELinuxConfig: &osbuild.SELinuxConfigStageOptions{ + State: osbuild.SELinuxStatePermissive, + }, + // RHBZ#1960617 + Tuned: osbuild.NewTunedStageOptions("sap-hana"), + // RHBZ#1959979 + Tmpfilesd: []*osbuild.TmpfilesdStageOptions{ + osbuild.NewTmpfilesdStageOptions("sap.conf", + []osbuild.TmpfilesdConfigLine{ + { + Type: "x", + Path: "/tmp/.sap*", + }, + { + Type: "x", + Path: "/tmp/.hdb*lock", + }, + { + Type: "x", + Path: "/tmp/.trex*lock", + }, + }, + ), + }, + // RHBZ#1959963 + PamLimitsConf: []*osbuild.PamLimitsConfStageOptions{ + osbuild.NewPamLimitsConfStageOptions("99-sap.conf", + []osbuild.PamLimitsConfigLine{ + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(1048576), + }, + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(1048576), + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(1048576), + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNofile, + Value: osbuild.PamLimitsValueInt(1048576), + }, + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + { + Domain: "@sapsys", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeHard, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + { + Domain: "@dba", + Type: osbuild.PamLimitsTypeSoft, + Item: osbuild.PamLimitsItemNproc, + Value: osbuild.PamLimitsValueUnlimited, + }, + }, + ), + }, + // RHBZ#1959962 + Sysctld: []*osbuild.SysctldStageOptions{ + osbuild.NewSysctldStageOptions("sap.conf", + []osbuild.SysctldConfigLine{ + { + Key: "kernel.pid_max", + Value: "4194304", + }, + { + Key: "vm.max_map_count", + Value: "2147483647", + }, + }, + ), + }, + // E4S/EUS + DNFConfig: []*osbuild.DNFConfigStageOptions{ + osbuild.NewDNFConfigStageOptions( + []osbuild.DNFVariable{ + { + Name: "releasever", + Value: osVersion, + }, + }, + nil, + ), + }, + } +} + +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", + }, + } +} diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/distro.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/distro.go index f35f4500e..4c4a1e359 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/distro.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/distro.go @@ -115,6 +115,15 @@ func newDistro(name string, minor int) *rhel.Distribution { ImageFormat: platform.FORMAT_RAW, }, } + + // Keep the RHEL EC2 x86_64 images before 8.9 BIOS-only for backward compatibility. + // RHEL-internal EC2 images and RHEL AMI images are kept intentionally in sync + // with regard to not supporting hybrid boot mode before RHEL version 8.9. + // The partitioning table for these reflects that and is also intentionally in sync. + if rd.IsRHEL() && common.VersionLessThan(rd.OsVersion(), "8.9") { + ec2X86Platform.UEFIVendor = "" + } + x86_64.AddImageTypes( ec2X86Platform, mkAmiImgTypeX86_64(), @@ -342,16 +351,6 @@ func newDistro(name string, minor int) *rhel.Distribution { mkAzureSapRhuiImgType(rd), ) - // keep the RHEL EC2 x86_64 images before 8.9 BIOS-only for backward compatibility - if common.VersionLessThan(rd.OsVersion(), "8.9") { - ec2X86Platform = &platform.X86{ - BIOS: true, - BasePlatform: platform.BasePlatform{ - ImageFormat: platform.FORMAT_RAW, - }, - } - } - // add ec2 image types to RHEL distro only x86_64.AddImageTypes( ec2X86Platform, diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/options.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/options.go index 56c6b9ca3..6e9d3e04d 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/options.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel8/options.go @@ -2,7 +2,6 @@ package rhel8 import ( "fmt" - "log" "strings" "slices" @@ -29,14 +28,14 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima if options.OSTree != nil { if err := options.OSTree.Validate(); err != nil { - return nil, err + return warnings, err } } if t.BootISO && t.RPMOSTree { // ostree-based ISOs require a URL from which to pull a payload commit if options.OSTree == nil || options.OSTree.URL == "" { - return nil, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.Name()) + return warnings, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.Name()) } if t.Name() == "edge-simplified-installer" { @@ -91,14 +90,10 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima // TODO(edge): directly error if these options are provided when rhel-9.5's time arrives if t.Name() == "edge-commit" || t.Name() == "edge-container" { if customizations.GetUsers() != nil { - w := fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.Name()) - log.Print(w) - warnings = append(warnings, w) + warnings = append(warnings, fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())) } if customizations.GetGroups() != nil { - w := fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.Name()) - log.Print(w) - warnings = append(warnings, w) + warnings = append(warnings, fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())) } } @@ -111,13 +106,27 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima } mountpoints := customizations.GetFilesystems() - - if mountpoints != nil && t.RPMOSTree { - return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types") + partitioning, err := customizations.GetPartitioning() + if err != nil { + return nil, err + } + if partitioning != nil { + return nil, fmt.Errorf("partitioning customizations are not supported on %s", t.Arch().Distro().Name()) } - err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies) - if err != nil { + if mountpoints != nil && t.RPMOSTree { + return warnings, fmt.Errorf("custom mountpoints are not supported for ostree types") + } + + if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil { + return warnings, err + } + + if err := partitioning.ValidateLayoutConstraints(); err != nil { + return warnings, err + } + + if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil { return warnings, err } @@ -171,7 +180,6 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() { w := fmt.Sprintln(common.FIPSEnabledImageWarning) - log.Print(w) warnings = append(warnings, w) } diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/distro.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/distro.go index eb838c7bd..06488134d 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/distro.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/distro.go @@ -202,6 +202,15 @@ func newDistro(name string, major, minor int) *rhel.Distribution { ImageFormat: platform.FORMAT_RAW, }, } + + // Keep the RHEL EC2 x86_64 images before 9.3 BIOS-only for backward compatibility. + // RHEL-internal EC2 images and RHEL AMI images are kept intentionally in sync + // with regard to not supporting hybrid boot mode before RHEL version 9.3. + // The partitioning table for these reflects that and is also intentionally in sync. + if rd.IsRHEL() && common.VersionLessThan(rd.OsVersion(), "9.3") { + ec2X86Platform.UEFIVendor = "" + } + x86_64.AddImageTypes( ec2X86Platform, mkAMIImgTypeX86_64(), @@ -337,16 +346,6 @@ func newDistro(name string, major, minor int) *rhel.Distribution { x86_64.AddImageTypes(azureX64Platform, mkAzureSapInternalImgType(rd)) - // keep the RHEL EC2 x86_64 images before 9.3 BIOS-only for backward compatibility - if common.VersionLessThan(rd.OsVersion(), "9.3") { - ec2X86Platform = &platform.X86{ - BIOS: true, - BasePlatform: platform.BasePlatform{ - ImageFormat: platform.FORMAT_RAW, - }, - } - } - // add ec2 image types to RHEL distro only x86_64.AddImageTypes(ec2X86Platform, mkEc2ImgTypeX86_64(), mkEc2HaImgTypeX86_64(), mkEC2SapImgTypeX86_64(rd.OsVersion())) diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/options.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/options.go index 61fd5cab1..1e11753db 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/options.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/options.go @@ -2,7 +2,6 @@ package rhel9 import ( "fmt" - "log" "strings" "slices" @@ -31,14 +30,14 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima if options.OSTree != nil { if err := options.OSTree.Validate(); err != nil { - return nil, err + return warnings, err } } if t.BootISO && t.RPMOSTree { // ostree-based ISOs require a URL from which to pull a payload commit if options.OSTree == nil || options.OSTree.URL == "" { - return nil, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.Name()) + return warnings, fmt.Errorf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", t.Name()) } if t.Name() == "edge-simplified-installer" { @@ -104,14 +103,10 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima // TODO(edge): directly error if these options are provided when rhel-9.5's time arrives if t.Name() == "edge-commit" || t.Name() == "edge-container" { if customizations.GetUsers() != nil { - w := fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.Name()) - log.Print(w) - warnings = append(warnings, w) + warnings = append(warnings, fmt.Sprintf("Please note that user customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())) } if customizations.GetGroups() != nil { - w := fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.Name()) - log.Print(w) - warnings = append(warnings, w) + warnings = append(warnings, fmt.Sprintf("Please note that group customizations on %q image type are deprecated and will be removed in the near future\n", t.Name())) } } @@ -124,10 +119,13 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima } mountpoints := customizations.GetFilesystems() - - if mountpoints != nil && t.RPMOSTree && (t.Name() == "edge-container" || t.Name() == "edge-commit") { - return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types") - } else if mountpoints != nil && t.RPMOSTree && !(t.Name() == "edge-container" || t.Name() == "edge-commit") { + partitioning, err := customizations.GetPartitioning() + if err != nil { + return nil, err + } + if (mountpoints != nil || partitioning != nil) && t.RPMOSTree && (t.Name() == "edge-container" || t.Name() == "edge-commit") { + return warnings, fmt.Errorf("custom mountpoints and partitioning are not supported for ostree types") + } else if (mountpoints != nil || partitioning != nil) && t.RPMOSTree && !(t.Name() == "edge-container" || t.Name() == "edge-commit") { //customization allowed for edge-raw-image,edge-ami,edge-vsphere,edge-simplified-installer err := blueprint.CheckMountpointsPolicy(mountpoints, policies.OstreeMountpointPolicies) if err != nil { @@ -135,8 +133,19 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima } } - err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies) - if err != nil { + if len(mountpoints) > 0 && partitioning != nil { + return nil, fmt.Errorf("partitioning customizations cannot be used with custom filesystems (mountpoints)") + } + + if err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies); err != nil { + return warnings, err + } + + if err := blueprint.CheckDiskMountpointsPolicy(partitioning, policies.MountpointPolicies); err != nil { + return warnings, err + } + + if err := partitioning.ValidateLayoutConstraints(); err != nil { return warnings, err } @@ -189,9 +198,7 @@ func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.Ima } if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() { - w := fmt.Sprintln(common.FIPSEnabledImageWarning) - log.Print(w) - warnings = append(warnings, w) + warnings = append(warnings, fmt.Sprintln(common.FIPSEnabledImageWarning)) } instCust, err := customizations.GetInstaller() diff --git a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/partition_tables.go b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/partition_tables.go index cb17cd210..03959ea62 100644 --- a/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/partition_tables.go +++ b/vendor/github.com/osbuild/images/pkg/distro/rhel/rhel9/partition_tables.go @@ -1,6 +1,8 @@ package rhel9 import ( + "strings" + "github.com/osbuild/images/internal/common" "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/datasizes" @@ -24,6 +26,47 @@ func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) { switch t.Arch().Name() { case arch.ARCH_X86_64.String(): + // RHEL EC2 x86_64 images prior to 9.3 support only BIOS boot + if common.VersionLessThan(t.Arch().Distro().OsVersion(), "9.3") && t.IsRHEL() && (strings.HasPrefix(t.Name(), "ec2") || t.Name() == "ami") { + return disk.PartitionTable{ + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: disk.PT_GPT, + Partitions: []disk.Partition{ + { + Size: 1 * datasizes.MebiByte, + Bootable: true, + Type: disk.BIOSBootPartitionGUID, + UUID: disk.BIOSBootPartitionUUID, + }, + { + Size: bootSize, + Type: disk.XBootLDRPartitionGUID, + UUID: disk.FilesystemDataUUID, + Payload: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + Label: "boot", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Size: 2 * datasizes.GibiByte, + Type: disk.FilesystemDataGUID, + UUID: disk.RootPartitionUUID, + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, true + } return disk.PartitionTable{ UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", Type: disk.PT_GPT, diff --git a/vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer_iso_tree.go b/vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer_iso_tree.go index 6978f7836..65d6fa2bf 100644 --- a/vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer_iso_tree.go +++ b/vendor/github.com/osbuild/images/pkg/manifest/anaconda_installer_iso_tree.go @@ -303,7 +303,7 @@ func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline { Size: fmt.Sprintf("%d", p.PartitionTable.Size), })) - for _, stage := range osbuild.GenMkfsStages(p.PartitionTable, filename) { + for _, stage := range osbuild.GenFsStages(p.PartitionTable, filename) { pipeline.AddStage(stage) } diff --git a/vendor/github.com/osbuild/images/pkg/manifest/coi_iso_tree.go b/vendor/github.com/osbuild/images/pkg/manifest/coi_iso_tree.go index a00dbe297..3fbf1155c 100644 --- a/vendor/github.com/osbuild/images/pkg/manifest/coi_iso_tree.go +++ b/vendor/github.com/osbuild/images/pkg/manifest/coi_iso_tree.go @@ -111,7 +111,7 @@ func (p *CoreOSISOTree) serialize() osbuild.Pipeline { Size: fmt.Sprintf("%d", p.PartitionTable.Size), })) - for _, stage := range osbuild.GenMkfsStages(p.PartitionTable, filename) { + for _, stage := range osbuild.GenFsStages(p.PartitionTable, filename) { pipeline.AddStage(stage) } diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/bootupd_stage.go b/vendor/github.com/osbuild/images/pkg/osbuild/bootupd_stage.go index bee683fba..3afa264a9 100644 --- a/vendor/github.com/osbuild/images/pkg/osbuild/bootupd_stage.go +++ b/vendor/github.com/osbuild/images/pkg/osbuild/bootupd_stage.go @@ -110,17 +110,22 @@ func genMountsForBootupd(source string, pt *disk.PartitionTable) ([]Mount, error case *disk.LVMVolumeGroup: for i := range payload.LogicalVolumes { lv := &payload.LogicalVolumes[i] - mountable, ok := lv.Payload.(disk.Mountable) - if !ok { - return nil, fmt.Errorf("expected LV payload %+[1]v to be mountable, got %[1]T", lv.Payload) + switch payload := lv.Payload.(type) { + case disk.Mountable: + mount, err := genOsbuildMount(lv.Name, payload) + if err != nil { + return nil, err + } + mount.Source = lv.Name + mounts = append(mounts, *mount) + case *disk.Swap: + // nothing to do + default: + return nil, fmt.Errorf("expected LV payload %+[1]v to be mountable or swap, got %[1]T", lv.Payload) } - mount, err := genOsbuildMount(lv.Name, mountable) - if err != nil { - return nil, err - } - mount.Source = lv.Name - mounts = append(mounts, *mount) } + case *disk.Swap: + // nothing to do default: return nil, fmt.Errorf("type %T not supported by bootupd handling yet", part.Payload) } diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/btrfs_subvol_stage.go b/vendor/github.com/osbuild/images/pkg/osbuild/btrfs_subvol_stage.go index f7deca5f5..678215f3f 100644 --- a/vendor/github.com/osbuild/images/pkg/osbuild/btrfs_subvol_stage.go +++ b/vendor/github.com/osbuild/images/pkg/osbuild/btrfs_subvol_stage.go @@ -1,9 +1,5 @@ package osbuild -import ( - "github.com/osbuild/images/pkg/disk" -) - type BtrfsSubVolOptions struct { Subvolumes []BtrfsSubVol `json:"subvolumes"` } @@ -22,52 +18,3 @@ func NewBtrfsSubVol(options *BtrfsSubVolOptions, devices *map[string]Device, mou Mounts: *mounts, } } - -func GenBtrfsSubVolStage(filename string, pt *disk.PartitionTable) *Stage { - var subvolumes []BtrfsSubVol - - genStage := func(mnt disk.Mountable, path []disk.Entity) error { - if mnt.GetFSType() != "btrfs" { - return nil - } - - btrfs := mnt.(*disk.BtrfsSubvolume) - subvolumes = append(subvolumes, BtrfsSubVol{Name: "/" + btrfs.Name}) - - return nil - } - - _ = pt.ForEachMountable(genStage) - - if len(subvolumes) == 0 { - return nil - } - - devices, mounts := genBtrfsMountDevices(filename, pt) - - return NewBtrfsSubVol(&BtrfsSubVolOptions{subvolumes}, devices, mounts) -} - -func genBtrfsMountDevices(filename string, pt *disk.PartitionTable) (*map[string]Device, *[]Mount) { - devices := make(map[string]Device, len(pt.Partitions)) - mounts := make([]Mount, 0, len(pt.Partitions)) - genMounts := func(ent disk.Entity, path []disk.Entity) error { - if _, isBtrfs := ent.(*disk.Btrfs); !isBtrfs { - return nil - } - - stageDevices, name := getDevices(path, filename, false) - - mounts = append(mounts, *NewBtrfsMount(name, name, "/", "", "")) - - // update devices map with new elements from stageDevices - for devName := range stageDevices { - devices[devName] = stageDevices[devName] - } - return nil - } - - _ = pt.ForEachEntity(genMounts) - - return &devices, &mounts -} diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/device.go b/vendor/github.com/osbuild/images/pkg/osbuild/device.go index 969bf51d1..8dbdb7729 100644 --- a/vendor/github.com/osbuild/images/pkg/osbuild/device.go +++ b/vendor/github.com/osbuild/images/pkg/osbuild/device.go @@ -162,6 +162,8 @@ func deviceName(p disk.Entity) string { return payload.Name case *disk.Btrfs: return "btrfs-" + payload.UUID[:4] + case *disk.Swap: + return "swap-" + payload.UUID[:4] } panic(fmt.Sprintf("unsupported device type in deviceName: '%T'", p)) } diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/disk.go b/vendor/github.com/osbuild/images/pkg/osbuild/disk.go index df000ecff..30465d9c0 100644 --- a/vendor/github.com/osbuild/images/pkg/osbuild/disk.go +++ b/vendor/github.com/osbuild/images/pkg/osbuild/disk.go @@ -99,15 +99,11 @@ func GenImagePrepareStages(pt *disk.PartitionTable, filename string, partTool Pa s := GenDeviceCreationStages(pt, filename) stages = append(stages, s...) - // Generate all the filesystems on partitons and devices - s = GenMkfsStages(pt, filename) + // Generate all the filesystems, subvolumes, and swap areas on partitons + // and devices + s = GenFsStages(pt, filename) stages = append(stages, s...) - subvolStage := GenBtrfsSubVolStage(filename, pt) - if subvolStage != nil { - stages = append(stages, subvolStage) - } - return stages } diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/fstab_stage.go b/vendor/github.com/osbuild/images/pkg/osbuild/fstab_stage.go index 6f807a52c..267c06952 100644 --- a/vendor/github.com/osbuild/images/pkg/osbuild/fstab_stage.go +++ b/vendor/github.com/osbuild/images/pkg/osbuild/fstab_stage.go @@ -58,13 +58,13 @@ func (options *FSTabStageOptions) AddFilesystem(id string, vfsType string, path func NewFSTabStageOptions(pt *disk.PartitionTable) (*FSTabStageOptions, error) { var options FSTabStageOptions - genOption := func(mnt disk.Mountable, path []disk.Entity) error { + genOption := func(mnt disk.FSTabEntity, path []disk.Entity) error { fsSpec := mnt.GetFSSpec() fsOptions, err := mnt.GetFSTabOptions() if err != nil { return err } - options.AddFilesystem(fsSpec.UUID, mnt.GetFSType(), mnt.GetMountpoint(), fsOptions.MntOps, fsOptions.Freq, fsOptions.PassNo) + options.AddFilesystem(fsSpec.UUID, mnt.GetFSType(), mnt.GetFSFile(), fsOptions.MntOps, fsOptions.Freq, fsOptions.PassNo) return nil } @@ -72,7 +72,7 @@ func NewFSTabStageOptions(pt *disk.PartitionTable) (*FSTabStageOptions, error) { return fmt.Sprintf("%d%s", fs.PassNo, fs.Path) } - err := pt.ForEachMountable(genOption) + err := pt.ForEachFSTabEntity(genOption) if err != nil { return nil, err } diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/mkfs_stage.go b/vendor/github.com/osbuild/images/pkg/osbuild/mkfs_stage.go index b942406dd..33558a66b 100644 --- a/vendor/github.com/osbuild/images/pkg/osbuild/mkfs_stage.go +++ b/vendor/github.com/osbuild/images/pkg/osbuild/mkfs_stage.go @@ -7,81 +7,96 @@ import ( "github.com/osbuild/images/pkg/disk" ) -// GenMkfsStages generates a list of org.mkfs.* stages based on a -// partition table description for a single device node -// filename is the path to the underlying image file (to be used as a source for the loopback device) -func GenMkfsStages(pt *disk.PartitionTable, filename string) []*Stage { +// GenFsStages generates a list of stages that create the filesystem and other +// related entities. Specifically, it creates stages for: +// - org.osbuild.mkfs.*: for all filesystems and btrfs volumes +// - org.osbuild.btrfs.subvol: for all btrfs subvolumes +// - org.osbuild.mkswap: for swap areas +func GenFsStages(pt *disk.PartitionTable, filename string) []*Stage { stages := make([]*Stage, 0, len(pt.Partitions)) - processedBtrfsPartitions := make(map[string]bool) - genStage := func(mnt disk.Mountable, path []disk.Entity) error { - t := mnt.GetFSType() - var stage *Stage + genStage := func(ent disk.Entity, path []disk.Entity) error { + switch e := ent.(type) { + case *disk.Filesystem: + // TODO: extract last device renaming into helper + stageDevices, lastName := getDevices(path, filename, true) - stageDevices, lastName := getDevices(path, filename, true) + // The last device in the chain must be named "device", because that's + // the device that mkfs stages run on. See the stage schemas for + // reference. + lastDevice := stageDevices[lastName] + delete(stageDevices, lastName) + stageDevices["device"] = lastDevice - // The last device in the chain must be named "device", because that's the device that mkfs stages run on. - // See their schema for reference. - lastDevice := stageDevices[lastName] - delete(stageDevices, lastName) - stageDevices["device"] = lastDevice + switch e.GetFSType() { + case "xfs": + options := &MkfsXfsStageOptions{ + UUID: e.UUID, + Label: e.Label, + } + stages = append(stages, NewMkfsXfsStage(options, stageDevices)) + case "vfat": + options := &MkfsFATStageOptions{ + VolID: strings.Replace(e.UUID, "-", "", -1), + } + stages = append(stages, NewMkfsFATStage(options, stageDevices)) + case "ext4": + options := &MkfsExt4StageOptions{ + UUID: e.UUID, + Label: e.Label, + } + stages = append(stages, NewMkfsExt4Stage(options, stageDevices)) + default: + panic(fmt.Sprintf("unknown fs type: %s", e.GetFSType())) + } + case *disk.Btrfs: + stageDevices, lastName := getDevices(path, filename, true) - fsSpec := mnt.GetFSSpec() - switch t { - case "xfs": - options := &MkfsXfsStageOptions{ - UUID: fsSpec.UUID, - Label: fsSpec.Label, - } - stage = NewMkfsXfsStage(options, stageDevices) - case "vfat": - options := &MkfsFATStageOptions{ - VolID: strings.Replace(fsSpec.UUID, "-", "", -1), - } - stage = NewMkfsFATStage(options, stageDevices) - case "btrfs": - // the disk library allows only subvolumes as Mountable, so we need to find the underlying btrfs partition - // and mkfs it - btrfsPart := findBtrfsPartition(path) - if btrfsPart == nil { - panic(fmt.Sprintf("found btrfs subvolume without btrfs partition: %s", mnt.GetMountpoint())) - } - - // btrfs partitions can be shared between multiple subvolumes, so we need to make sure we only create - // one - if processedBtrfsPartitions[btrfsPart.UUID] { - return nil - } - processedBtrfsPartitions[btrfsPart.UUID] = true + // The last device in the chain must be named "device", because that's + // the device that mkfs stages run on. See the stage schemas for + // reference. + lastDevice := stageDevices[lastName] + delete(stageDevices, lastName) + stageDevices["device"] = lastDevice options := &MkfsBtrfsStageOptions{ - UUID: btrfsPart.UUID, - Label: btrfsPart.Label, + UUID: e.UUID, + Label: e.Label, } - stage = NewMkfsBtrfsStage(options, stageDevices) - case "ext4": - options := &MkfsExt4StageOptions{ - UUID: fsSpec.UUID, - Label: fsSpec.Label, + stages = append(stages, NewMkfsBtrfsStage(options, stageDevices)) + // Handle subvolumes here directly instead of collecting them in + // their own case, since we already have access to the parent volume. + subvolumes := make([]BtrfsSubVol, len(e.Subvolumes)) + for idx, subvol := range e.Subvolumes { + subvolumes[idx] = BtrfsSubVol{Name: "/" + strings.TrimLeft(subvol.Name, "/")} } - stage = NewMkfsExt4Stage(options, stageDevices) - default: - panic("unknown fs type " + t) - } - stages = append(stages, stage) + // Subvolume creation does not require locking the device, nor does + // it require the renaming to "device", but let's reuse the volume + // device for convenience + mount := *NewBtrfsMount("volume", "device", "/", "", "") + stages = append(stages, NewBtrfsSubVol(&BtrfsSubVolOptions{subvolumes}, &stageDevices, &[]Mount{mount})) + case *disk.Swap: + // TODO: extract last device renaming into helper + stageDevices, lastName := getDevices(path, filename, true) + + // The last device in the chain must be named "device", because that's + // the device that the mkswap stage runs on. See the stage schema + // for reference. + lastDevice := stageDevices[lastName] + delete(stageDevices, lastName) + stageDevices["device"] = lastDevice + + options := &MkswapStageOptions{ + UUID: e.UUID, + Label: e.Label, + } + stages = append(stages, NewMkswapStage(options, stageDevices)) + } return nil } - _ = pt.ForEachMountable(genStage) // genStage always returns nil + _ = pt.ForEachEntity(genStage) // genStage always returns nil return stages -} -func findBtrfsPartition(path []disk.Entity) *disk.Btrfs { - for _, e := range path { - if btrfsPartition, ok := e.(*disk.Btrfs); ok { - return btrfsPartition - } - } - return nil } diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/mkswap_stage.go b/vendor/github.com/osbuild/images/pkg/osbuild/mkswap_stage.go new file mode 100644 index 000000000..d4cfdabd6 --- /dev/null +++ b/vendor/github.com/osbuild/images/pkg/osbuild/mkswap_stage.go @@ -0,0 +1,16 @@ +package osbuild + +type MkswapStageOptions struct { + UUID string `json:"uuid"` + Label string `json:"label,omitempty"` +} + +func (MkswapStageOptions) isStageOptions() {} + +func NewMkswapStage(options *MkswapStageOptions, devices map[string]Device) *Stage { + return &Stage{ + Type: "org.osbuild.mkswap", + Options: options, + Devices: devices, + } +} diff --git a/vendor/github.com/osbuild/images/pkg/osbuild/monitor.go b/vendor/github.com/osbuild/images/pkg/osbuild/monitor.go new file mode 100644 index 000000000..72c8fdb61 --- /dev/null +++ b/vendor/github.com/osbuild/images/pkg/osbuild/monitor.go @@ -0,0 +1,180 @@ +package osbuild + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "strings" + "time" +) + +// Status is a high level aggregation of the low-level osbuild monitor +// messages. It is more structured and meant to be used by UI frontends. +// +// this is intentionally minimal at the beginning until we figure +// out the best API, exposing the jsonseq direct feels too messy +// and based on what we learn here we may consider tweaking +// the osbuild progress +type Status struct { + // Trace contains a single log line, usually very low-level or + // stage output but useful for e.g. bug reporting. Should in + // general not be displayed to the user but the concatenation + // of all "trace" lines should give the same information as + // running osbuild on a terminal + Trace string + + // Message contains a high level user-visible message about + // e.g. a startus change + Message string + + // Progress contains the current progress. + Progress *Progress + + // Timestamp contains the timestamp the message was recieved in + Timestamp time.Time +} + +// Progress provides progress information from an osbuild build. +// Each progress can have an arbitrary number of sub-progress information +// +// Note while those can be nested arbitrarly deep in practise +// we are at 2 levels currently: +// 1. overall pipeline progress +// 2. stages inside each pipeline +// +// we might get +// 3. stage progress (e.g. rpm install progress) +// +// in the future +type Progress struct { + // A human readable message about what is going on + Message string + // The amount of work already done + Done int + // The total amount of work for this (sub)progress + Total int + + SubProgress *Progress +} + +// NewStatusScanner returns a StatusScanner that can parse osbuild +// jsonseq monitor status messages +func NewStatusScanner(r io.Reader) *StatusScanner { + return &StatusScanner{ + scanner: bufio.NewScanner(r), + contextMap: make(map[string]*contextJSON), + stageContextMap: make(map[string]*stageContextJSON), + } +} + +// StatusScanner scan scan the osbuild jsonseq monitor output +type StatusScanner struct { + scanner *bufio.Scanner + contextMap map[string]*contextJSON + stageContextMap map[string]*stageContextJSON +} + +// Status returns a single status struct from the scanner or nil +// if the end of the status reporting is reached. +func (sr *StatusScanner) Status() (*Status, error) { + if !sr.scanner.Scan() { + return nil, sr.scanner.Err() + } + + var status statusJSON + line := sr.scanner.Bytes() + line = bytes.Trim(line, "\x1e") + if err := json.Unmarshal(line, &status); err != nil { + return nil, fmt.Errorf("cannot scan line %q: %w", line, err) + } + // keep track of the context + id := status.Context.ID + context := sr.contextMap[id] + if context == nil { + sr.contextMap[id] = &status.Context + context = &status.Context + } + ts := time.UnixMilli(int64(status.Timestamp * 1000)) + pipelineName := context.Pipeline.Name + + var trace, msg string + // This is a convention, "osbuild.montior" sends the high level + // status, the other messages contain low-level stdout/stderr + // output from individual stages like "org.osbuild.rpm". + if context.Origin == "osbuild.monitor" { + msg = strings.TrimSpace(status.Message) + } else { + trace = strings.TrimSpace(status.Message) + } + + st := &Status{ + Trace: trace, + Message: msg, + Progress: &Progress{ + Done: status.Progress.Done, + Total: status.Progress.Total, + Message: fmt.Sprintf("Pipeline %s", pipelineName), + }, + Timestamp: ts, + } + + // add subprogress + stageID := context.Pipeline.Stage.ID + stageContext := sr.stageContextMap[stageID] + if stageContext == nil { + sr.stageContextMap[id] = &context.Pipeline.Stage + stageContext = &context.Pipeline.Stage + } + stageName := fmt.Sprintf("Stage %s", stageContext.Name) + prog := st.Progress + for subProg := status.Progress.SubProgress; subProg != nil; subProg = subProg.SubProgress { + prog.SubProgress = &Progress{ + Done: subProg.Done, + Total: subProg.Total, + Message: stageName, + } + prog = prog.SubProgress + } + + return st, nil +} + +// statusJSON is a single status entry from the osbuild monitor +type statusJSON struct { + Context contextJSON `json:"context"` + Progress progressJSON `json:"progress"` + // Add "Result" here once + // https://github.com/osbuild/osbuild/pull/1831 is merged + + Message string `json:"message"` + Timestamp float64 `json:"timestamp"` +} + +// contextJSON is the context for which a status is given. Once a context +// was sent to the user from then on it is only referenced by the ID +type contextJSON struct { + Origin string `json:"origin"` + ID string `json:"id"` + Pipeline struct { + ID string `json:"id"` + Name string `json:"name"` + Stage stageContextJSON `json:"stage"` + } `json:"pipeline"` +} + +type stageContextJSON struct { + Name string `json:"name"` + ID string `json:"id"` +} + +// progress is the progress information associcated with a given status. +// The details about nesting are the same as for "Progress" above. +type progressJSON struct { + Name string `json:"name"` + Total int `json:"total"` + Done int `json:"done"` + + SubProgress *progressJSON `json:"progress"` +} diff --git a/vendor/github.com/osbuild/images/pkg/reporegistry/repository.go b/vendor/github.com/osbuild/images/pkg/reporegistry/repository.go index ffe14574a..4706724be 100644 --- a/vendor/github.com/osbuild/images/pkg/reporegistry/repository.go +++ b/vendor/github.com/osbuild/images/pkg/reporegistry/repository.go @@ -75,7 +75,7 @@ func LoadAllRepositoriesFromFS(confPaths []fs.FS) (rpmmd.DistrosRepoConfigs, err return nil, err } - logrus.Infof("Loaded repository configuration file: %s", configFile) + logrus.Infof("Loaded repository configuration file: %s", fileEntry.Name()) distrosRepoConfigs[distro] = distroRepos } diff --git a/vendor/modules.txt b/vendor/modules.txt index 89334e98b..dfaf17311 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1022,7 +1022,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/transfer github.com/oracle/oci-go-sdk/v54/workrequests -# github.com/osbuild/images v0.102.0 +# github.com/osbuild/images v0.105.0 ## explicit; go 1.21.0 github.com/osbuild/images/internal/common github.com/osbuild/images/internal/environment