go.mod: bump osbuild/images to v0.158.0

Use the version that contains the updated Koji upload code.

Also bump the version of `osbuild/blueprint` due to the new `uri` field
in file customizations.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
This commit is contained in:
Tomáš Hozza 2025-07-08 15:17:05 +02:00 committed by Sanne Raymaekers
parent 17380c7aca
commit 7a580f79ae
53 changed files with 1399 additions and 1957 deletions

6
go.mod
View file

@ -45,8 +45,8 @@ require (
github.com/oapi-codegen/runtime v1.1.1
github.com/openshift-online/ocm-sdk-go v0.1.438
github.com/oracle/oci-go-sdk/v54 v54.0.0
github.com/osbuild/blueprint v1.6.0
github.com/osbuild/images v0.156.0
github.com/osbuild/blueprint v1.10.0
github.com/osbuild/images v0.158.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.21.1
@ -60,7 +60,7 @@ require (
golang.org/x/oauth2 v0.30.0
golang.org/x/sync v0.15.0
golang.org/x/sys v0.33.0
google.golang.org/api v0.239.0
google.golang.org/api v0.240.0
)
require (

12
go.sum
View file

@ -577,10 +577,10 @@ 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/blueprint v1.6.0 h1:HUV1w/dMxpgqOgVtHhfTZE3zRmWQkuW/qTfx9smKImI=
github.com/osbuild/blueprint v1.6.0/go.mod h1:0d3dlY8aSJ6jM6NHwBmJFF1VIySsp/GsDpcJQ0yrOqM=
github.com/osbuild/images v0.156.0 h1:G83I4mrvD8GzXF6aXNNeAFbj3eHv/b8nLVnyuLxWz40=
github.com/osbuild/images v0.156.0/go.mod h1:Ae3VCmXpuoV6jjengnqEEKvErQByyJfIFseINtRBvOI=
github.com/osbuild/blueprint v1.10.0 h1:6TG+mSV5kUA3Vq+0fc10MchDilBcDd8SEA8KbDFUn2w=
github.com/osbuild/blueprint v1.10.0/go.mod h1:uknOfX/bAoi+dbeNJj+uAir1T++/LVEtoY8HO3U7MiQ=
github.com/osbuild/images v0.158.0 h1:9TIueFQ83LkMEB6Af6ID92eNSD0oV4SuCAmaoDLGffU=
github.com/osbuild/images v0.158.0/go.mod h1:cHCCI3bZmv+SQk15fCRmMiBu3KVgCqug6YKqD2rZFzM=
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=
@ -931,8 +931,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.239.0 h1:2hZKUnFZEy81eugPs4e2XzIJ5SOwQg0G82bpXD65Puo=
google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU=
google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

View file

@ -724,7 +724,7 @@ func stagesToPackageMetadata(stages []osbuild.RPMStageMetadata) []PackageMetadat
Release: rpm.Release,
Epoch: rpm.Epoch,
Arch: rpm.Arch,
Signature: osbuild.RPMPackageMetadataToSignature(rpm),
Signature: rpm.Signature(),
Sigmd5: rpm.SigMD5,
},
)

View file

@ -1,3 +1,8 @@
//go:build cgo
// koji requires the khttp kerberos module which requires cgo so when
// build without cgo kerberos uploads are currently not supported
package koji
import (
@ -306,6 +311,8 @@ func (k *Koji) Upload(file io.Reader, filepath, filename string) (string, uint64
return "", 0, err
}
// NB: the 'n' returned by Read() of an io.Reader can never be negative
/* #nosec G115 */
offset += uint64(n)
m, err := hash.Write(chunk[:n])

View file

@ -57,7 +57,7 @@ func OSBuildMetadataToRPMs(stagesMetadata map[string]osbuild.StageMetadata) []RP
Release: pkg.Release,
Arch: pkg.Arch,
Sigmd5: pkg.SigMD5,
Signature: osbuild.RPMPackageMetadataToSignature(pkg),
Signature: pkg.Signature(),
})
}
default:

View file

@ -14,8 +14,8 @@ import (
// A Blueprint is a high-level description of an image.
type Blueprint struct {
Name string `json:"name" toml:"name"`
Description string `json:"description" toml:"description"`
Name string `json:"name,omitempty" toml:"name,omitempty"`
Description string `json:"description,omitempty" toml:"description,omitempty"`
Version string `json:"version,omitempty" toml:"version,omitempty"`
Packages []Package `json:"packages" toml:"packages"`
Modules []Package `json:"modules" toml:"modules"`
@ -26,8 +26,8 @@ type Blueprint struct {
Groups []Group `json:"groups" toml:"groups"`
Containers []Container `json:"containers,omitempty" toml:"containers,omitempty"`
Customizations *Customizations `json:"customizations,omitempty" toml:"customizations"`
Distro string `json:"distro" toml:"distro"`
Customizations *Customizations `json:"customizations,omitempty" toml:"customizations,omitempty"`
Distro string `json:"distro,omitempty" toml:"distro,omitempty"`
Arch string `json:"architecture,omitempty" toml:"architecture,omitempty"`
// EXPERIMENTAL
@ -361,6 +361,9 @@ func Convert(bp Blueprint) iblueprint.Blueprint {
ipart := iblueprint.PartitionCustomization{
Type: part.Type,
MinSize: part.MinSize,
PartType: part.PartType,
PartLabel: part.PartLabel,
PartUUID: part.PartUUID,
BtrfsVolumeCustomization: iblueprint.BtrfsVolumeCustomization{},
VGCustomization: iblueprint.VGCustomization{
Name: part.VGCustomization.Name,

View file

@ -64,7 +64,7 @@ type FDOCustomization struct {
type KernelCustomization struct {
Name string `json:"name,omitempty" toml:"name,omitempty"`
Append string `json:"append" toml:"append"`
Append string `json:"append,omitempty" toml:"append,omitempty"`
}
type SSHKeyCustomization struct {

View file

@ -9,6 +9,7 @@ import (
"regexp"
"slices"
"strings"
"unicode/utf16"
"github.com/google/uuid"
"github.com/osbuild/images/pkg/datasizes"
@ -19,8 +20,8 @@ type DiskCustomization struct {
// Type of the partition table: gpt or dos.
// Optional, the default depends on the distro and image type.
Type string `json:"type,omitempty" toml:"type,omitempty"`
MinSize uint64 `json:"minsize,omitempty" toml:"minsize,omitempty"`
Partitions []PartitionCustomization `json:"partitions,omitempty" toml:"minsize,omitempty"`
MinSize uint64 `json:"minsize,omitempty,omitzero" toml:"minsize,omitempty,omitzero"`
Partitions []PartitionCustomization `json:"partitions,omitempty" toml:"partitions,omitempty"`
}
type diskCustomizationMarshaler struct {
@ -64,7 +65,7 @@ type PartitionCustomization struct {
// addition, certain mountpoints have required minimum sizes. See
// https://osbuild.org/docs/user-guide/partitioning for more details.
// (optional, defaults depend on payload and mountpoints).
MinSize uint64 `json:"minsize" toml:"minsize"`
MinSize uint64 `json:"minsize,omitempty,omitzero" toml:"minsize,omitempty,omitzero"`
// The partition type GUID for GPT partitions. For DOS partitions, this
// field can be used to set the (2 hex digit) partition type.
@ -72,6 +73,14 @@ type PartitionCustomization struct {
// or the payload type.
PartType string `json:"part_type,omitempty" toml:"part_type,omitempty"`
// The partition label for GPT partitions, not supported for dos partitions.
// Note: This is not the same as the label, which can be set in "Label"
PartLabel string `json:"part_label,omitempty" toml:"part_label,omitempty"`
// The partition GUID for GPT partitions, not supported for dos partitions.
// Note: This is the unique uuid, not the type guid, that is PartType
PartUUID string `json:"part_uuid,omitempty" toml:"part_uuid,omitempty"`
BtrfsVolumeCustomization
VGCustomization
@ -117,7 +126,7 @@ type LVCustomization struct {
Name string `json:"name,omitempty" toml:"name,omitempty"`
// Minimum size of the logical volume
MinSize uint64 `json:"minsize,omitempty" toml:"minsize,omitempty"`
MinSize uint64 `json:"minsize,omitempty,omitzero" toml:"minsize,omitempty,omitzero"`
FilesystemTypedCustomization
}
@ -176,9 +185,11 @@ type BtrfsSubvolumeCustomization struct {
func (v *PartitionCustomization) UnmarshalJSON(data []byte) error {
errPrefix := "JSON unmarshal:"
var typeSniffer struct {
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
PartLabel string `json:"part_label"`
PartUUID string `json:"part_uuid"`
}
if err := json.Unmarshal(data, &typeSniffer); err != nil {
return fmt.Errorf("%s %w", errPrefix, err)
@ -208,6 +219,8 @@ func (v *PartitionCustomization) UnmarshalJSON(data []byte) error {
v.Type = partType
v.PartType = typeSniffer.PartType
v.PartLabel = typeSniffer.PartLabel
v.PartUUID = typeSniffer.PartUUID
if typeSniffer.MinSize == nil {
return fmt.Errorf("minsize is required")
@ -227,11 +240,13 @@ func (v *PartitionCustomization) UnmarshalJSON(data []byte) error {
// the type is "plain", none of the fields for btrfs or lvm are used.
func decodePlain(v *PartitionCustomization, data []byte) error {
var plain struct {
// Type, minsize, and part_type are handled by the caller. These are added here to
// Type, minsize, and part_* are handled by the caller. These are added here to
// satisfy "DisallowUnknownFields" when decoding.
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
PartLabel string `json:"part_label"`
PartUUID string `json:"part_uuid"`
FilesystemTypedCustomization
}
@ -251,11 +266,13 @@ func decodePlain(v *PartitionCustomization, data []byte) error {
// the type is btrfs, none of the fields for plain or lvm are used.
func decodeBtrfs(v *PartitionCustomization, data []byte) error {
var btrfs struct {
// Type, minsize, and part_type are handled by the caller. These are added here to
// Type, minsize, and part_* are handled by the caller. These are added here to
// satisfy "DisallowUnknownFields" when decoding.
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
PartLabel string `json:"part_label"`
PartUUID string `json:"part_uuid"`
BtrfsVolumeCustomization
}
@ -275,11 +292,13 @@ func decodeBtrfs(v *PartitionCustomization, data []byte) error {
// is lvm, none of the fields for plain or btrfs are used.
func decodeLVM(v *PartitionCustomization, data []byte) error {
var vg struct {
// Type, minsize, and part_type are handled by the caller. These are added here to
// Type, minsize, and part_* are handled by the caller. These are added here to
// satisfy "DisallowUnknownFields" when decoding.
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
Type string `json:"type"`
MinSize any `json:"minsize"`
PartType string `json:"part_type"`
PartLabel string `json:"part_label"`
PartUUID string `json:"part_uuid"`
VGCustomization
}
@ -397,6 +416,12 @@ func (p *DiskCustomization) Validate() error {
if err := part.ValidatePartitionTypeID(p.Type); err != nil {
errs = append(errs, err)
}
if err := part.ValidatePartitionID(p.Type); err != nil {
errs = append(errs, err)
}
if err := part.ValidatePartitionLabel(p.Type); err != nil {
errs = append(errs, err)
}
switch part.Type {
case "plain", "":
errs = append(errs, part.validatePlain(mountpoints))
@ -539,6 +564,48 @@ func (p *PartitionCustomization) ValidatePartitionTypeID(ptType string) error {
return nil
}
// ValidatePartitionID returns an error if the partition ID is not
// valid given the partition table type. If the partition table type is an
// empty string, the function returns an error only if the partition type ID is
// invalid for both gpt and dos partition tables.
func (p *PartitionCustomization) ValidatePartitionID(ptType string) error {
// Empty PartUUID is fine, it will be selected automatically if needed
if p.PartUUID == "" {
return nil
}
if ptType == "dos" {
return fmt.Errorf("part_type is not supported for dos partition tables")
}
_, uuidErr := uuid.Parse(p.PartUUID)
if uuidErr != nil {
return fmt.Errorf("invalid partition part_uuid %q (must be a valid UUID): %w", p.PartUUID, uuidErr)
}
return nil
}
// ValidatePartitionID returns an error if the partition ID is not
// valid given the partition table type.
func (p *PartitionCustomization) ValidatePartitionLabel(ptType string) error {
// Empty PartLabel is fine
if p.PartLabel == "" {
return nil
}
if ptType == "dos" {
return fmt.Errorf("part_label is not supported for dos partition tables")
}
// GPT Labels are up to 36 utf-16 chars
if len(utf16.Encode([]rune(p.PartLabel))) > 36 {
return fmt.Errorf("part_label is not a valid GPT label, it is too long")
}
return nil
}
func (p *PartitionCustomization) validatePlain(mountpoints map[string]bool) error {
if p.FSType == "swap" {
// make sure the mountpoint is empty and return

View file

@ -192,6 +192,17 @@ type FileCustomization struct {
Mode string `json:"mode,omitempty" toml:"mode,omitempty"`
// Data is the file content in plain text
Data string `json:"data,omitempty" toml:"data,omitempty"`
// URI references the given URI, this makes the manifest alone
// no-longer portable (but future offline manifest bundles
// will fix that). It will still be reproducible as the
// manifest will include all the hashes of the content so any
// change will make the build fail.
//
// Initially only single files are supported, but this can be
// expanded to dirs (which will just be added recursively) and
// http{,s}.
URI string `json:"uri,omitempty" toml:"uri,omitempty"`
}
// Custom TOML unmarshalling for FileCustomization with validation
@ -247,6 +258,15 @@ func (f *FileCustomization) UnmarshalTOML(data interface{}) error {
return fmt.Errorf("UnmarshalTOML: data must be a string")
}
switch uri := dataMap["uri"].(type) {
case string:
file.URI = uri
case nil:
break
default:
return fmt.Errorf("UnmarshalTOML: uri must be a string")
}
// try converting to fsnode.File to validate all values
_, err := file.ToFsNodeFile()
if err != nil {
@ -293,6 +313,10 @@ func (f *FileCustomization) UnmarshalJSON(data []byte) error {
// ToFsNodeFile converts the FileCustomization to an fsnode.File
func (f FileCustomization) ToFsNodeFile() (*fsnode.File, error) {
if f.Data != "" && f.URI != "" {
return nil, fmt.Errorf("cannot specify both data %q and URI %q", f.Data, f.URI)
}
var data []byte
if f.Data != "" {
data = []byte(f.Data)
@ -308,11 +332,12 @@ func (f FileCustomization) ToFsNodeFile() (*fsnode.File, error) {
if err != nil {
return nil, fmt.Errorf("invalid mode %s: %v", f.Mode, err)
}
// modeNum is parsed as an unsigned 32 bit int
/* #nosec G115 */
mode = common.ToPtr(os.FileMode(modeNum))
}
if f.URI != "" {
return fsnode.NewFileForURI(f.Path, mode, f.User, f.Group, f.URI)
}
return fsnode.NewFile(f.Path, mode, f.User, f.Group, data)
}

View file

@ -190,6 +190,17 @@ type FileCustomization struct {
Mode string `json:"mode,omitempty" toml:"mode,omitempty"`
// Data is the file content in plain text
Data string `json:"data,omitempty" toml:"data,omitempty"`
// URI references the given URI, this makes the manifest alone
// no-longer portable (but future offline manifest bundles
// will fix that). It will still be reproducible as the
// manifest will include all the hashes of the content so any
// change will make the build fail.
//
// Initially only single files are supported, but this can be
// expanded to dirs (which will just be added recursively) and
// http{,s}.
URI string `json:"uri,omitempty" toml:"uri,omitempty"`
}
// Custom TOML unmarshalling for FileCustomization with validation
@ -245,6 +256,15 @@ func (f *FileCustomization) UnmarshalTOML(data interface{}) error {
return fmt.Errorf("UnmarshalTOML: data must be a string")
}
switch uri := dataMap["uri"].(type) {
case string:
file.URI = uri
case nil:
break
default:
return fmt.Errorf("UnmarshalTOML: uri must be a string")
}
// try converting to fsnode.File to validate all values
_, err := file.ToFsNodeFile()
if err != nil {
@ -291,6 +311,10 @@ func (f *FileCustomization) UnmarshalJSON(data []byte) error {
// ToFsNodeFile converts the FileCustomization to an fsnode.File
func (f FileCustomization) ToFsNodeFile() (*fsnode.File, error) {
if f.Data != "" && f.URI != "" {
return nil, fmt.Errorf("cannot specify both data %q and URI %q", f.Data, f.URI)
}
var data []byte
if f.Data != "" {
data = []byte(f.Data)
@ -309,6 +333,9 @@ func (f FileCustomization) ToFsNodeFile() (*fsnode.File, error) {
mode = common.ToPtr(os.FileMode(modeNum))
}
if f.URI != "" {
return fsnode.NewFileForURI(f.Path, mode, f.User, f.Group, f.URI)
}
return fsnode.NewFile(f.Path, mode, f.User, f.Group, data)
}

View file

@ -3,6 +3,8 @@ package fsnode
import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"os"
"github.com/osbuild/images/internal/common"
@ -11,6 +13,8 @@ import (
type File struct {
baseFsNode
data []byte
uri string
}
func (f *File) Data() []byte {
@ -41,9 +45,49 @@ func (f *File) UnmarshalYAML(unmarshal func(any) error) error {
return common.UnmarshalYAMLviaJSON(f, unmarshal)
}
func (f *File) URI() string {
return f.uri
}
// NewFile creates a new file with the given path, data, mode, user and group.
// user and group can be either a string (user name/group name), an int64 (UID/GID) or nil.
func NewFile(path string, mode *os.FileMode, user interface{}, group interface{}, data []byte) (*File, error) {
return newFile(path, mode, user, group, data, "")
}
// NewFleForURI creates a new file from the given "URI" (currently
// only local file are supported).
func NewFileForURI(targetPath string, mode *os.FileMode, user interface{}, group interface{}, uriStr string) (*File, error) {
uri, err := url.Parse(uriStr)
if err != nil {
return nil, err
}
switch uri.Scheme {
case "", "file":
return newFileForURILocalFile(targetPath, mode, user, group, uri)
default:
return nil, fmt.Errorf("unsupported scheme for %v (try file://)", uri)
}
}
func newFileForURILocalFile(targetPath string, mode *os.FileMode, user interface{}, group interface{}, uri *url.URL) (*File, error) {
st, err := os.Stat(uri.Path)
if err != nil {
return nil, fmt.Errorf("cannot include blueprint file: %w", err)
}
if !st.Mode().IsRegular() {
return nil, fmt.Errorf("%s is not a regular file", uri.Path)
}
if mode == nil {
mode = common.ToPtr(st.Mode())
}
// note that user/group are not take from the local file, just
// default to unset which means root
return newFile(targetPath, mode, user, group, nil, uri.Path)
}
func newFile(path string, mode *os.FileMode, user interface{}, group interface{}, data []byte, uri string) (*File, error) {
baseNode, err := newBaseFsNode(path, mode, user, group)
if err != nil {
@ -53,5 +97,6 @@ func NewFile(path string, mode *os.FileMode, user interface{}, group interface{}
return &File{
baseFsNode: *baseNode,
data: data,
uri: uri,
}, nil
}

View file

@ -1,13 +1,14 @@
distros:
- &fedora_rawhide
name: fedora-43
distro_like: fedora
preview: true
os_version: 43
release_version: 43
module_platform_id: platform:f43
product: "Fedora"
ostree_ref_tmpl: "fedora/43/%s/iot"
iso_label_tmpl: "{{.Product}}-{{.OsVersion}}-{{.ISOLabel}}-{{.Arch}}"
iso_label_tmpl: "{{.Product}}-{{.Distro.MajorVersion}}-{{.ISOLabel}}-{{.Arch}}"
default_fs_type: "ext4"
defs_path: fedora
runner: &fedora_runner
@ -50,7 +51,7 @@ distros:
ostree_ref_tmpl: "fedora/{{.MajorVersion}}/%s/iot"
runner:
<<: *fedora_runner
name: org.osbuild.fedora{{.MajorVersion}}
name: "org.osbuild.fedora{{.MajorVersion}}"
bootstrap_containers:
x86_64: "registry.fedoraproject.org/fedora-toolbox:{{.MajorVersion}}"
aarch64: "registry.fedoraproject.org/fedora-toolbox:{{.MajorVersion}}"
@ -59,3 +60,114 @@ distros:
# XXX: remove once fedora containers are part of the upstream
# fedora registry (and can be validated via tls)
riscv64: "ghcr.io/mvo5/fedora-buildroot:{{.MajorVersion}}"
- &rhel10
name: "rhel-{{.MajorVersion}}.{{.MinorVersion}}"
match: "rhel-10.[0-9]{,[0-9]}"
distro_like: rhel-10
product: "Red Hat Enterprise Linux"
os_version: "10.{{.MinorVersion}}"
release_version: 10
module_platform_id: "platform:el10"
vendor: "redhat"
ostree_ref_tmpl: "rhel/10/%s/edge"
default_fs_type: "xfs"
defs_path: rhel-10
iso_label_tmpl: "RHEL-{{.Distro.MajorVersion}}-{{.Distro.MinorVersion}}-0-BaseOS-{{.Arch}}"
runner:
name: "org.osbuild.rhel{{.MajorVersion}}{{.MinorVersion}}"
build_packages: &rhel_runner_build_packages
- "glibc" # ldconfig
- "platform-python" # osbuild
- "systemd" # systemd-tmpfiles and systemd-sysusers
- "python3" # osbuild stages
# rhel9 & cs9 share the same list
# of allowed profiles so a single
# allow list can be used
oscap_profiles_allowlist: &oscap_profile_allowlist_rhel10
- "xccdf_org.ssgproject.content_profile_anssi_bp28_enhanced"
- "xccdf_org.ssgproject.content_profile_anssi_bp28_high"
- "xccdf_org.ssgproject.content_profile_anssi_bp28_intermediary"
- "xccdf_org.ssgproject.content_profile_anssi_bp28_minimal"
- "xccdf_org.ssgproject.content_profile_cis"
- "xccdf_org.ssgproject.content_profile_cis_server_l1"
- "xccdf_org.ssgproject.content_profile_cis_workstation_l1"
- "xccdf_org.ssgproject.content_profile_cis_workstation_l2"
- "xccdf_org.ssgproject.content_profile_cui"
- "xccdf_org.ssgproject.content_profile_e8"
- "xccdf_org.ssgproject.content_profile_hipaa"
- "xccdf_org.ssgproject.content_profile_ism_o"
- "xccdf_org.ssgproject.content_profile_ospp"
- "xccdf_org.ssgproject.content_profile_pci-dss"
- "xccdf_org.ssgproject.content_profile_stig"
- "xccdf_org.ssgproject.content_profile_stig_gui"
- <<: *rhel10
name: "almalinux-{{.MajorVersion}}.{{.MinorVersion}}"
match: "almalinux-10.[0-9]{,[0-9]}"
product: "AlmaLinux"
vendor: "almalinux"
ostree_ref_tmpl: "almalinux/10/%%s/edge"
iso_label_tmpl: "AlmaLinux-{{.Distro.MajorVersion}}-{{.Distro.MinorVersion}}-{{.Arch}}-dvd"
- &centos10
name: centos-10
distro_like: rhel-10
product: "CentOS Stream"
os_version: "10-stream"
release_version: 10
module_platform_id: "platform:el10"
vendor: "centos"
ostree_ref_tmpl: "rhel/10/%s/edge"
default_fs_type: "xfs"
defs_path: rhel-10
iso_label_tmpl: "CentOS-Stream-{{.Distro.MajorVersion}}-BaseOS-{{.Arch}}"
ignore_image_types:
- azure-cvm
- azure-rhui
- azure-sap-rhui
- azure-sapapps-rhui
- ec2
- ec2-sap
- ec2-ha
runner:
name: org.osbuild.centos10
build_packages:
- "glibc" # ldconfig
- "platform-python" # osbuild
- "systemd" # systemd-tmpfiles and systemd-sysusers
- "python3" # osbuild stages
oscap_profiles_allowlist: *oscap_profile_allowlist_rhel10
- <<: *centos10
name: "almalinux_kitten-10"
product: "AlmaLinux Kitten"
os_version: "10-kitten"
release_version: 10
module_platform_id: "platform:el10"
vendor: "almalinux"
ostree_ref_tmpl: "almalinux/10/%s/edge"
- &rhel7
name: "rhel-{{.MajorVersion}}.{{.MinorVersion}}"
match: "rhel-7.[0-9]{,[0-9]}"
distro_like: rhel-7
product: "Red Hat Enterprise Linux"
codename: "Maipo"
os_version: "7.{{.MinorVersion}}"
release_version: 7
module_platform_id: "platform:el7"
vendor: "redhat"
ostree_ref_tmpl: "rhel/7/%s/edge"
default_fs_type: "xfs"
defs_path: rhel-7
runner:
name: "org.osbuild.rhel{{.MajorVersion}}{{.MinorVersion}}"
build_packages: &rhel_runner_build_packages
- "glibc" # ldconfig
# The RHEL 8 runner in osbuild runs with platform-python but
# explicitly symlinks python 3.6 to /etc/alternatives (which in turn
# is the target for /usr/bin/python3) for the stages.
# https://github.com/osbuild/osbuild/blob/ea8261cad6c5c606c00c0f2824c3f483c01a0cc9/runners/org.osbuild.rhel82#L61
# Install python36 explicitly for RHEL 8.
- "python36"

View file

@ -173,16 +173,13 @@
"f41 dracut requires ifcfg, rootfs is squashfs":
when:
version_equal: "41"
override:
additional_anaconda_modules: *install_config_additional_anaconda_modules
shallow_merge:
additional_dracut_modules:
- "ifcfg"
squashfs_rootfs: true
"f40 and lower uses ifcfg in dracut and squashfs+ext4 rootfs":
when:
version_less_than: "41"
override:
additional_anaconda_modules: *install_config_additional_anaconda_modules
shallow_merge:
additional_dracut_modules:
- "ifcfg"
squashfs_rootfs: false
@ -1600,11 +1597,19 @@ image_types:
- "net-lib"
- "dbus-broker"
squashfs_rootfs: true
# NOTE: this is not supported right now because the
# image-installer on Fedora isn't working when unattended.
# These options are probably necessary but could change.
# Unattended/non-interactive installations are better set to text,
# since they might be running headless and a UI is unnecessary.
kickstart_unattended_extra_kernel_opts:
- "inst.text"
- "inst.noninteractive"
conditions:
"on f40 we use ifcfg instead of net-lib":
when:
version_equal: "40"
override:
shallow_merge:
additional_dracut_modules: &additional_dracut_f40
- "ifcfg"
- "dbus-broker"
@ -1612,9 +1617,8 @@ image_types:
"on f41 use squashfs_rootfs":
when:
version_equal: "41"
override:
shallow_merge:
additional_dracut_modules: *additional_dracut_f40
squashfs_rootfs: true
image_config:
locale: "en_US.UTF-8"
iso_rootfs_type: "squashfs"

View file

@ -9,6 +9,7 @@ import (
"io/fs"
"os"
"path/filepath"
"slices"
"sort"
"text/template"
@ -22,7 +23,9 @@ import (
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/experimentalflags"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/olog"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/images/pkg/runner"
@ -96,6 +99,15 @@ type DistroYAML struct {
imageTypes map[string]ImageTypeYAML
// distro wide default image config
imageConfig *distro.ImageConfig `yaml:"default"`
// ignore the given image types
IgnoreImageTypes []string `yaml:"ignore_image_types"`
// XXX: remove this in favor of a better abstraction, this
// is currently needed because the manifest pkg has conditionals
// based on the distro, ideally it would not have this but
// here we are.
DistroLike manifest.Distro `yaml:"distro_like"`
}
func (d *DistroYAML) ImageTypes() map[string]ImageTypeYAML {
@ -204,8 +216,14 @@ func NewDistroYAML(nameVer string) (*DistroYAML, error) {
if len(toplevel.ImageTypes) > 0 {
foundDistro.imageTypes = make(map[string]ImageTypeYAML, len(toplevel.ImageTypes))
for name := range toplevel.ImageTypes {
if slices.Contains(foundDistro.IgnoreImageTypes, name) {
continue
}
v := toplevel.ImageTypes[name]
v.name = name
if err := v.runTemplates(foundDistro); err != nil {
return nil, err
}
foundDistro.imageTypes[name] = v
}
}
@ -338,6 +356,11 @@ type ImageTypeYAML struct {
NameAliases []string `yaml:"name_aliases"`
// for RHEL7 compat
// TODO: determine a better place for these options, but for now they are here
DiskImagePartTool *osbuild.PartTool `yaml:"disk_image_part_tool"`
DiskImageVPCForceSize *bool `yaml:"disk_image_vpc_force_size"`
// name is set by the loader
name string
}
@ -346,6 +369,34 @@ func (it *ImageTypeYAML) Name() string {
return it.name
}
func (it *ImageTypeYAML) runTemplates(distro *DistroYAML) error {
var data any
// set the DistroVendor in the struct only if its actually
// set, this ensures that the template execution fails if the
// template is used by the user has not set it
if distro.Vendor != "" {
data = struct {
DistroVendor string
}{
DistroVendor: distro.Vendor,
}
}
for idx := range it.Platforms {
// fill the UEFI vendor string
templ, err := template.New("uefi-vendor").Parse(it.Platforms[idx].UEFIVendor)
templ.Option("missingkey=error")
if err != nil {
return fmt.Errorf(`cannot parse template for "vendor" field: %w`, err)
}
var buf bytes.Buffer
if err := templ.Execute(&buf, data); err != nil {
return fmt.Errorf(`cannot execute template for "vendor" field (is it set?): %w`, err)
}
it.Platforms[idx].UEFIVendor = buf.String()
}
return nil
}
type imageConfig struct {
*distro.ImageConfig `yaml:",inline"`
Conditions map[string]*conditionsImgConf `yaml:"conditions,omitempty"`
@ -362,8 +413,8 @@ type installerConfig struct {
}
type conditionsInstallerConf struct {
When whenCondition `yaml:"when,omitempty"`
Override *distro.InstallerConfig `yaml:"override,omitempty"`
When whenCondition `yaml:"when,omitempty"`
ShallowMerge *distro.InstallerConfig `yaml:"shallow_merge,omitempty"`
}
type packageSet struct {
@ -502,7 +553,7 @@ func (imgType *ImageTypeYAML) InstallerConfig(distroNameVer, archName string) (*
for _, cond := range condMap {
if cond.When.Eval(id, archName) {
installerConfig = cond.Override
installerConfig = cond.ShallowMerge.InheritFrom(installerConfig)
}
}
}

View file

@ -32,6 +32,97 @@
- "grub2-ppc64le"
- "grub2-ppc64le-modules"
disk_sizes:
default_required_partition_sizes: &default_required_dir_sizes
"/": 1_073_741_824 # 1 * datasizes.GiB
"/usr": 2_147_483_648 # 2 * datasizes.GiB
platforms:
x86_64_uefi_platform: &x86_64_uefi_platform
arch: "x86_64"
bootloader: "grub2"
uefi_vendor: "{{.DistroVendor}}"
qcow2_compat: "1.1"
packages: &x86_64_uefi_platform_packages
uefi:
- "dracut-config-generic"
- "efibootmgr"
- "grub2-efi-x64"
- "shim-x64"
x86_64_bios_platform: &x86_64_bios_platform
<<: *x86_64_uefi_platform
bios_platform: "i386-pc"
uefi_vendor: "{{.DistroVendor}}"
packages: &x86_64_bios_platform_packages
<<: *x86_64_uefi_platform_packages
bios:
- "dracut-config-generic"
- "grub2-pc"
build_packages:
bios:
- "grub2-pc"
x86_64_installer_platform: &x86_64_installer_platform
<<: *x86_64_bios_platform
image_format: "raw"
packages:
<<: *x86_64_bios_platform_packages
firmware:
- "microcode_ctl" # ??
- "iwl1000-firmware"
- "iwl100-firmware"
- "iwl105-firmware"
- "iwl135-firmware"
- "iwl2000-firmware"
- "iwl2030-firmware"
- "iwl3160-firmware"
- "iwl5000-firmware"
- "iwl5150-firmware"
- "iwl6050-firmware"
aarch64_platform: &aarch64_platform
arch: "aarch64"
bootloader: "grub2"
uefi_vendor: "{{.DistroVendor}}"
image_format: "qcow2"
qcow2_compat: "1.1"
packages: &aarch64_uefi_platform_packages
uefi:
- "dracut-config-generic"
- "efibootmgr"
- "grub2-efi-aa64"
- "grub2-tools"
- "shim-aa64"
ppc64le_bios_platform: &ppc64le_bios_platform
arch: "ppc64le"
bootloader: "grub2"
bios_platform: "powerpc-ieee1275"
image_format: "qcow2"
qcow2_compat: "1.1"
packages:
bios:
- "dracut-config-generic"
- "powerpc-utils"
- "grub2-ppc64le"
- "grub2-ppc64le-modules"
build_packages:
bios:
- "grub2-ppc64le"
- "grub2-ppc64le-modules"
s390x_zipl_platform: &s390x_zipl_platform
arch: "s390x"
# XXX: merge zipl_support/bootloader
bootloader: "zipl"
zipl_support: true
image_format: "qcow2"
qcow2_compat: "1.1"
packages:
zipl:
- "dracut-config-generic"
- "s390utils-base"
- "s390utils-core"
build_packages:
zipl:
- "s390utils-base"
sapapps_image_config: &sapapps_image_config
selinux_config:
state: "permissive"
@ -603,6 +694,26 @@ image_types:
- "subscription-manager-cockpit"
qcow2: &qcow2
filename: "disk.qcow2"
mime_type: "application/x-qemu-disk"
# note that unlike fedora rhel does not use the environment.KVM
# for unknown reasons
bootable: true
default_size: 10_737_418_240 # 10 * datasizes.GibiByte
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "qcow2"]
exports: ["qcow2"]
required_partition_sizes: *default_required_dir_sizes
platforms:
- <<: *x86_64_bios_platform
image_format: "qcow2"
- <<: *aarch64_platform
image_format: "qcow2"
- <<: *ppc64le_bios_platform
image_format: "qcow2"
- <<: *s390x_zipl_platform
image_format: "qcow2"
image_config: &qcow2_image_config
default_target: "multi-user.target"
kernel_options: ["console=tty0", "console=ttyS0,115200n8", "no_timer_check"]
@ -690,6 +801,22 @@ image_types:
"vagrant-libvirt":
<<: *qcow2
filename: "vagrant-libvirt.box"
mime_type: "application/x-tar"
bootable: true
default_size: 10_737_418_240 # 10 * datasizes.GibiByte
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "vagrant", "archive"]
exports: ["archive"]
required_partition_sizes: *default_required_dir_sizes
platforms:
- <<: *x86_64_bios_platform
image_format: "vagrant_libvirt"
qcow2_compat: ""
- <<: *aarch64_platform
image_format: "vagrant_libvirt"
qcow2_compat: ""
image_config:
<<: *qcow2_image_config
users:
@ -707,9 +834,26 @@ image_types:
data: |
vagrant ALL=(ALL) NOPASSWD: ALL
oci: *qcow2
oci:
<<: *qcow2
platforms:
- <<: *x86_64_bios_platform
image_format: "qcow2"
vhd: &vhd
<<: *qcow2
filename: "disk.vhd"
mime_type: "application/x-vhd"
default_size: 4_294_967_296 # 4 * datasizes.GibiByte
payload_pipelines: ["os", "image", "vpc"]
exports: ["vpc"]
# note that unlike fedora no "environment.Azure" is used here for
# unknown reasons
platforms:
- <<: *x86_64_bios_platform
image_format: "vhd"
- <<: *aarch64_platform
image_format: "vhd"
# 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
image_config: &image_config_vhd
<<: *azure_image_config
@ -822,6 +966,10 @@ image_types:
"azure-rhui": &azure_rhui
<<: *vhd
payload_pipelines: ["os", "image", "vpc", "xz"]
exports: ["xz"]
compression: "xz"
filename: "disk.vhd.xz"
partition_table:
x86_64:
uuid: "D209C89E-EA5E-4FBD-B161-B461CCE297E0"
@ -916,6 +1064,9 @@ image_types:
"azure-sap-rhui":
<<: *azure_rhui
platforms:
- <<: *x86_64_bios_platform
image_format: "vhd"
image_config:
<<: [*image_config_vhd, *sap_image_config]
package_sets:
@ -926,6 +1077,9 @@ image_types:
azure-sapapps-rhui:
<<: *azure_rhui
platforms:
- <<: *x86_64_bios_platform
image_format: "vhd"
image_config:
<<: [*image_config_vhd, *sapapps_image_config]
package_sets:
@ -934,6 +1088,12 @@ image_types:
- *sap_base_pkgset
tar:
filename: "root.tar.xz"
mime_type: "application/x-tar"
image_func: "tar"
build_pipelines: ["build"]
payload_pipelines: ["os", "archive"]
exports: ["archive"]
package_sets:
os:
- include:
@ -941,8 +1101,25 @@ image_types:
- "selinux-policy-targeted"
exclude:
- "rng-tools"
platforms:
- arch: "x86_64"
- arch: "aarch64"
- arch: "ppc64le"
- arch: "s390x"
vmdk: &vmdk
filename: "disk.vmdk"
mime_type: "application/x-vmdk"
bootable: true
default_size: 4_294_967_296 # 4 * datasizes.GibiByte
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "vmdk"]
exports: ["vmdk"]
required_partition_sizes: *default_required_dir_sizes
platforms:
- <<: *x86_64_bios_platform
image_format: "vmdk"
image_config:
kernel_options:
- "ro"
@ -962,9 +1139,31 @@ image_types:
- "dracut-config-rescue"
- "rng-tools"
ova: *vmdk
ova:
<<: *vmdk
filename: "image.ova"
mime_type: "application/ovf"
payload_pipelines: ["os", "image", "vmdk", "ovf", "archive"]
exports: ["archive"]
platforms:
- <<: *x86_64_bios_platform
image_format: "ova"
ami: &ami
filename: "image.raw"
mime_type: "application/octet-stream"
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image"]
exports: ["image"]
bootable: true
default_size: 10_737_418_240 # 10 * datasizes.GibiByte
required_partition_sizes: *default_required_dir_sizes
platforms:
- <<: *x86_64_bios_platform
image_format: "raw"
- <<: *aarch64_platform
image_format: "raw"
image_config: &ami_image_config
time_synchronization:
servers:
@ -1124,10 +1323,21 @@ image_types:
conditions:
<<: *conditions_pkgsets_insights_client_on_rhel
ec2: *ami
# RHEL internal-only x86_64 EC2 image type
ec2: &ec2
<<: *ami
payload_pipelines: ["os", "image", "xz"]
exports: ["xz"]
filename: "image.raw.xz"
compression: "xz"
"ec2-ha":
<<: *ami
<<: *ec2
filename: "image.raw.xz"
compression: "xz"
platforms:
- <<: *x86_64_bios_platform
image_format: "raw"
package_sets:
os:
- *ami_pkgset
@ -1137,7 +1347,12 @@ image_types:
- "pcs"
"ec2-sap":
<<: *ami
<<: *ec2
filename: "image.raw.xz"
compression: "xz"
platforms:
- <<: *x86_64_bios_platform
image_format: "raw"
package_sets:
os:
- *ami_pkgset
@ -1164,6 +1379,16 @@ image_types:
- "intel_idle.max_cstate=1"
wsl:
filename: "image.wsl"
mime_type: "application/x-tar"
image_func: "tar"
build_pipelines: ["build"]
payload_pipelines: ["os", "archive", "xz"]
exports: ["xz"]
compression: "xz"
platforms:
- arch: "x86_64"
- arch: "aarch64"
image_config:
cloud_init:
- filename: "99_wsl.cfg"
@ -1282,6 +1507,36 @@ image_types:
- "rpm-plugin-systemd-inhibit"
"image-installer":
filename: "installer.iso"
mime_type: "application/x-iso9660-image"
bootable: true
boot_iso: true
image_func: "image_installer"
# We don't know the variant of the OS pipeline being installed
iso_label: "Unknown"
build_pipelines: ["build"]
payload_pipelines:
- "anaconda-tree"
- "efiboot-tree"
- "os"
- "bootiso-tree"
- "bootiso"
exports: ["bootiso"]
required_partition_sizes: *default_required_dir_sizes
image_config:
iso_rootfs_type: "squashfs"
installer_config:
additional_dracut_modules:
- "nvdimm" # non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
- "net-lib"
additional_drivers:
- "ipmi_devintf"
- "ipmi_msghandler"
# see commit c6bfb22f54, controls the kickstart location
iso_root_kickstart: true
platforms:
- *x86_64_installer_platform
- *aarch64_platform
package_sets:
<<: *bare_metal_pkgset
installer:
@ -1414,6 +1669,18 @@ image_types:
- "dmidecode"
gce:
filename: "image.tar.gz"
mime_type: "application/gzip"
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "archive"]
exports: ["archive"]
bootable: true
default_size: 21_474_836_480 # 20 * datasizes.GibiByte
required_partition_sizes: *default_required_dir_sizes
platforms:
- <<: *x86_64_uefi_platform
image_format: "gce"
image_config:
kernel_options: ["biosdevname=0", "scsi_mod.use_blk_mq=Y", "console=ttyS0,38400n8d"]
time_synchronization:
@ -1486,6 +1753,8 @@ image_types:
"InstanceSetup":
set_boto_config: false
partition_table:
# TODO: the base partition table still contains the BIOS boot
# partition, but the image is UEFI-only
<<: *default_partition_tables
package_sets:
os:
@ -1569,6 +1838,24 @@ image_types:
<<: *conditions_pkgsets_insights_client_on_rhel
"azure-cvm":
<<: *vhd
filename: "disk.vhd.xz"
mime_type: "application/xz"
payload_pipelines: ["os", "image", "vpc", "xz"]
exports: ["xz"]
compression: "xz"
default_size: 34_359_738_368 # 32 * datasizes.GibiByte
platforms:
- arch: "x86_64"
bootloader: "uki"
image_format: "vhd"
uefi_vendor: "{{.DistroVendor}}"
packages:
uki:
- "efibootmgr"
- "kernel-uki-virt-addons" # provides useful cmdline utilities for the UKI
- "shim-x64"
- "uki-direct"
image_config:
<<: *azure_image_config
default_kernel: "kernel-uki-virt"

View file

@ -56,6 +56,7 @@
- &efi_system_partition_guid "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
- &filesystem_data_guid "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
- &xboot_ldr_partition_guid "BC13C2FF-59E6-4262-A352-B275FD6F7172"
- &lvm_partition_guid "E6D6D379-F507-44C2-A23C-238F2A3DF928"
# static UUIDs for partitions and filesystems
# NOTE(akoutsou): These are unnecessary and have stuck around since the
# beginning where (I believe) the goal was to have predictable,
@ -74,7 +75,8 @@
uuid: "D209C89E-EA5E-4FBD-B161-B461CCE297E0"
type: "gpt"
partitions:
- size: "1 MiB"
- &bios_boot_partition
size: "1 MiB"
bootable: true
type: *bios_boot_partition_guid
uuid: *bios_boot_partition_uuid
@ -115,7 +117,127 @@
fstab_options: "defaults"
fstab_freq: 0
fstab_passno: 0
ec2_partition_tables: &ec2_partition_tables
x86_64:
uuid: "D209C89E-EA5E-4FBD-B161-B461CCE297E0"
type: "gpt"
size: "10 GiB"
partitions:
- *bios_boot_partition
- size: 6_442_450_944 # 6144 * datasizes.MebiByte
type: *filesystem_data_guid
uuid: *root_partition_uuid
payload_type: "filesystem"
payload:
<<: *default_partition_table_part_root_payload
azure_rhui_partition_tables: &azure_rhui_partition_tables
x86_64:
uuid: "D209C89E-EA5E-4FBD-B161-B461CCE297E0"
type: "gpt"
size: "64 GiB"
partitions:
- &azure_rhui_part_boot_efi
size: 524_288_000 # 500 * datasizes.MebiByte
type: *efi_system_partition_guid
UUID: *efi_system_partition_uuid
payload_type: "filesystem"
payload:
type: "vfat"
uuid: *efi_filesystem_uuid
mountpoint: "/boot/efi"
fstab_options: "defaults,uid=0,gid=0,umask=077,shortname=winnt"
fstab_freq: 0
fstab_passno: 2
- &azure_rhui_part_boot
size: "500 MiB"
type: *filesystem_data_guid
uuid: *data_partition_uuid
payload_type: "filesystem"
payload:
type: "xfs"
mountpoint: "/boot"
fstab_options: "defaults"
fstab_freq: 0
fstab_passno: 0
- size: "2 MiB"
bootable: true
type: *bios_boot_partition_guid
uuid: *bios_boot_partition_uuid
- &azure_rhui_part_lvm
type: *lvm_partition_guid
uuid: *root_partition_uuid
payload_type: "lvm"
payload:
name: "rootvg"
description: "built with lvm2 and osbuild"
logical_volumes:
- size: "1 GiB"
name: "homelv"
payload_type: "filesystem"
payload:
type: "xfs"
label: "home"
mountpoint: "/home"
fstab_options: "defaults"
- size: "2 GiB"
name: "rootlv"
payload_type: "filesystem"
payload:
type: "xfs"
label: "root"
mountpoint: "/"
fstab_options: "defaults"
- size: "2 GiB"
name: "tmplv"
payload_type: "filesystem"
payload:
type: "xfs"
label: "tmp"
mountpoint: "/tmp"
fstab_options: "defaults"
- size: "10 GiB"
name: "usrlv"
payload_type: "filesystem"
payload:
type: "xfs"
label: "usr"
mountpoint: "/usr"
fstab_options: "defaults"
- size: "10 GiB"
name: "varlv"
payload_type: "filesystem"
payload:
type: "xfs"
label: "var"
mountpoint: "/var"
fstab_options: "defaults"
disk_sizes:
default_required_partition_sizes: &default_required_dir_sizes
"/": 1_073_741_824 # 1 * datasizes.GiB
"/usr": 2_147_483_648 # 2 * datasizes.GiB
platforms:
x86_64_bios_platform: &x86_64_bios_platform
arch: "x86_64"
bootloader: "grub2"
bios_platform: "i386-pc"
packages: &x86_64_bios_platform_packages
bios:
- "dracut-config-generic"
- "grub2-pc"
build_packages:
bios:
- "grub2-pc"
x86_64_uefi_vendor_platform: &x86_64_uefi_vendor_platform
<<: *x86_64_bios_platform
uefi_vendor: "{{.DistroVendor}}"
packages:
<<: *x86_64_bios_platform_packages
uefi_vendor:
- "efibootmgr"
- "grub2-efi-x64"
- "shim-x64"
image_config:
default:
@ -136,15 +258,265 @@ image_config:
image_types:
"azure-rhui":
filename: "disk.vhd.xz"
mime_type: "application/xz"
image_func: "disk"
default_size: 68_719_476_736 # 64 * datasizes.GibiByte
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "vpc", "xz"]
exports: ["xz"]
compression: "xz"
bootable: true
# RHEL 7 qemu vpc subformat does not support force_size
disk_image_vpc_force_size: false
platforms:
- <<: *x86_64_uefi_vendor_platform
image_format: "vhd"
image_config:
timezone: "Etc/UTC"
locale: "en_US.UTF-8"
gpgkey_files:
- "/etc/pki/rpm-gpg/RPM-GPG-KEY-microsoft-azure-release"
- "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
selinux_force_relabel: true
authconfig: {}
update_default_kernel: true
default_kernel: "kernel-core"
sysconfig:
networking: true
no_zero_conf: true
enabled_services:
- "cloud-config"
- "cloud-final"
- "cloud-init-local"
- "cloud-init"
- "firewalld"
- "NetworkManager"
- "sshd"
- "waagent"
sshd_config:
config:
ClientAliveInterval: 180
modprobe:
- filename: "blacklist-amdgpu.conf"
commands:
- command: blacklist
modulename: "amdgpu"
- filename: "blacklist-intel-cstate.conf"
commands:
- command: blacklist
modulename: "intel_cstate"
- filename: "blacklist-floppy.conf"
commands:
- command: blacklist
modulename: "floppy"
- filename: "blacklist-nouveau.conf"
commands:
- command: blacklist
modulename: "nouveau"
- command: blacklist
modulename: "lbm-nouveau"
- filename: "blacklist-skylake-edac.conf"
commands:
- command: blacklist
modulename: "skx_edac"
cloud_init:
- filename: "06_logging_override.cfg"
config:
output:
all: "| tee -a /var/log/cloud-init-output.log"
- filename: "10-azure-kvp.cfg"
config:
reporting:
logging:
type: "log"
telemetry:
type: "hyperv"
- filename: "91-azure_datasource.cfg"
config:
datasource:
azure:
apply_network_config: false
datasource_list:
- "Azure"
pwquality:
config:
minlen: 6
minclass: 3
dcredit: 0
ucredit: 0
lcredit: 0
ocredit: 0
waagent_config:
config:
"ResourceDisk.Format": false
"ResourceDisk.EnableSwap": false
rhsm_config:
"no-subscription":
yum_plugin:
subscription_manager:
enabled: false
subman:
rhsmcertd:
auto_registration: true
rhsm:
manage_repos: false
"with-subscription":
subman:
rhsmcertd:
auto_registration: true
# do not disable the redhat.repo management if the user
# explicitly request the system to be subscribed
grub2_config:
terminal_input: ["serial", "console"]
terminal_output: ["serial", "console"]
serial: "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
timeout: 10
udev_rules:
filename: "/etc/udev/rules.d/68-azure-sriov-nm-unmanaged.rules"
rules:
- comment:
- "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."
- rule:
- K: "SUBSYSTEM"
O: "=="
V: "net"
- K: "DRIVERS"
O: "=="
V: "hv_pci"
- K: "ACTION"
O: "=="
V: "add"
- K: "ENV"
A: "NM_UNMANAGED"
O: "="
V: "1"
yum_config:
config:
http_caching: "packages"
plugins:
langpacks:
locales: ["en_US.UTF-8"]
default_target: "multi-user.target"
kernel_options:
- "ro"
- "crashkernel=auto"
- "console=tty1"
- "console=ttyS0"
- "earlyprintk=ttyS0"
- "rootdelay=300"
- "scsi_mod.use_blk_mq=y"
disk_image_part_tool: sgdisk
partition_table:
<<: *default_partition_tables
<<: *azure_rhui_partition_tables
package_sets:
os:
- *azure_rhui_common_pkgset
ec2:
filename: "image.raw.xz"
mime_type: "application/xz"
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "xz"]
exports: ["xz"]
compression: "xz"
bootable: true
default_size: 10_737_418_240 # 10 * datasizes.GibiByte
required_partition_sizes: *default_required_dir_sizes
platforms:
- <<: *x86_64_bios_platform
image_format: "raw"
image_config:
files:
# systemd-firstboot on el7 does not support --keymap option
- path: "/etc/vconsole.conf"
data: |
FONT=latarcyrheb-sun16
KEYMAP=us
# This is needed to disable predictable network interface names.
# The org.osbuild.udev.rules stage can't create empty files.
- path: "/etc/udev/rules.d/80-net-name-slot.rules"
data: ""
# While cloud-init does this automatically on first boot for the specified user
# this was in the original KS.
- path: "/etc/sudoers.d/ec2-user"
mode: 0440
data: "ec2-user\tALL=(ALL)\tNOPASSWD: ALL\n"
# The image built from the original KS has this file with this content.
- path: "/etc/hostname"
data: "localhost.localdomain\n"
timezone: "UTC"
time_synchronization:
servers:
- hostname: "0.rhel.pool.ntp.org"
iburst: true
- hostname: "1.rhel.pool.ntp.org"
iburst: true
- hostname: "2.rhel.pool.ntp.org"
iburst: true
- hostname: "3.rhel.pool.ntp.org"
iburst: true
- hostname: "169.254.169.123"
prefer: true
iburst: true
minpoll: 4
maxpoll: 4
# empty string will remove any occurrences of the option from the configuration
leapsectz: ""
enabled_services:
- "sshd"
- "rsyslog"
default_target: "multi-user.target"
update_default_kernel: true
default_kernel: "kernel"
sysconfig:
networking: true
no_zero_conf: true
create_default_network_scripts: true
systemd_logind:
- filename: "logind.conf"
config:
login:
nautovts: 0
cloud_init:
- filename: "00-rhel-default-user.cfg"
config:
system_info:
default_user:
name: "ec2-user"
- filename: "99-datasource.cfg"
config:
datasource_list:
- "Ec2"
- "None"
modprobe:
- filename: "blacklist-nouveau.conf"
commands:
- command: blacklist
modulename: "nouveau"
dracut_conf:
- filename: "sgdisk.conf"
config:
install: ["sgdisk"]
sshd_config:
config:
PasswordAuthentication: false
selinux_force_relabel: true
kernel_options:
- "ro"
- "console=tty0"
- "console=ttyS0,115200n8"
- "net.ifnames=0"
- "rd.blacklist=nouveau"
- "nvme_core.io_timeout=4294967295"
- "crashkernel=auto"
- "LANG=en_US.UTF-8"
disk_image_part_tool: "sgdisk"
partition_table:
<<: *default_partition_tables
<<: *ec2_partition_tables
package_sets:
os:
- include:
@ -199,6 +571,42 @@ image_types:
- "firewalld"
qcow2:
filename: "disk.qcow2"
mime_type: "application/x-qemu-disk"
bootable: true
default_size: 10_737_418_240 # 10 * datasizes.GibiByte
image_func: "disk"
build_pipelines: ["build"]
payload_pipelines: ["os", "image", "qcow2"]
exports: ["qcow2"]
required_partition_sizes: *default_required_dir_sizes
disk_image_part_tool: sgdisk
platforms:
- <<: *x86_64_uefi_vendor_platform
image_format: "qcow2"
qcow2_compat: "0.10"
image_config:
default_target: "multi-user.target"
selinux_force_relabel: true
update_default_kernel: true
default_kernel: "kernel"
kernel_options:
- "console=tty0"
- "console=ttyS0,115200n8"
- "no_timer_check"
- "net.ifnames=0"
- "crashkernel=auto"
sysconfig:
networking: true
no_zero_conf: true
create_default_network_scripts: true
rhsm_config:
"no-subscription":
yum_plugin:
product_id:
enabled: false
subscription_manager:
enabled: false
partition_table:
<<: *default_partition_tables
package_sets:

View file

@ -49,20 +49,22 @@ type distribution struct {
}
func (d *distribution) getISOLabelFunc(isoLabel string) isoLabelFunc {
id := common.Must(distro.ParseID(d.Name()))
return func(t *imageType) string {
type inputs struct {
Product string
OsVersion string
Arch string
ISOLabel string
Distro *distro.ID
Product string
Arch string
ISOLabel string
}
templ := common.Must(template.New("iso-label").Parse(d.DistroYAML.ISOLabelTmpl))
var buf bytes.Buffer
err := templ.Execute(&buf, inputs{
Product: t.Arch().Distro().Product(),
OsVersion: t.Arch().Distro().OsVersion(),
Arch: t.Arch().Name(),
ISOLabel: isoLabel,
Distro: id,
Product: d.Product(),
Arch: t.Arch().Name(),
ISOLabel: isoLabel,
})
if err != nil {
// XXX: cleanup isoLabelFunc to allow error

View file

@ -3,6 +3,7 @@ package generic
import (
"fmt"
"math/rand"
"strings"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/arch"
@ -15,6 +16,7 @@ import (
"github.com/osbuild/images/pkg/customizations/ignition"
"github.com/osbuild/images/pkg/customizations/kickstart"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/customizations/subscription"
"github.com/osbuild/images/pkg/customizations/users"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/image"
@ -24,13 +26,22 @@ import (
"github.com/osbuild/images/pkg/rpmmd"
)
func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []container.SourceSpec, c *blueprint.Customizations) (manifest.OSCustomizations, error) {
func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, options distro.ImageOptions, containers []container.SourceSpec, c *blueprint.Customizations) (manifest.OSCustomizations, error) {
imageConfig := t.getDefaultImageConfig()
osc := manifest.OSCustomizations{}
if t.ImageTypeYAML.Bootable || t.ImageTypeYAML.RPMOSTree {
// TODO: for now the only image types that define a default kernel are
// ones that use UKIs and don't allow overriding, so this works.
// However, if we ever need to specify default kernels for image types
// that allow overriding, we will need to change c.GetKernel() to take
// an argument as fallback or make it not return the standard "kernel"
// when it's unset.
osc.KernelName = c.GetKernel().Name
if imageConfig.DefaultKernelName != nil {
osc.KernelName = *imageConfig.DefaultKernelName
}
var kernelOptions []string
// XXX: keep in sync with the identical copy in rhel/images.go
@ -41,6 +52,9 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
kernelOptions = append(kernelOptions, bpKernel.Append)
}
osc.KernelOptionsAppend = kernelOptions
if imageConfig.KernelOptionsBootloader != nil {
osc.KernelOptionsBootloader = *imageConfig.KernelOptionsBootloader
}
}
osc.FIPS = c.GetFIPS()
@ -76,6 +90,7 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
osc.DefaultTarget = *imageConfig.DefaultTarget
}
osc.Firewall = imageConfig.Firewall
if fw := c.GetFirewall(); fw != nil {
options := osbuild.FirewallStageOptions{
Ports: fw.Ports,
@ -85,6 +100,14 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
options.EnabledServices = fw.Services.Enabled
options.DisabledServices = fw.Services.Disabled
}
if fw.Zones != nil {
for _, z := range fw.Zones {
options.Zones = append(options.Zones, osbuild.FirewallZone{
Name: *z.Name,
Sources: z.Sources,
})
}
}
osc.Firewall = &options
}
@ -98,6 +121,9 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
osc.Keyboard = keyboard
} else if imageConfig.Keyboard != nil {
osc.Keyboard = &imageConfig.Keyboard.Keymap
if imageConfig.Keyboard.X11Keymap != nil {
osc.X11KeymapLayouts = imageConfig.Keyboard.X11Keymap.Layouts
}
}
if hostname := c.GetHostname(); hostname != nil {
@ -132,6 +158,12 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
// Relabel the tree, unless the `NoSElinux` flag is explicitly set to `true`
if imageConfig.NoSElinux == nil || imageConfig.NoSElinux != nil && !*imageConfig.NoSElinux {
osc.SElinux = "targeted"
osc.SELinuxForceRelabel = imageConfig.SELinuxForceRelabel
}
// XXX: move into pure YAML
if strings.HasPrefix(t.Arch().Distro().Name(), "rhel-") && options.Facts != nil {
osc.RHSMFacts = options.Facts
}
var err error
@ -161,6 +193,9 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
if containerStorage := c.GetContainerStorage(); containerStorage != nil {
osc.ContainersStorage = containerStorage.StoragePath
}
// set yum repos first, so it doesn't get overridden by
// imageConfig.YUMRepos
osc.YUMRepos = imageConfig.YUMRepos
customRepos, err := c.GetRepositories()
if err != nil {
@ -206,8 +241,24 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
osc.OpenSCAPRemediationConfig = remediationConfig
}
osc.ShellInit = imageConfig.ShellInit
var subscriptionStatus subscription.RHSMStatus
if options.Subscription != nil {
subscriptionStatus = subscription.RHSMConfigWithSubscription
if options.Subscription.Proxy != "" {
osc.InsightsClientConfig = &osbuild.InsightsClientConfigStageOptions{Config: osbuild.InsightsClientConfig{Proxy: options.Subscription.Proxy}}
}
} else {
subscriptionStatus = subscription.RHSMConfigNoSubscription
}
if rhsmConfig, exists := imageConfig.RHSMConfig[subscriptionStatus]; exists {
osc.RHSMConfig = rhsmConfig
}
if bpRhsmConfig := subscription.RHSMConfigFromBP(c.GetRHSM()); bpRhsmConfig != nil {
osc.RHSMConfig = osc.RHSMConfig.Update(bpRhsmConfig)
}
osc.ShellInit = imageConfig.ShellInit
osc.Grub2Config = imageConfig.Grub2Config
osc.Sysconfig = imageConfig.SysconfigStageOptions()
osc.SystemdLogind = imageConfig.SystemdLogind
@ -223,9 +274,15 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
osc.PamLimitsConf = imageConfig.PamLimitsConf
osc.Sysctld = imageConfig.Sysctld
osc.DNFConfig = imageConfig.DNFConfigOptions(t.arch.distro.OsVersion())
osc.DNFAutomaticConfig = imageConfig.DNFAutomaticConfig
osc.YUMConfig = imageConfig.YumConfig
osc.SshdConfig = imageConfig.SshdConfig
osc.AuthConfig = imageConfig.Authconfig
osc.PwQuality = imageConfig.PwQuality
osc.Subscription = options.Subscription
osc.WAAgentConfig = imageConfig.WAAgentConfig
osc.UdevRules = imageConfig.UdevRules
osc.GCPGuestAgentConfig = imageConfig.GCPGuestAgentConfig
osc.NetworkManager = imageConfig.NetworkManager
if imageConfig.WSL != nil {
@ -236,6 +293,10 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
osc.Files = append(osc.Files, imageConfig.Files...)
osc.Directories = append(osc.Directories, imageConfig.Directories...)
if imageConfig.NoBLS != nil {
osc.NoBLS = *imageConfig.NoBLS
}
ca, err := c.GetCACerts()
if err != nil {
panic(fmt.Sprintf("unexpected error checking CA certs: %v", err))
@ -244,6 +305,10 @@ func osCustomizations(t *imageType, osPackageSet rpmmd.PackageSet, containers []
osc.CACerts = ca.PEMCerts
}
if imageConfig.InstallWeakDeps != nil {
osc.InstallWeakDeps = *imageConfig.InstallWeakDeps
}
if imageConfig.MachineIdUninitialized != nil {
osc.MachineIdUninitialized = *imageConfig.MachineIdUninitialized
}
@ -342,7 +407,7 @@ func diskImage(workload workload.Workload,
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}
@ -363,6 +428,18 @@ func diskImage(workload workload.Workload,
img.Filename = t.Filename()
img.VPCForceSize = t.ImageTypeYAML.DiskImageVPCForceSize
if img.OSCustomizations.NoBLS {
img.OSProduct = t.Arch().Distro().Product()
img.OSVersion = t.Arch().Distro().OsVersion()
img.OSNick = t.Arch().Distro().Codename()
}
if t.ImageTypeYAML.DiskImagePartTool != nil {
img.PartTool = *t.ImageTypeYAML.DiskImagePartTool
}
return img, nil
}
@ -378,7 +455,7 @@ func tarImage(workload workload.Workload,
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}
@ -407,7 +484,7 @@ func containerImage(workload workload.Workload,
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}
@ -492,7 +569,7 @@ func imageInstallerImage(workload workload.Workload,
img := image.NewAnacondaTarInstaller()
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}
@ -505,16 +582,6 @@ func imageInstallerImage(workload workload.Workload,
img.Kickstart.Keyboard = img.OSCustomizations.Keyboard
img.Kickstart.Timezone = &img.OSCustomizations.Timezone
if img.Kickstart.Unattended {
// NOTE: this is not supported right now because the
// image-installer on Fedora isn't working when unattended.
// These options are probably necessary but could change.
// Unattended/non-interactive installations are better set to text
// time since they might be running headless and a UI is
// unnecessary.
img.AdditionalKernelOpts = []string{"inst.text", "inst.noninteractive"}
}
instCust, err := customizations.GetInstaller()
if err != nil {
return nil, err
@ -541,6 +608,18 @@ func imageInstallerImage(workload workload.Workload,
if installerConfig.SquashfsRootfs != nil && *installerConfig.SquashfsRootfs {
img.RootfsType = manifest.SquashfsRootfs
}
if img.Kickstart.Unattended {
img.AdditionalKernelOpts = append(img.AdditionalKernelOpts, installerConfig.KickstartUnattendedExtraKernelOpts...)
}
// Put the kickstart file in the root of the iso, some image
// types (like rhel10/image-installer) put them there, some
// others (like fedora/image-installer) do not and because
// its not uniform we need to make it configurable.
// XXX: unify with rhel-11 ? or rhel-10.x?
if installerConfig.ISORootKickstart != nil {
img.ISORootKickstart = *installerConfig.ISORootKickstart
}
}
d := t.arch.distro
@ -589,7 +668,7 @@ func iotCommitImage(workload workload.Workload,
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}
@ -624,7 +703,7 @@ func bootableContainerImage(workload workload.Workload,
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}
@ -662,7 +741,7 @@ func iotContainerImage(workload workload.Workload,
img.Platform = t.platform
var err error
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.OSCustomizations, err = osCustomizations(t, packageSets[osPkgsKey], options, containers, bp.Customizations)
if err != nil {
return nil, err
}

View file

@ -303,7 +303,13 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
return nil, nil, err
}
mf := manifest.New()
mf.Distro = manifest.DISTRO_FEDORA
// TODO: remove the need for this entirely, the manifest has a
// bunch of code that checks the distro currently, ideally all
// would just be encoded in the YAML
mf.Distro = t.arch.distro.DistroYAML.DistroLike
if mf.Distro == manifest.DISTRO_NULL {
return nil, nil, fmt.Errorf("no distro_like set in yaml for %q", t.arch.distro.Name())
}
if options.UseBootstrapContainer {
mf.DistroBootstrapRef = bootstrapContainerFor(t)
}
@ -489,7 +495,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
if instCust != nil {
// only supported by the Anaconda installer
if slices.Index([]string{"iot-installer"}, t.Name()) == -1 {
if !slices.Contains([]string{"image-installer", "edge-installer", "live-installer", "iot-installer"}, t.Name()) {
return warnings, fmt.Errorf("installer customizations are not supported for %q", t.Name())
}

View file

@ -50,7 +50,7 @@ type ImageConfig struct {
// Do not use. Forces auto-relabelling on first boot.
// See https://github.com/osbuild/osbuild/commit/52cb27631b587c1df177cd17625c5b473e1e85d2
SELinuxForceRelabel *bool `yaml:"selinux_force_relabel"`
SELinuxForceRelabel *bool `yaml:"selinux_force_relabel,omitempty"`
// Disable documentation
ExcludeDocs *bool `yaml:"exclude_docs,omitempty"`
@ -140,19 +140,18 @@ type ImageConfig struct {
IsoRootfsType *manifest.RootfsType `yaml:"iso_rootfs_type,omitempty"`
}
type DNFConfig struct {
Options []*osbuild.DNFConfigStageOptions
SetReleaseVerVar *bool `yaml:"set_release_ver_var"`
}
// shallowMerge creates a new struct by merging a child and a parent.
// Only values unset in the child will be copied from the parent.
// It is not recursive.
//
// Returns a pointer to a new struct instance of type T.
func shallowMerge[T any](child *T, parent *T) *T {
finalConfig := *child
// InheritFrom inherits unset values from the provided parent configuration and
// returns a new structure instance, which is a result of the inheritance.
func (c *ImageConfig) InheritFrom(parentConfig *ImageConfig) *ImageConfig {
finalConfig := ImageConfig(*c)
if parentConfig != nil {
if parent != nil {
// iterate over all struct fields and copy unset values from the parent
for i := 0; i < reflect.TypeOf(*c).NumField(); i++ {
fieldName := reflect.TypeOf(*c).Field(i).Name
for i := 0; i < reflect.TypeOf(*child).NumField(); i++ {
fieldName := reflect.TypeOf(*child).Field(i).Name
field := reflect.ValueOf(&finalConfig).Elem().FieldByName(fieldName)
// Only container types or pointer are supported.
@ -163,13 +162,24 @@ func (c *ImageConfig) InheritFrom(parentConfig *ImageConfig) *ImageConfig {
}
if field.IsNil() {
field.Set(reflect.ValueOf(parentConfig).Elem().FieldByName(fieldName))
field.Set(reflect.ValueOf(parent).Elem().FieldByName(fieldName))
}
}
}
return &finalConfig
}
type DNFConfig struct {
Options []*osbuild.DNFConfigStageOptions
SetReleaseVerVar *bool `yaml:"set_release_ver_var"`
}
// InheritFrom inherits unset values from the provided parent configuration and
// returns a new structure instance, which is a result of the inheritance.
func (c *ImageConfig) InheritFrom(parentConfig *ImageConfig) *ImageConfig {
return shallowMerge(c, parentConfig)
}
func (c *ImageConfig) DNFConfigOptions(osVersion string) []*osbuild.DNFConfigStageOptions {
if c.DNFConfig == nil {
return nil

View file

@ -8,6 +8,17 @@ type InstallerConfig struct {
AdditionalDrivers []string `yaml:"additional_drivers"`
AdditionalAnacondaModules []string `yaml:"additional_anaconda_modules"`
// XXX: this is really here only for compatibility/because of drift in the "imageInstallerImage"
// between fedora/rhel
KickstartUnattendedExtraKernelOpts []string `yaml:"kickstart_unattended_extra_kernel_opts"`
ISORootKickstart *bool `yaml:"iso_root_kickstart"`
// SquashfsRootfs will set SquashfsRootfs as rootfs in the iso image
SquashfsRootfs *bool `yaml:"squashfs_rootfs"`
}
// InheritFrom inherits unset values from the provided parent configuration and
// returns a new structure instance, which is a result of the inheritance.
func (c *InstallerConfig) InheritFrom(parentConfig *InstallerConfig) *InstallerConfig {
return shallowMerge(c, parentConfig)
}

View file

@ -1,133 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkAMIImgTypeX86_64(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(d, "x86_64", "ami")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkAMIImgTypeAarch64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ami",
"image.raw",
"application/octet-stream",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image"},
[]string{"image"},
)
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, "aarch64", "ami")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// RHEL internal-only x86_64 EC2 image type
func mkEc2ImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, "x86_64", "ec2")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// RHEL internal-only aarch64 EC2 image type
func mkEC2ImgTypeAarch64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, "aarch64", "ec2")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// RHEL internal-only x86_64 EC2 HA image type
func mkEc2HaImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2-ha",
"image.raw.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, "x86_64", "ec2-ha")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkEC2SapImgTypeX86_64(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ec2-sap",
"image.raw.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, "x86_64", "ec2-sap")
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

@ -1,114 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel"
)
// Azure image type
func mkAzureImgType(rd *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"vhd",
"disk.vhd",
"application/x-vhd",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc"},
[]string{"vpc"},
)
it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, a.String(), "vhd")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// Azure RHEL-internal image type
func mkAzureInternalImgType(rd *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"azure-rhui",
"disk.vhd.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, a.String(), "azure-rhui")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkAzureSapInternalImgType(rd *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"azure-sap-rhui",
"disk.vhd.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, a.String(), "azure-sap-rhui")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkAzureSapAppsImgType(rd *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"azure-sapapps-rhui",
"disk.vhd.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, a.String(), "azure-sapapps-rhui")
it.BasePartitionTables = defaultBasePartitionTables
return it
}
// Azure Confidential VM
func mkAzureCVMImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"azure-cvm",
"disk.vhd.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.Bootable = true
it.DefaultSize = 32 * datasizes.GibiByte
it.DefaultImageConfig = imageConfig(rd, "x86_64", "azure-cvm")
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

@ -1,49 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkTarImgType() *rhel.ImageType {
return rhel.NewImageType(
"tar",
"root.tar.xz",
"application/x-tar",
packageSetLoader,
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive"},
[]string{"archive"},
)
}
func mkImageInstallerImgType() *rhel.ImageType {
it := rhel.NewImageType(
"image-installer",
"installer.iso",
"application/x-iso9660-image",
packageSetLoader,
rhel.ImageInstallerImage,
[]string{"build"},
[]string{"anaconda-tree", "efiboot-tree", "os", "bootiso-tree", "bootiso"},
[]string{"bootiso"},
)
it.BootISO = true
it.Bootable = true
it.ISOLabelFn = distroISOLabelFunc
it.DefaultInstallerConfig = &distro.InstallerConfig{
AdditionalDracutModules: []string{
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"net-lib",
},
AdditionalDrivers: []string{
"ipmi_devintf",
"ipmi_msghandler",
},
}
return it
}

View file

@ -1,338 +0,0 @@
package rhel10
import (
"fmt"
"strings"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/oscap"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/defs"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/platform"
)
var (
// rhel9 & cs9 share the same list
// of allowed profiles so a single
// allow list can be used
oscapProfileAllowList = []oscap.Profile{
oscap.AnssiBp28Enhanced,
oscap.AnssiBp28High,
oscap.AnssiBp28Intermediary,
oscap.AnssiBp28Minimal,
oscap.Cis,
oscap.CisServerL1,
oscap.CisWorkstationL1,
oscap.CisWorkstationL2,
oscap.Cui,
oscap.E8,
oscap.Hippa,
oscap.IsmO,
oscap.Ospp,
oscap.PciDss,
oscap.Stig,
oscap.StigGui,
}
)
func distroISOLabelFunc(t *rhel.ImageType) string {
const RHEL_ISO_LABEL = "RHEL-%s-%s-0-BaseOS-%s"
const CS_ISO_LABEL = "CentOS-Stream-%s-BaseOS-%s"
const ALMALINUX_ISO_LABEL = "AlmaLinux-%s-%s-%s-dvd"
const KITTEN_ISO_LABEL = "AlmaLinux-Kitten-%s-%s-dvd"
if t.IsRHEL() {
osVer := strings.Split(t.Arch().Distro().OsVersion(), ".")
return fmt.Sprintf(RHEL_ISO_LABEL, osVer[0], osVer[1], t.Arch().Name())
} else if t.IsAlmaLinuxKitten() {
return fmt.Sprintf(KITTEN_ISO_LABEL, t.Arch().Distro().Releasever(), t.Arch().Name())
} else if t.IsAlmaLinux() {
osVer := strings.Split(t.Arch().Distro().OsVersion(), ".")
return fmt.Sprintf(ALMALINUX_ISO_LABEL, osVer[0], osVer[1], t.Arch().Name())
} else {
return fmt.Sprintf(CS_ISO_LABEL, t.Arch().Distro().Releasever(), t.Arch().Name())
}
}
func defaultDistroImageConfig(d *rhel.Distribution) *distro.ImageConfig {
return common.Must(defs.DistroImageConfig(d.Name()))
}
func newDistro(name string, major, minor int) *rhel.Distribution {
rd, err := rhel.NewDistribution(name, major, minor)
if err != nil {
panic(err)
}
rd.CheckOptions = checkOptions
rd.DefaultImageConfig = defaultDistroImageConfig
// Architecture definitions
x86_64 := rhel.NewArchitecture(rd, arch.ARCH_X86_64)
aarch64 := rhel.NewArchitecture(rd, arch.ARCH_AARCH64)
ppc64le := rhel.NewArchitecture(rd, arch.ARCH_PPC64LE)
s390x := rhel.NewArchitecture(rd, arch.ARCH_S390X)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd, arch.ARCH_X86_64),
mkOCIImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VMDK,
},
},
mkVMDKImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_OVA,
},
},
mkOVAImgType(rd),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VAGRANT_LIBVIRT,
},
},
mkVagrantLibvirtImgType(rd, arch.ARCH_X86_64),
)
x86_64.AddImageTypes(
&platform.X86{},
mkTarImgType(),
mkWSLImgType(rd),
)
aarch64.AddImageTypes(
&platform.Aarch64{},
mkTarImgType(),
mkWSLImgType(rd),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd, arch.ARCH_AARCH64),
)
aarch64.AddImageTypes(
&platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VAGRANT_LIBVIRT,
},
},
mkVagrantLibvirtImgType(rd, arch.ARCH_AARCH64),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd, arch.ARCH_PPC64LE),
)
ppc64le.AddImageTypes(
&platform.PPC64LE{},
mkTarImgType(),
)
s390x.AddImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
mkQcow2ImgType(rd, arch.ARCH_S390X),
)
s390x.AddImageTypes(
&platform.S390X{},
mkTarImgType(),
)
ec2X86Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
x86_64.AddImageTypes(
ec2X86Platform,
mkAMIImgTypeX86_64(rd),
)
ec2Aarch64Platform := &platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
}
aarch64.AddImageTypes(
ec2Aarch64Platform,
mkAMIImgTypeAarch64(rd),
)
azureX64Platform := &platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
azureAarch64Platform := &platform.Aarch64{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
}
x86_64.AddImageTypes(azureX64Platform, mkAzureImgType(rd, azureX64Platform.GetArch()))
aarch64.AddImageTypes(azureAarch64Platform, mkAzureImgType(rd, azureAarch64Platform.GetArch()))
gceX86Platform := &platform.X86{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_GCE,
},
}
x86_64.AddImageTypes(
gceX86Platform,
mkGCEImageType(rd, arch.ARCH_X86_64),
)
x86_64.AddImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"microcode_ctl", // ??
"iwl1000-firmware",
"iwl100-firmware",
"iwl105-firmware",
"iwl135-firmware",
"iwl2000-firmware",
"iwl2030-firmware",
"iwl3160-firmware",
"iwl5000-firmware",
"iwl5150-firmware",
"iwl6050-firmware",
},
},
BIOS: true,
UEFIVendor: rd.Vendor(),
},
mkImageInstallerImgType(),
)
aarch64.AddImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{},
UEFIVendor: rd.Vendor(),
},
mkImageInstallerImgType(),
)
if rd.IsRHEL() { // RHEL-only (non-CentOS) image types
x86_64.AddImageTypes(azureX64Platform, mkAzureInternalImgType(rd, azureX64Platform.GetArch()))
aarch64.AddImageTypes(azureAarch64Platform, mkAzureInternalImgType(rd, azureAarch64Platform.GetArch()))
x86_64.AddImageTypes(azureX64Platform, mkAzureSapInternalImgType(rd, azureX64Platform.GetArch()), mkAzureSapAppsImgType(rd, azureX64Platform.GetArch()))
x86_64.AddImageTypes(ec2X86Platform, mkEc2ImgTypeX86_64(rd), mkEc2HaImgTypeX86_64(rd), mkEC2SapImgTypeX86_64(rd))
aarch64.AddImageTypes(ec2Aarch64Platform, mkEC2ImgTypeAarch64(rd))
azureX64CVMPlatform := &platform.X86{
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
Bootloader: platform.BOOTLOADER_UKI,
}
x86_64.AddImageTypes(
azureX64CVMPlatform,
mkAzureCVMImgType(rd),
)
}
rd.AddArches(x86_64, aarch64, ppc64le, s390x)
return rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" && id.Name != "almalinux" && id.Name != "almalinux_kitten" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
if id.MajorVersion != 10 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS and Kitten do not use minor versions
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
if id.Name == "almalinux_kitten" && id.MinorVersion != -1 {
return nil, fmt.Errorf("almalinux kitten does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
// So does AlmaLinux
if id.Name == "almalinux" && id.MinorVersion == -1 {
return nil, fmt.Errorf("almalinux requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, 10, id.MinorVersion)
}

View file

@ -1,28 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkGCEImageType(rd *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"gce",
"image.tar.gz",
"application/gzip",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = imageConfig(rd, a.String(), "gce")
it.DefaultSize = 20 * datasizes.GibiByte
it.Bootable = true
// TODO: the base partition table still contains the BIOS boot partition, but the image is UEFI-only
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

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

View file

@ -1,19 +0,0 @@
package rhel10
// This file defines package sets that are used by more than one image type.
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/defs"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
func packageSetLoader(t *rhel.ImageType) (map[string]rpmmd.PackageSet, error) {
return defs.PackageSets(t)
}
func imageConfig(d *rhel.Distribution, archName, imageType string) *distro.ImageConfig {
return common.Must(defs.ImageConfig(d.Name(), archName, imageType))
}

View file

@ -1,25 +0,0 @@
package rhel10
import (
"errors"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro/defs"
"github.com/osbuild/images/pkg/distro/rhel"
)
func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
partitionTable, err := defs.PartitionTable(t)
if errors.Is(err, defs.ErrNoPartitionTableForImgType) {
return disk.PartitionTable{}, false
}
if err != nil {
panic(err)
}
if partitionTable == nil {
return disk.PartitionTable{}, false
}
return *partitionTable, true
}

View file

@ -1,47 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkQcow2ImgType(d *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"qcow2",
"disk.qcow2",
"application/x-qemu-disk",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = imageConfig(d, a.String(), "qcow2")
it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOCIImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"oci",
"disk.qcow2",
"application/x-qemu-disk",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
it.DefaultImageConfig = imageConfig(d, "", "oci")
it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

@ -1,27 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkVagrantLibvirtImgType(d *rhel.Distribution, a arch.Arch) *rhel.ImageType {
it := rhel.NewImageType(
"vagrant-libvirt",
"vagrant-libvirt.box",
"application/x-tar",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vagrant", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = imageConfig(d, a.String(), "vagrant-libvirt")
it.DefaultSize = 10 * datasizes.GibiByte
it.Bootable = true
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

@ -1,44 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkVMDKImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"vmdk",
"disk.vmdk",
"application/x-vmdk",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk"},
[]string{"vmdk"},
)
it.DefaultImageConfig = imageConfig(d, "x86_64", "vmdk")
it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}
func mkOVAImgType(d *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"ova",
"image.ova",
"application/ovf",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vmdk", "ovf", "archive"},
[]string{"archive"},
)
it.DefaultImageConfig = imageConfig(d, "x86_64", "ova")
it.Bootable = true
it.DefaultSize = 4 * datasizes.GibiByte
it.BasePartitionTables = defaultBasePartitionTables
return it
}

View file

@ -1,23 +0,0 @@
package rhel10
import (
"github.com/osbuild/images/pkg/distro/rhel"
)
func mkWSLImgType(rd *rhel.Distribution) *rhel.ImageType {
it := rhel.NewImageType(
"wsl",
"image.wsl",
"application/x-tar",
packageSetLoader,
rhel.TarImage,
[]string{"build"},
[]string{"os", "archive", "xz"},
[]string{"xz"},
)
it.Compression = "xz"
it.DefaultImageConfig = imageConfig(rd, "", "wsl")
return it
}

View file

@ -1,208 +0,0 @@
package rhel7
import (
"os"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/fsnode"
"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"
)
func mkEc2ImgTypeX86_64() *rhel.ImageType {
it := rhel.NewImageType(
"ec2",
"image.raw.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "xz"},
[]string{"xz"},
)
// all RHEL 7 images should use sgdisk
it.DiskImagePartTool = common.ToPtr(osbuild.PTSgdisk)
it.Compression = "xz"
it.DefaultImageConfig = ec2ImageConfig()
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.BasePartitionTables = ec2PartitionTables
return it
}
// default EC2 images config (common for all architectures)
func ec2ImageConfig() *distro.ImageConfig {
// systemd-firstboot on el7 does not support --keymap option
vconsoleFile, err := fsnode.NewFile("/etc/vconsole.conf", nil, nil, nil, []byte("FONT=latarcyrheb-sun16\nKEYMAP=us\n"))
if err != nil {
panic(err)
}
// This is needed to disable predictable network interface names.
// The org.osbuild.udev.rules stage can't create empty files.
udevNetNameSlotRulesFile, err := fsnode.NewFile("/etc/udev/rules.d/80-net-name-slot.rules", nil, nil, nil, []byte{})
if err != nil {
panic(err)
}
// While cloud-init does this automatically on first boot for the specified user,
// this was in the original KS.
ec2UserSudoers, err := fsnode.NewFile("/etc/sudoers.d/ec2-user", common.ToPtr(os.FileMode(0o440)), nil, nil, []byte("ec2-user\tALL=(ALL)\tNOPASSWD: ALL\n"))
if err != nil {
panic(err)
}
// The image built from the original KS has this file with this content.
hostnameFile, err := fsnode.NewFile("/etc/hostname", nil, nil, nil, []byte("localhost.localdomain\n"))
if err != nil {
panic(err)
}
return &distro.ImageConfig{
Timezone: common.ToPtr("UTC"),
TimeSynchronization: &osbuild.ChronyStageOptions{
Servers: []osbuild.ChronyConfigServer{
{
Hostname: "0.rhel.pool.ntp.org",
Iburst: common.ToPtr(true),
},
{
Hostname: "1.rhel.pool.ntp.org",
Iburst: common.ToPtr(true),
},
{
Hostname: "2.rhel.pool.ntp.org",
Iburst: common.ToPtr(true),
},
{
Hostname: "3.rhel.pool.ntp.org",
Iburst: common.ToPtr(true),
},
{
Hostname: "169.254.169.123",
Prefer: common.ToPtr(true),
Iburst: common.ToPtr(true),
Minpoll: common.ToPtr(4),
Maxpoll: common.ToPtr(4),
},
},
// empty string will remove any occurrences of the option from the configuration
LeapsecTz: common.ToPtr(""),
},
EnabledServices: []string{
"sshd",
"rsyslog",
},
DefaultTarget: common.ToPtr("multi-user.target"),
UpdateDefaultKernel: common.ToPtr(true),
DefaultKernel: common.ToPtr("kernel"),
Sysconfig: &distro.Sysconfig{
Networking: true,
NoZeroConf: true,
CreateDefaultNetworkScripts: true,
},
SystemdLogind: []*osbuild.SystemdLogindStageOptions{
{
Filename: "logind.conf",
Config: osbuild.SystemdLogindConfigDropin{
Login: osbuild.SystemdLogindConfigLoginSection{
NAutoVTs: common.ToPtr(0),
},
},
},
},
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "00-rhel-default-user.cfg",
Config: osbuild.CloudInitConfigFile{
SystemInfo: &osbuild.CloudInitConfigSystemInfo{
DefaultUser: &osbuild.CloudInitConfigDefaultUser{
Name: "ec2-user",
},
},
},
},
{
Filename: "99-datasource.cfg",
Config: osbuild.CloudInitConfigFile{
DatasourceList: []string{
"Ec2",
"None",
},
},
},
},
Modprobe: []*osbuild.ModprobeStageOptions{
{
Filename: "blacklist-nouveau.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("nouveau"),
},
},
},
DracutConf: []*osbuild.DracutConfStageOptions{
{
Filename: "sgdisk.conf",
Config: osbuild.DracutConfigFile{
Install: []string{"sgdisk"},
},
},
},
SshdConfig: &osbuild.SshdConfigStageOptions{
Config: osbuild.SshdConfigConfig{
PasswordAuthentication: common.ToPtr(false),
},
},
Files: []*fsnode.File{
vconsoleFile,
udevNetNameSlotRulesFile,
ec2UserSudoers,
hostnameFile,
},
SELinuxForceRelabel: common.ToPtr(true),
KernelOptions: []string{"ro", "console=tty0", "console=ttyS0,115200n8", "net.ifnames=0", "rd.blacklist=nouveau", "nvme_core.io_timeout=4294967295", "crashkernel=auto", "LANG=en_US.UTF-8"},
}
}
func ec2PartitionTables(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: 10 * datasizes.GibiByte,
Partitions: []disk.Partition{
{
Size: 1 * datasizes.MebiByte,
Bootable: true,
Type: disk.BIOSBootPartitionGUID,
UUID: disk.BIOSBootPartitionUUID,
},
{
Size: 6144 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.RootPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}, true
default:
return disk.PartitionTable{}, false
}
}

View file

@ -1,337 +0,0 @@
package rhel7
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/customizations/subscription"
"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"
)
func mkAzureRhuiImgType() *rhel.ImageType {
it := rhel.NewImageType(
"azure-rhui",
"disk.vhd.xz",
"application/xz",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "vpc", "xz"},
[]string{"xz"},
)
// all RHEL 7 images should use sgdisk
it.DiskImagePartTool = common.ToPtr(osbuild.PTSgdisk)
// RHEL 7 qemu vpc subformat does not support force_size
it.DiskImageVPCForceSize = common.ToPtr(false)
it.Compression = "xz"
it.DefaultImageConfig = azureDefaultImgConfig
it.Bootable = true
it.DefaultSize = 64 * datasizes.GibiByte
it.BasePartitionTables = azureRhuiBasePartitionTables
return it
}
var azureDefaultImgConfig = &distro.ImageConfig{
Timezone: common.ToPtr("Etc/UTC"),
Locale: common.ToPtr("en_US.UTF-8"),
GPGKeyFiles: []string{
"/etc/pki/rpm-gpg/RPM-GPG-KEY-microsoft-azure-release",
"/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release",
},
SELinuxForceRelabel: common.ToPtr(true),
Authconfig: &osbuild.AuthconfigStageOptions{},
UpdateDefaultKernel: common.ToPtr(true),
DefaultKernel: common.ToPtr("kernel-core"),
Sysconfig: &distro.Sysconfig{
Networking: true,
NoZeroConf: true,
},
EnabledServices: []string{
"cloud-config",
"cloud-final",
"cloud-init-local",
"cloud-init",
"firewalld",
"NetworkManager",
"sshd",
"waagent",
},
SshdConfig: &osbuild.SshdConfigStageOptions{
Config: osbuild.SshdConfigConfig{
ClientAliveInterval: common.ToPtr(180),
},
},
Modprobe: []*osbuild.ModprobeStageOptions{
{
Filename: "blacklist-amdgpu.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("amdgpu"),
},
},
{
Filename: "blacklist-intel-cstate.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("intel_cstate"),
},
},
{
Filename: "blacklist-floppy.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("floppy"),
},
},
{
Filename: "blacklist-nouveau.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("nouveau"),
osbuild.NewModprobeConfigCmdBlacklist("lbm-nouveau"),
},
},
{
Filename: "blacklist-skylake-edac.conf",
Commands: osbuild.ModprobeConfigCmdList{
osbuild.NewModprobeConfigCmdBlacklist("skx_edac"),
},
},
},
CloudInit: []*osbuild.CloudInitStageOptions{
{
Filename: "06_logging_override.cfg",
Config: osbuild.CloudInitConfigFile{
Output: &osbuild.CloudInitConfigOutput{
All: common.ToPtr("| tee -a /var/log/cloud-init-output.log"),
},
},
},
{
Filename: "10-azure-kvp.cfg",
Config: osbuild.CloudInitConfigFile{
Reporting: &osbuild.CloudInitConfigReporting{
Logging: &osbuild.CloudInitConfigReportingHandlers{
Type: "log",
},
Telemetry: &osbuild.CloudInitConfigReportingHandlers{
Type: "hyperv",
},
},
},
},
{
Filename: "91-azure_datasource.cfg",
Config: osbuild.CloudInitConfigFile{
Datasource: &osbuild.CloudInitConfigDatasource{
Azure: &osbuild.CloudInitConfigDatasourceAzure{
ApplyNetworkConfig: false,
},
},
DatasourceList: []string{
"Azure",
},
},
},
},
PwQuality: &osbuild.PwqualityConfStageOptions{
Config: osbuild.PwqualityConfConfig{
Minlen: common.ToPtr(6),
Minclass: common.ToPtr(3),
Dcredit: common.ToPtr(0),
Ucredit: common.ToPtr(0),
Lcredit: common.ToPtr(0),
Ocredit: common.ToPtr(0),
},
},
WAAgentConfig: &osbuild.WAAgentConfStageOptions{
Config: osbuild.WAAgentConfig{
RDFormat: common.ToPtr(false),
RDEnableSwap: common.ToPtr(false),
},
},
RHSMConfig: map[subscription.RHSMStatus]*subscription.RHSMConfig{
subscription.RHSMConfigNoSubscription: {
YumPlugins: subscription.SubManDNFPluginsConfig{
SubscriptionManager: subscription.DNFPluginConfig{
Enabled: common.ToPtr(false),
},
},
SubMan: subscription.SubManConfig{
Rhsmcertd: subscription.SubManRHSMCertdConfig{
AutoRegistration: common.ToPtr(true),
},
Rhsm: subscription.SubManRHSMConfig{
ManageRepos: common.ToPtr(false),
},
},
},
subscription.RHSMConfigWithSubscription: {
SubMan: subscription.SubManConfig{
Rhsmcertd: subscription.SubManRHSMCertdConfig{
AutoRegistration: common.ToPtr(true),
},
// do not disable the redhat.repo management if the user
// explicitly request the system to be subscribed
},
},
},
Grub2Config: &osbuild.GRUB2Config{
TerminalInput: []string{"serial", "console"},
TerminalOutput: []string{"serial", "console"},
Serial: "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1",
Timeout: 10,
},
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"},
},
),
},
},
YumConfig: &osbuild.YumConfigStageOptions{
Config: &osbuild.YumConfigConfig{
HttpCaching: common.ToPtr("packages"),
},
Plugins: &osbuild.YumConfigPlugins{
Langpacks: &osbuild.YumConfigPluginsLangpacks{
Locales: []string{"en_US.UTF-8"},
},
},
},
DefaultTarget: common.ToPtr("multi-user.target"),
KernelOptions: []string{"ro", "crashkernel=auto", "console=tty1", "console=ttyS0", "earlyprintk=ttyS0", "rootdelay=300", "scsi_mod.use_blk_mq=y"},
}
func azureRhuiBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
switch t.Arch().Name() {
case arch.ARCH_X86_64.String():
return disk.PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: 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,
},
},
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.DataPartitionUUID,
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
default:
return disk.PartitionTable{}, false
}
}

View file

@ -1,100 +0,0 @@
package rhel7
import (
"fmt"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/defs"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/platform"
)
// RHEL-based OS image configuration defaults
func defaultDistroImageConfig(d *rhel.Distribution) *distro.ImageConfig {
return common.Must(defs.DistroImageConfig(d.Name()))
}
func newDistro(name string, minor int) *rhel.Distribution {
rd, err := rhel.NewDistribution(name, 7, minor)
if err != nil {
panic(err)
}
rd.CheckOptions = checkOptions
rd.DefaultImageConfig = defaultDistroImageConfig
rd.DistCodename = "Maipo"
// Architecture definitions
x86_64 := rhel.NewArchitecture(rd, arch.ARCH_X86_64)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "0.10",
},
},
mkQcow2ImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
UEFIVendor: rd.Vendor(),
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_VHD,
},
},
mkAzureRhuiImgType(),
)
x86_64.AddImageTypes(
&platform.X86{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_RAW,
},
},
mkEc2ImgTypeX86_64(),
)
rd.AddArches(
x86_64,
)
return rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
if id.MajorVersion != 7 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, id.MinorVersion)
}

View file

@ -1,63 +0,0 @@
package rhel7
import (
"fmt"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/policies"
)
// checkOptions checks the validity and compatibility of options and customizations for the image type.
// Returns ([]string, error) where []string, if non-nil, will hold any generated warnings (e.g. deprecation notices).
func checkOptions(t *rhel.ImageType, bp *blueprint.Blueprint, options distro.ImageOptions) ([]string, error) {
customizations := bp.Customizations
// holds warnings (e.g. deprecation notices)
var warnings []string
if len(bp.Containers) > 0 {
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.Name(), t.Arch().Distro().Name())
}
mountpoints := customizations.GetFilesystems()
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
if osc := customizations.GetOpenSCAP(); osc != nil {
return warnings, fmt.Errorf("OpenSCAP unsupported os version: %s", t.Arch().Distro().OsVersion())
}
// Check Directory/File Customizations are valid
dc := customizations.GetDirectories()
fc := customizations.GetFiles()
err = blueprint.ValidateDirFileCustomizations(dc, fc)
if err != nil {
return warnings, err
}
dcp := policies.CustomDirectoriesPolicies
fcp := policies.CustomFilesPolicies
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, dcp)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, fcp)
if err != nil {
return warnings, err
}
// check if repository customizations are valid
_, err = customizations.GetRepositories()
if err != nil {
return warnings, err
}
return warnings, nil
}

View file

@ -1,11 +0,0 @@
package rhel7
import (
"github.com/osbuild/images/pkg/distro/defs"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/rpmmd"
)
func packageSetLoader(t *rhel.ImageType) (map[string]rpmmd.PackageSet, error) {
return defs.PackageSets(t)
}

View file

@ -1,25 +0,0 @@
package rhel7
import (
"errors"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro/defs"
"github.com/osbuild/images/pkg/distro/rhel"
)
func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
partitionTable, err := defs.PartitionTable(t)
if errors.Is(err, defs.ErrNoPartitionTableForImgType) {
return disk.PartitionTable{}, false
}
if err != nil {
panic(err)
}
if partitionTable == nil {
return disk.PartitionTable{}, false
}
return *partitionTable, true
}

View file

@ -1,58 +0,0 @@
package rhel7
import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/customizations/subscription"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel"
"github.com/osbuild/images/pkg/osbuild"
)
func mkQcow2ImgType() *rhel.ImageType {
it := rhel.NewImageType(
"qcow2",
"disk.qcow2",
"application/x-qemu-disk",
packageSetLoader,
rhel.DiskImage,
[]string{"build"},
[]string{"os", "image", "qcow2"},
[]string{"qcow2"},
)
// all RHEL 7 images should use sgdisk
it.DiskImagePartTool = common.ToPtr(osbuild.PTSgdisk)
it.Bootable = true
it.DefaultSize = 10 * datasizes.GibiByte
it.DefaultImageConfig = qcow2DefaultImgConfig
it.BasePartitionTables = defaultBasePartitionTables
return it
}
var qcow2DefaultImgConfig = &distro.ImageConfig{
DefaultTarget: common.ToPtr("multi-user.target"),
SELinuxForceRelabel: common.ToPtr(true),
UpdateDefaultKernel: common.ToPtr(true),
DefaultKernel: common.ToPtr("kernel"),
Sysconfig: &distro.Sysconfig{
Networking: true,
NoZeroConf: true,
CreateDefaultNetworkScripts: true,
},
RHSMConfig: map[subscription.RHSMStatus]*subscription.RHSMConfig{
subscription.RHSMConfigNoSubscription: {
YumPlugins: subscription.SubManDNFPluginsConfig{
ProductID: subscription.DNFPluginConfig{
Enabled: common.ToPtr(false),
},
SubscriptionManager: subscription.DNFPluginConfig{
Enabled: common.ToPtr(false),
},
},
},
},
KernelOptions: []string{"console=tty0", "console=ttyS0,115200n8", "no_timer_check", "net.ifnames=0", "crashkernel=auto"},
}

View file

@ -6,8 +6,6 @@ import (
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/generic"
"github.com/osbuild/images/pkg/distro/rhel/rhel10"
"github.com/osbuild/images/pkg/distro/rhel/rhel7"
"github.com/osbuild/images/pkg/distro/rhel/rhel8"
"github.com/osbuild/images/pkg/distro/rhel/rhel9"
"github.com/osbuild/images/pkg/distro/test_distro"
@ -110,10 +108,8 @@ func New(factories ...FactoryFunc) *Factory {
func NewDefault() *Factory {
return New(
generic.DistroFactory,
rhel7.DistroFactory,
rhel8.DistroFactory,
rhel9.DistroFactory,
rhel10.DistroFactory,
)
}

View file

@ -2,8 +2,6 @@ package distroidparser
import (
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distro/rhel/rhel10"
"github.com/osbuild/images/pkg/distro/rhel/rhel7"
"github.com/osbuild/images/pkg/distro/rhel/rhel8"
"github.com/osbuild/images/pkg/distro/rhel/rhel9"
)
@ -62,9 +60,7 @@ func (p *Parser) Standardize(idStr string) (string, error) {
func NewDefaultParser() *Parser {
return New(
rhel7.ParseID,
rhel8.ParseID,
rhel9.ParseID,
rhel10.ParseID,
)
}

View file

@ -0,0 +1,26 @@
package hashutil
import (
"crypto/sha256"
"fmt"
"io"
"os"
)
// Sha256sum() is a convenience wrapper to generate
// the sha256 hex digest of a file. The hash is the
// same as from the sha256sum util.
func Sha256sum(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}

View file

@ -16,6 +16,7 @@ import (
"encoding/json"
"fmt"
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/dnfjson"
"github.com/osbuild/images/pkg/osbuild"
@ -34,6 +35,33 @@ const (
DISTRO_FEDORA
)
func (d *Distro) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
switch s {
case "rhel-10":
*d = DISTRO_EL10
case "rhel-9":
*d = DISTRO_EL9
case "rhel-8":
*d = DISTRO_EL8
case "rhel-7":
*d = DISTRO_EL7
case "fedora":
*d = DISTRO_FEDORA
default:
return fmt.Errorf("unknown distro: %q", s)
}
return nil
}
func (d *Distro) UnmarshalYAML(unmarshal func(any) error) error {
return common.UnmarshalYAMLviaJSON(d, unmarshal)
}
type Inputs osbuild.SourceInputs
// An OSBuildManifest is an opaque JSON object, which is a valid input to osbuild
@ -161,12 +189,12 @@ func (m Manifest) Serialize(depsolvedSets map[string]dnfjson.DepsolveResult, con
var mergedInputs osbuild.SourceInputs
for _, pipeline := range m.pipelines {
pipelines = append(pipelines, pipeline.serialize())
mergedInputs.Commits = append(mergedInputs.Commits, pipeline.getOSTreeCommits()...)
mergedInputs.Depsolved.Packages = append(mergedInputs.Depsolved.Packages, depsolvedSets[pipeline.Name()].Packages...)
mergedInputs.Depsolved.Repos = append(mergedInputs.Depsolved.Repos, depsolvedSets[pipeline.Name()].Repos...)
mergedInputs.Containers = append(mergedInputs.Containers, pipeline.getContainerSpecs()...)
mergedInputs.InlineData = append(mergedInputs.InlineData, pipeline.getInline()...)
mergedInputs.FileRefs = append(mergedInputs.FileRefs, pipeline.fileRefs()...)
}
for _, pipeline := range m.pipelines {
pipeline.serializeEnd()

View file

@ -2,6 +2,7 @@ package manifest
import (
"fmt"
"net/url"
"path/filepath"
"strings"
@ -691,7 +692,7 @@ func (p *OS) serialize() osbuild.Pipeline {
}
pipeline.AddStage(subStage)
pipeline.AddStages(osbuild.GenDirectoryNodesStages(subDirs)...)
p.addInlineDataAndStages(&pipeline, subFiles)
p.addStagesForAllFilesAndInlineData(&pipeline, subFiles)
p.OSCustomizations.EnabledServices = append(p.OSCustomizations.EnabledServices, subServices...)
}
@ -746,7 +747,7 @@ func (p *OS) serialize() osbuild.Pipeline {
if err != nil {
panic(err)
}
p.addInlineDataAndStages(&pipeline, []*fsnode.File{csvfile})
p.addStagesForAllFilesAndInlineData(&pipeline, []*fsnode.File{csvfile})
stages, err := maybeAddHMACandDirStage(p.packageSpecs, espMountpoint, p.kernelVer)
if err != nil {
@ -810,7 +811,7 @@ func (p *OS) serialize() osbuild.Pipeline {
}
pipeline.AddStages(osbuild.GenDirectoryNodesStages([]*fsnode.Directory{failsafeDir})...)
p.addInlineDataAndStages(&pipeline, failsafeFiles)
p.addStagesForAllFilesAndInlineData(&pipeline, failsafeFiles)
}
// First create custom directories, because some of the custom files may depend on them
@ -822,7 +823,7 @@ func (p *OS) serialize() osbuild.Pipeline {
// units, so let's make sure they get created before the systemd stage that
// will probably want to enable them
if len(p.OSCustomizations.Files) > 0 {
p.addInlineDataAndStages(&pipeline, p.OSCustomizations.Files)
p.addStagesForAllFilesAndInlineData(&pipeline, p.OSCustomizations.Files)
}
enabledServices := []string{}
@ -870,7 +871,7 @@ func (p *OS) serialize() osbuild.Pipeline {
if p.OSCustomizations.FIPS {
pipeline.AddStages(osbuild.GenFIPSStages()...)
p.addInlineDataAndStages(&pipeline, osbuild.GenFIPSFiles())
p.addStagesForAllFilesAndInlineData(&pipeline, osbuild.GenFIPSFiles())
}
// NOTE: We need to run the OpenSCAP stages as the last stage before SELinux
@ -899,7 +900,7 @@ func (p *OS) serialize() osbuild.Pipeline {
}
if len(files) > 0 {
p.addInlineDataAndStages(&pipeline, files)
p.addStagesForAllFilesAndInlineData(&pipeline, files)
}
}
pipeline.AddStage(osbuild.NewUpdateCATrustStage())
@ -1154,13 +1155,45 @@ func (p *OS) getInline() []string {
return p.inlineData
}
// addInlineDataAndStages generates stages for creating files and adds them to
// addStagesForAllFilesAndInlineData generates stages for creating files and adds them to
// the pipeline. It also adds their data to the inlineData for the pipeline so
// that the appropriate sources are created.
func (p *OS) addInlineDataAndStages(pipeline *osbuild.Pipeline, files []*fsnode.File) {
//
// Note that this also creates stages for non-inline files that come via "fileRefs()"
func (p *OS) addStagesForAllFilesAndInlineData(pipeline *osbuild.Pipeline, files []*fsnode.File) {
pipeline.AddStages(osbuild.GenFileNodesStages(files)...)
for _, file := range files {
p.inlineData = append(p.inlineData, string(file.Data()))
// files that come via an URI are not inline data and
// are added via the "fileRefs()" below
if file.URI() == "" {
p.inlineData = append(p.inlineData, string(file.Data()))
}
}
}
// fileRefs ensures that any files from customizations that require fetching data
// (e.g. via the "uri" key in customizations) are added to the manifests "sources"
//
// Note that the actual copy/chmod/... stages are generated via addStagesForAllFilesAndInlineData
func (p *OS) fileRefs() []string {
var fileRefs []string
for _, file := range p.OSCustomizations.Files {
if uriStr := file.URI(); uriStr != "" {
uri, err := url.Parse(uriStr)
if err != nil {
panic(fmt.Errorf("internal error: file customizations is not a valid URL: %w", err))
}
switch uri.Scheme {
case "", "file":
fileRefs = append(fileRefs, uri.Path)
default:
panic(fmt.Errorf("internal error: unsupported schema for OSCustomizations.Files: %v", uriStr))
}
}
}
return fileRefs
}

View file

@ -447,7 +447,7 @@ func (p *OSTreeDeployment) serialize() osbuild.Pipeline {
}
if p.FIPS {
p.addInlineDataAndStages(&pipeline, osbuild.GenFIPSFiles(), ref)
p.addStagesForAllFilesAndInlineData(&pipeline, osbuild.GenFIPSFiles(), ref)
for _, stage := range osbuild.GenFIPSStages() {
stage.MountOSTree(p.osName, ref, 0)
pipeline.AddStage(stage)
@ -483,7 +483,7 @@ func (p *OSTreeDeployment) serialize() osbuild.Pipeline {
}
if len(p.Files) > 0 {
p.addInlineDataAndStages(&pipeline, p.Files, ref)
p.addStagesForAllFilesAndInlineData(&pipeline, p.Files, ref)
}
if len(p.EnabledServices) != 0 || len(p.DisabledServices) != 0 {
@ -511,10 +511,10 @@ func (p *OSTreeDeployment) getInline() []string {
return p.inlineData
}
// addInlineDataAndStages generates stages for creating files and adds them to
// addStagesForAllFilesAndInlineData generates stages for creating files and adds them to
// the pipeline. It also adds their data to the inlineData for the pipeline so
// that the appropriate sources are created.
func (p *OSTreeDeployment) addInlineDataAndStages(pipeline *osbuild.Pipeline, files []*fsnode.File, ref string) {
func (p *OSTreeDeployment) addStagesForAllFilesAndInlineData(pipeline *osbuild.Pipeline, files []*fsnode.File, ref string) {
for _, stage := range osbuild.GenFileNodesStages(files) {
stage.MountOSTree(p.osName, ref, 0)
pipeline.AddStage(stage)

View file

@ -69,6 +69,9 @@ type Pipeline interface {
// getInline returns the list of inlined data content that will be used to
// embed files in the pipeline tree.
getInline() []string
// files generated from url references
fileRefs() []string
}
// A Base represents the core functionality shared between each of the pipeline
@ -148,6 +151,10 @@ func (p Base) getInline() []string {
return []string{}
}
func (p Base) fileRefs() []string {
return nil
}
// NewBase returns a generic Pipeline object. The name is mandatory, immutable and must
// be unique among all the pipelines used in a manifest, which is currently not enforced.
// The build argument is a pipeline representing a build root in which the rest of the

View file

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/osbuild/images/pkg/customizations/fsnode"
"github.com/osbuild/images/pkg/hashutil"
)
// GenFileNodesStages generates the stages for a list of file nodes.
@ -22,7 +23,16 @@ func GenFileNodesStages(files []*fsnode.File) []*Stage {
chownPaths := make(map[string]ChownStagePathOptions)
for _, file := range files {
fileDataChecksum := fmt.Sprintf("%x", sha256.Sum256(file.Data()))
var fileDataChecksum string
if file.URI() == "" {
fileDataChecksum = fmt.Sprintf("%x", sha256.Sum256(file.Data()))
} else {
var err error
fileDataChecksum, err = hashutil.Sha256sum(file.URI())
if err != nil {
panic(err)
}
}
copyStageInputKey := fmt.Sprintf("file-%s", fileDataChecksum)
copyStagePaths = append(copyStagePaths, CopyStagePath{
From: fmt.Sprintf("input://%s/sha256:%s", copyStageInputKey, fileDataChecksum),

View file

@ -94,41 +94,17 @@ type RPMPackageMetadata struct {
SigGPG string `json:"siggpg"`
}
func (RPMStageMetadata) isStageMetadata() {}
func OSBuildMetadataToRPMs(stagesMetadata map[string]StageMetadata) []rpmmd.RPM {
rpms := make([]rpmmd.RPM, 0)
for _, md := range stagesMetadata {
switch metadata := md.(type) {
case *RPMStageMetadata:
for _, pkg := range metadata.Packages {
rpms = append(rpms, rpmmd.RPM{
Type: "rpm",
Name: pkg.Name,
Epoch: pkg.Epoch,
Version: pkg.Version,
Release: pkg.Release,
Arch: pkg.Arch,
Sigmd5: pkg.SigMD5,
Signature: RPMPackageMetadataToSignature(pkg),
})
}
default:
continue
}
}
return rpms
}
func RPMPackageMetadataToSignature(pkg RPMPackageMetadata) *string {
if pkg.SigGPG != "" {
return &pkg.SigGPG
} else if pkg.SigPGP != "" {
return &pkg.SigPGP
func (pkgmd RPMPackageMetadata) Signature() *string {
if pkgmd.SigGPG != "" {
return &pkgmd.SigGPG
} else if pkgmd.SigPGP != "" {
return &pkgmd.SigPGP
}
return nil
}
func (RPMStageMetadata) isStageMetadata() {}
func NewRpmStageSourceFilesInputs(specs []rpmmd.PackageSpec) *RPMStageInputs {
input := NewFilesInput(pkgRefs(specs))
return &RPMStageInputs{Packages: input}

View file

@ -7,6 +7,7 @@ import (
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/dnfjson"
"github.com/osbuild/images/pkg/hashutil"
"github.com/osbuild/images/pkg/ostree"
"github.com/osbuild/images/pkg/rpmmd"
)
@ -27,7 +28,10 @@ type SourceInputs struct {
Depsolved dnfjson.DepsolveResult
Containers []container.Spec
Commits []ostree.CommitSpec
// InlineData contans the inline data for fsnode.Files
InlineData []string
// FileRefs contains the references of paths/urls for fsnode.Files
FileRefs []string
}
// A Sources map contains all the sources made available to an osbuild run
@ -170,5 +174,24 @@ func GenSources(inputs SourceInputs, rpmDownloader RpmDownloader) (Sources, erro
}
}
// collect host resources
if len(inputs.FileRefs) > 0 {
// XXX: fugly
curl, ok := sources["org.osbuild.curl"].(*CurlSource)
if !ok || curl == nil {
curl = NewCurlSource()
}
for _, hostRes := range inputs.FileRefs {
checksum, err := hashutil.Sha256sum(hostRes)
if err != nil {
return nil, err
}
curl.Items["sha256:"+checksum] = &CurlSourceOptions{
URL: fmt.Sprintf("file:%s", hostRes),
}
}
sources["org.osbuild.curl"] = curl
}
return sources, nil
}

View file

@ -1,39 +0,0 @@
package rpmmd
import (
"fmt"
)
type RPM struct {
Type string `json:"type"` // must be 'rpm'
Name string `json:"name"`
Version string `json:"version"`
Release string `json:"release"`
Epoch *string `json:"epoch,omitempty"`
Arch string `json:"arch"`
Sigmd5 string `json:"sigmd5"`
Signature *string `json:"signature"`
}
// NEVRA string for the package
func (r RPM) String() string {
epoch := ""
if r.Epoch != nil {
epoch = *r.Epoch + ":"
}
return fmt.Sprintf("%s-%s%s-%s.%s", r.Name, epoch, r.Version, r.Release, r.Arch)
}
// Deduplicate a list of RPMs based on NEVRA string
func DeduplicateRPMs(rpms []RPM) []RPM {
rpmMap := make(map[string]struct{}, len(rpms))
uniqueRPMs := make([]RPM, 0, len(rpms))
for _, rpm := range rpms {
if _, added := rpmMap[rpm.String()]; !added {
rpmMap[rpm.String()] = struct{}{}
uniqueRPMs = append(uniqueRPMs, rpm)
}
}
return uniqueRPMs
}

View file

@ -5,4 +5,4 @@
package internal
// Version is the current tagged release of the library.
const Version = "0.239.0"
const Version = "0.240.0"

11
vendor/modules.txt vendored
View file

@ -1049,11 +1049,11 @@ 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/blueprint v1.6.0
## explicit; go 1.22.8
# github.com/osbuild/blueprint v1.10.0
## explicit; go 1.23.9
github.com/osbuild/blueprint/internal/common
github.com/osbuild/blueprint/pkg/blueprint
# github.com/osbuild/images v0.156.0
# github.com/osbuild/images v0.158.0
## explicit; go 1.23.9
github.com/osbuild/images/data/dependencies
github.com/osbuild/images/data/repositories
@ -1083,8 +1083,6 @@ github.com/osbuild/images/pkg/distro
github.com/osbuild/images/pkg/distro/defs
github.com/osbuild/images/pkg/distro/generic
github.com/osbuild/images/pkg/distro/rhel
github.com/osbuild/images/pkg/distro/rhel/rhel10
github.com/osbuild/images/pkg/distro/rhel/rhel7
github.com/osbuild/images/pkg/distro/rhel/rhel8
github.com/osbuild/images/pkg/distro/rhel/rhel9
github.com/osbuild/images/pkg/distro/test_distro
@ -1092,6 +1090,7 @@ github.com/osbuild/images/pkg/distrofactory
github.com/osbuild/images/pkg/distroidparser
github.com/osbuild/images/pkg/dnfjson
github.com/osbuild/images/pkg/experimentalflags
github.com/osbuild/images/pkg/hashutil
github.com/osbuild/images/pkg/image
github.com/osbuild/images/pkg/manifest
github.com/osbuild/images/pkg/olog
@ -1499,7 +1498,7 @@ golang.org/x/tools/internal/gopathwalk
golang.org/x/tools/internal/imports
golang.org/x/tools/internal/modindex
golang.org/x/tools/internal/stdlib
# google.golang.org/api v0.239.0
# google.golang.org/api v0.240.0
## explicit; go 1.23.0
google.golang.org/api/googleapi
google.golang.org/api/googleapi/transport