Port osbuild/images v0.33.0 with dot-notation to composer

Update the osbuild/images to the version which introduces "dot notation"
for distro release versions.

 - Replace all uses of distroregistry by distrofactory.
 - Delete local version of reporegistry and use the one from the
   osbuild/images.
 - Weldr: unify `createWeldrAPI()` and `createWeldrAPI2()` into a single
   `createTestWeldrAPI()` function`.
 - store/fixture: rework fixtures to allow overriding the host distro
   name and host architecture name. A cleanup function to restore the
   host distro and arch names is always part of the fixture struct.
 - Delete `distro_mock` package, since it is no longer used.
 - Bump the required version of osbuild to 98, because the OSCAP
   customization is using the 'compress_results' stage option, which is
   not available in older versions of osbuild.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
This commit is contained in:
Tomáš Hozza 2024-01-08 17:58:49 +01:00 committed by Achilleas Koutsou
parent f6ff8c40dd
commit 625b1578fa
1166 changed files with 154457 additions and 5508 deletions

View file

@ -17,6 +17,8 @@ const (
BOOT_LEGACY
BOOT_UEFI
BOOT_HYBRID
UnsupportedCustomizationError = "unsupported blueprint customizations found for image type %q: (allowed: %s)"
NoCustomizationsAllowedError = "image type %q does not support customizations"
)
func (m BootMode) String() string {

View file

@ -131,6 +131,20 @@ var (
exports: []string{"commit-archive"},
}
iotBootableContainer = imageType{
name: "iot-bootable-container",
filename: "iot-bootable-container.tar",
mimeType: "application/x-tar",
packageSets: map[string]packageSetFunc{
osPkgsKey: bootableContainerPackageSet,
},
rpmOstree: true,
image: bootableContainerImage,
buildPipelines: []string{"build"},
payloadPipelines: []string{"os", "ostree-commit", "ostree-encapsulate"},
exports: []string{"ostree-encapsulate"},
}
iotOCIImgType = imageType{
name: "iot-container",
nameAliases: []string{"fedora-iot-container"},
@ -519,20 +533,6 @@ func (a *architecture) Distro() distro.Distro {
return a.distro
}
// New creates a new distro object, defining the supported architectures and image types
func NewF37() distro.Distro {
return newDistro(37)
}
func NewF38() distro.Distro {
return newDistro(38)
}
func NewF39() distro.Distro {
return newDistro(39)
}
func NewF40() distro.Distro {
return newDistro(40)
}
func newDistro(version int) distro.Distro {
rd := getDistro(version)
@ -843,6 +843,7 @@ func newDistro(version int) distro.Distro {
},
iotSimplifiedInstallerImgType,
)
aarch64.addImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{
@ -868,6 +869,63 @@ func newDistro(version int) distro.Distro {
)
}
if !common.VersionLessThan(rd.Releasever(), "39") {
// bootc was introduced in F39
x86_64.addImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"biosdevname",
"iwlwifi-dvm-firmware",
"iwlwifi-mvm-firmware",
"microcode_ctl",
},
},
BIOS: true,
UEFIVendor: "fedora",
},
iotBootableContainer,
)
aarch64.addImageTypes(
&platform.Aarch64{
BasePlatform: platform.BasePlatform{
FirmwarePackages: []string{
"arm-image-installer",
"bcm283x-firmware",
"brcmfmac-firmware",
"iwlwifi-mvm-firmware",
"realtek-firmware",
"uboot-images-armv8",
},
},
UEFIVendor: "fedora",
},
iotBootableContainer,
)
ppc64le.addImageTypes(
&platform.PPC64LE{
BIOS: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
iotBootableContainer,
)
s390x.addImageTypes(
&platform.S390X{
Zipl: true,
BasePlatform: platform.BasePlatform{
ImageFormat: platform.FORMAT_QCOW2,
QCOW2Compat: "1.1",
},
},
iotBootableContainer,
)
}
ppc64le.addImageTypes(
&platform.PPC64LE{
BIOS: true,
@ -901,3 +959,29 @@ func newDistro(version int) distro.Distro {
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 != "fedora" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
if id.MinorVersion != -1 {
return nil, fmt.Errorf("fedora distro does not support minor versions")
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.MajorVersion)
}

View file

@ -138,6 +138,19 @@ func osCustomizations(
panic(fmt.Sprintf("failed to convert file customizations to fs node files: %v", err))
}
// OSTree commits do not include data in `/var` since that is tied to the
// deployment, rather than the commit. Therefore the containers need to be
// stored in a different location, like `/usr/share`, and the container
// storage engine configured accordingly.
if t.rpmOstree && len(containers) > 0 {
storagePath := "/usr/share/containers/storage"
osc.ContainersStorage = &storagePath
}
if containerStorage := c.GetContainerStorage(); containerStorage != nil {
osc.ContainersStorage = containerStorage.StoragePath
}
customRepos, err := c.GetRepositories()
if err != nil {
// This shouldn't happen and since the repos
@ -410,6 +423,32 @@ func iotCommitImage(workload workload.Workload,
return img, nil
}
func bootableContainerImage(workload workload.Workload,
t *imageType,
bp *blueprint.Blueprint,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.SourceSpec,
rng *rand.Rand) (image.ImageKind, error) {
parentCommit, commitRef := makeOSTreeParentCommit(options.OSTree, t.OSTreeRef())
img := image.NewOSTreeArchive(commitRef)
d := t.arch.distro
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, bp.Customizations)
img.Environment = t.environment
img.Workload = workload
img.OSTreeParent = parentCommit
img.OSVersion = d.osVersion
img.Filename = t.Filename()
img.InstallWeakDeps = false
img.BootContainer = true
return img, nil
}
func iotContainerImage(workload workload.Workload,
t *imageType,
bp *blueprint.Blueprint,
@ -485,7 +524,8 @@ func iotInstallerImage(workload workload.Workload,
img.ISOLabelTempl = d.isolabelTmpl
img.Product = d.product
img.Variant = "IoT"
img.OSName = "fedora"
img.OSName = "fedora-iot"
img.Remote = "fedora-iot"
img.OSVersion = d.osVersion
img.Release = fmt.Sprintf("%s %s", d.product, d.osVersion)

View file

@ -7,7 +7,6 @@ import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/pathpolicy"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
@ -17,6 +16,7 @@ import (
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/policies"
"github.com/osbuild/images/pkg/rpmmd"
"golang.org/x/exp/slices"
)
@ -222,8 +222,14 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx := range bp.Containers {
containerSources[idx] = container.SourceSpec(bp.Containers[idx])
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
ContainersTransport: cont.ContainersTransport,
StoragePath: cont.StoragePath,
}
}
source := rand.NewSource(seed)
@ -256,6 +262,14 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return nil, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name)
}
if len(bp.Containers) > 0 {
for _, container := range bp.Containers {
if err := container.Validate(); err != nil {
return nil, err
}
}
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
@ -272,7 +286,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if t.name == "iot-raw-image" || t.name == "iot-qcow2-image" {
allowed := []string{"User", "Group", "Directories", "Files", "Services", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return nil, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer" in RHEL distros
}
@ -283,7 +297,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if t.name == "iot-simplified-installer" {
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return nil, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return nil, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name)
@ -321,12 +335,12 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
} else if t.name == "iot-installer" || t.name == "image-installer" {
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return nil, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
} else if t.name == "live-installer" {
allowed := []string{}
if err := customizations.CheckAllowed(allowed...); err != nil {
return nil, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: None)", t.name)
return nil, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name)
}
}
}
@ -341,7 +355,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return nil, fmt.Errorf("Custom mountpoints are not supported for ostree types")
}
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.MountpointPolicies)
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return nil, err
}
@ -368,12 +382,12 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return nil, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, pathpolicy.CustomDirectoriesPolicies)
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
if err != nil {
return nil, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, pathpolicy.CustomFilesPolicies)
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
if err != nil {
return nil, err
}
@ -384,5 +398,10 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return nil, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
return []string{w}, nil
}
return nil, nil
}

View file

@ -188,6 +188,104 @@ func iotCommitPackageSet(t *imageType) rpmmd.PackageSet {
return ps
}
func bootableContainerPackageSet(t *imageType) rpmmd.PackageSet {
// Replicating package selection from centos-bootc:
// https://github.com/CentOS/centos-bootc/
ps := rpmmd.PackageSet{
Include: []string{
"acl",
"attr", // used by admins interactively
"bootc",
"bootupd",
"chrony", // NTP support
"container-selinux",
"container-selinux",
"crun",
"cryptsetup",
"dnf",
"e2fsprogs",
"fwupd", // if you're using linux-firmware, you probably also want fwupd
"iproute", "iproute-tc", // route manipulation and QoS
"iptables", "nftables", // firewall manipulation
"iptables-services", // additional firewall support
"kbd", // i18n
"keyutils", // Manipulating the kernel keyring; used by bootc
"libsss_sudo", // allow communication between sudo and SSSD for caching sudo rules by SSSD
"linux-firmware", // linux-firmware now a recommends so let's explicitly include it
"logrotate", // There are things that write outside of the journal still (such as the classic wtmp, etc.). auditd also writes outside the journal but it has its own log rotation. Anything package layered will also tend to expect files dropped in /etc/logrotate.d to work. Really, this is a legacy thing, but if we don't have it then people's disks will slowly fill up with logs.
"lsof",
"lvm2", // Storage configuration/management
"nano", // default editor
"ncurses", // provides terminal tools like clear, reset, tput, and tset
"NetworkManager-cloud-setup", // support for cloud quirks and dynamic config in real rootfs: https://github.com/coreos/fedora-coreos-tracker/issues/320
"NetworkManager", "hostname", // standard tools for configuring network/hostname
"NetworkManager-team", "teamd", // teaming https://github.com/coreos/fedora-coreos-config/pull/289 and http://bugzilla.redhat.com/1758162
"NetworkManager-tui", // interactive Networking configuration during coreos-install
"nfs-utils-coreos", "iptables-nft", // minimal NFS client
"nss-altfiles",
"openssh-clients",
"openssh-server",
"openssl",
"ostree",
"passwd", "shadow-utils", // User configuration
"podman",
"rpm-ostree",
"selinux-policy-targeted",
"sg3_utils",
"skopeo",
"socat", "net-tools", "bind-utils", // interactive network tools for admins
"sssd-client", "sssd-ad", "sssd-ipa", "sssd-krb5", "sssd-ldap", // SSSD backends
"stalld", // Boost starving threads https://github.com/coreos/fedora-coreos-tracker/issues/753
"subscription-manager", // To ensure we can enable client certs to access RHEL content
"sudo",
"systemd",
"systemd-resolved", // resolved was broken out to its own package in rawhide/f35
"tpm2-tools", // needed for tpm2 bound luks
"WALinuxAgent-udev", // udev rules for Azure (rhbz#1748432)
"xfsprogs",
"zram-generator", // zram-generator (but not zram-generator-defaults) for F33 change
},
Exclude: []string{
"cowsay", // just in case
"grubby",
"initscripts", // make sure initscripts doesn't get pulled back in https://github.com/coreos/fedora-coreos-tracker/issues/220#issuecomment-611566254
"NetworkManager-initscripts-ifcfg-rh", // do not use legacy ifcfg config format in NetworkManager See https://github.com/coreos/fedora-coreos-config/pull/1991
"nodejs",
"perl",
"perl-interpreter",
"plymouth", // for (datacenter/cloud oriented) servers, we want to see the details by default. https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/HSMISZ3ETWQ4ETVLWZQJ55ARZT27AAV3/
"systemd-networkd", // we use NetworkManager
},
}
switch t.Arch().Name() {
case arch.ARCH_AARCH64.String():
ps.Append(rpmmd.PackageSet{
Include: []string{
"irqbalance",
"ostree-grub2",
},
})
case arch.ARCH_PPC64LE.String():
ps.Append(rpmmd.PackageSet{
Include: []string{
"irqbalance",
"librtas",
"powerpc-utils-core",
"ppc64-diag-rtas",
},
})
case arch.ARCH_X86_64.String():
ps.Append(rpmmd.PackageSet{
Include: []string{
"irqbalance",
},
})
}
return ps
}
// INSTALLER PACKAGE SET
func installerPackageSet(t *imageType) rpmmd.PackageSet {

50
vendor/github.com/osbuild/images/pkg/distro/host.go generated vendored Normal file
View file

@ -0,0 +1,50 @@
package distro
import (
"bufio"
"errors"
"io"
"os"
"strings"
)
// GetHostDistroName returns the name of the host distribution, such as
// "fedora-32" or "rhel-8.2". It does so by reading the /etc/os-release file.
func GetHostDistroName() (string, error) {
f, err := os.Open("/etc/os-release")
if err != nil {
return "", err
}
defer f.Close()
osrelease, err := readOSRelease(f)
if err != nil {
return "", err
}
name := osrelease["ID"] + "-" + osrelease["VERSION_ID"]
return name, nil
}
func readOSRelease(r io.Reader) (map[string]string, error) {
osrelease := make(map[string]string)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if len(line) == 0 {
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
return nil, errors.New("readOSRelease: invalid input")
}
key := strings.TrimSpace(parts[0])
// drop all surrounding whitespace and double-quotes
value := strings.Trim(strings.TrimSpace(parts[1]), "\"")
osrelease[key] = value
}
return osrelease, nil
}

82
vendor/github.com/osbuild/images/pkg/distro/id.go generated vendored Normal file
View file

@ -0,0 +1,82 @@
package distro
import (
"fmt"
"strconv"
"strings"
)
// ID represents a distro name and version
type ID struct {
Name string
MajorVersion int
// MinorVersion is -1 if not specified
MinorVersion int
}
func (id ID) String() string {
if id.MinorVersion == -1 {
return fmt.Sprintf("%s-%d", id.Name, id.MajorVersion)
}
return fmt.Sprintf("%s-%d.%d", id.Name, id.MajorVersion, id.MinorVersion)
}
type ParseError struct {
ToParse string
Msg string
Inner error
}
func (e ParseError) Error() string {
msg := fmt.Sprintf("error when parsing distro name (%s): %v", e.ToParse, e.Msg)
if e.Inner != nil {
msg += fmt.Sprintf(", inner error:\n%v", e.Inner)
}
return msg
}
// ParseID parses a distro name and version from a Distro ID string.
// This is the generic parser, which is used by all distros as the base parser.
//
// Limitations:
// - the distro name must not contain a dash
func ParseID(idStr string) (*ID, error) {
idParts := strings.Split(idStr, "-")
if len(idParts) < 2 {
return nil, ParseError{ToParse: idStr, Msg: "A dash is expected to separate distro name and version"}
}
name := strings.Join(idParts[:len(idParts)-1], "-")
version := idParts[len(idParts)-1]
versionParts := strings.Split(version, ".")
if len(versionParts) > 2 {
return nil, ParseError{ToParse: idStr, Msg: fmt.Sprintf("too many dots in the version (%d)", len(versionParts)-1)}
}
majorVersion, err := strconv.Atoi(versionParts[0])
if err != nil {
return nil, ParseError{ToParse: idStr, Msg: "parsing major version failed", Inner: err}
}
minorVersion := -1
if len(versionParts) > 1 {
minorVersion, err = strconv.Atoi(versionParts[1])
if err != nil {
return nil, ParseError{ToParse: idStr, Msg: "parsing minor version failed", Inner: err}
}
}
return &ID{
Name: name,
MajorVersion: majorVersion,
MinorVersion: minorVersion,
}, nil
}

View file

@ -48,21 +48,6 @@ var defaultDistroImageConfig = &distro.ImageConfig{
},
}
// distribution objects without the arches > image types
var distroMap = map[string]distribution{
"rhel-7": {
name: "rhel-7",
product: "Red Hat Enterprise Linux",
osVersion: "7.9",
nick: "Maipo",
releaseVersion: "7",
modulePlatformID: "platform:el7",
vendor: "redhat",
runner: &runner.RHEL{Major: uint64(7), Minor: uint64(9)},
defaultImageConfig: defaultDistroImageConfig,
},
}
// --- Distribution ---
type distribution struct {
name string
@ -193,14 +178,24 @@ func (a *architecture) Distro() distro.Distro {
return a.distro
}
// New creates a new distro object, defining the supported architectures and image types
func New() distro.Distro {
return newDistro("rhel-7")
}
func newDistro(distroName string) distro.Distro {
rd := distroMap[distroName]
func newDistro(name string, minor int) *distribution {
var rd distribution
switch name {
case "rhel":
rd = distribution{
name: fmt.Sprintf("rhel-7.%d", minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("7.%d", minor),
nick: "Maipo",
releaseVersion: "7",
modulePlatformID: "platform:el7",
vendor: "redhat",
runner: &runner.RHEL{Major: uint64(7), Minor: uint64(minor)},
defaultImageConfig: defaultDistroImageConfig,
}
default:
panic(fmt.Sprintf("unknown distro name: %s", name))
}
// Architecture definitions
x86_64 := architecture{
@ -237,3 +232,33 @@ func newDistro(distroName string) distro.Distro {
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

@ -5,7 +5,6 @@ import (
"math/rand"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/pathpolicy"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
@ -14,6 +13,7 @@ import (
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/policies"
"github.com/osbuild/images/pkg/rpmmd"
"golang.org/x/exp/slices"
)
@ -198,8 +198,14 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx := range bp.Containers {
containerSources[idx] = container.SourceSpec(bp.Containers[idx])
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
ContainersTransport: cont.ContainersTransport,
StoragePath: cont.StoragePath,
}
}
source := rand.NewSource(seed)
@ -237,7 +243,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
// set of customizations. The current set of customizations defined in
// the blueprint spec corresponds to the Custom workflow.
if customizations != nil {
return warnings, fmt.Errorf("image type %q does not support customizations", t.name)
return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name)
}
}
@ -247,7 +253,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
mountpoints := customizations.GetFilesystems()
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.MountpointPolicies)
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
@ -265,12 +271,12 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, pathpolicy.CustomDirectoriesPolicies)
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, pathpolicy.CustomFilesPolicies)
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
if err != nil {
return warnings, err
}

View file

@ -123,53 +123,12 @@ func (d *distribution) getDefaultImageConfig() *distro.ImageConfig {
return d.defaultImageConfig
}
// New creates a new distro object, defining the supported architectures and image types
func New() distro.Distro {
// default minor: create default minor version (current GA) and rename it
d := newDistro("rhel", 10)
d.name = "rhel-8"
return d
}
func NewRHEL84() distro.Distro {
return newDistro("rhel", 4)
}
func NewRHEL85() distro.Distro {
return newDistro("rhel", 5)
}
func NewRHEL86() distro.Distro {
return newDistro("rhel", 6)
}
func NewRHEL87() distro.Distro {
return newDistro("rhel", 7)
}
func NewRHEL88() distro.Distro {
return newDistro("rhel", 8)
}
func NewRHEL89() distro.Distro {
return newDistro("rhel", 9)
}
func NewRHEL810() distro.Distro {
return newDistro("rhel", 10)
}
func NewCentos() distro.Distro {
return newDistro("centos", 0)
}
func newDistro(name string, minor int) *distribution {
var rd distribution
switch name {
case "rhel":
rd = distribution{
name: fmt.Sprintf("rhel-8%d", minor),
name: fmt.Sprintf("rhel-8.%d", minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("8.%d", minor),
releaseVersion: "8",
@ -517,3 +476,52 @@ func newDistro(name string, minor int) *distribution {
rd.addArches(x86_64, aarch64, ppc64le)
return &rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
// Backward compatibility layer for "rhel-84" or "rhel-810"
if id.Name == "rhel" && id.MinorVersion == -1 {
if id.MajorVersion/10 == 8 {
// handle single digit minor version
id.MinorVersion = id.MajorVersion % 10
id.MajorVersion = 8
} else if id.MajorVersion/100 == 8 {
// handle two digit minor version
id.MinorVersion = id.MajorVersion % 100
id.MajorVersion = 8
}
}
if id.MajorVersion != 8 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, id.MinorVersion)
}

View file

@ -155,6 +155,19 @@ func osCustomizations(
panic(fmt.Sprintf("failed to convert file customizations to fs node files: %v", err))
}
// OSTree commits do not include data in `/var` since that is tied to the
// deployment, rather than the commit. Therefore the containers need to be
// stored in a different location, like `/usr/share`, and the container
// storage engine configured accordingly.
if t.rpmOstree && len(containers) > 0 {
storagePath := "/usr/share/containers/storage"
osc.ContainersStorage = &storagePath
}
if containerStorage := c.GetContainerStorage(); containerStorage != nil {
osc.ContainersStorage = containerStorage.StoragePath
}
// set yum repos first, so it doesn't get overridden by
// imageConfig.YUMRepos
osc.YUMRepos = imageConfig.YUMRepos

View file

@ -10,7 +10,6 @@ import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/pathpolicy"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
@ -20,6 +19,7 @@ import (
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/policies"
"github.com/osbuild/images/pkg/rpmmd"
)
@ -243,8 +243,14 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx := range bp.Containers {
containerSources[idx] = container.SourceSpec(bp.Containers[idx])
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
ContainersTransport: cont.ContainersTransport,
StoragePath: cont.StoragePath,
}
}
source := rand.NewSource(seed)
@ -282,7 +288,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
// set of customizations. The current set of customizations defined in
// the blueprint spec corresponds to the Custom workflow.
if customizations != nil {
return warnings, fmt.Errorf("image type %q does not support customizations", t.name)
return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name)
}
}
// we do not support embedding containers on ostree-derived images, only on commits themselves
@ -290,6 +296,14 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name)
}
if len(bp.Containers) > 0 {
for _, container := range bp.Containers {
if err := container.Validate(); err != nil {
return nil, err
}
}
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
@ -305,7 +319,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if t.name == "edge-simplified-installer" {
allowed := []string{"InstallationDevice", "FDO", "User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name)
@ -332,7 +346,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
} else if t.name == "edge-installer" {
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
}
}
@ -345,7 +359,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer"
}
@ -375,7 +389,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, fmt.Errorf("Custom mountpoints are not supported for ostree types")
}
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.MountpointPolicies)
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
@ -403,12 +417,12 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if err != nil {
return warnings, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, pathpolicy.CustomDirectoriesPolicies)
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, pathpolicy.CustomFilesPolicies)
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
if err != nil {
return warnings, err
}
@ -419,5 +433,11 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
return warnings, nil
}

View file

@ -125,43 +125,12 @@ func (d *distribution) getDefaultImageConfig() *distro.ImageConfig {
return d.defaultImageConfig
}
func New() distro.Distro {
// default minor: create default minor version (current GA) and rename it
d := newDistro("rhel", 4)
d.name = "rhel-9"
return d
}
func NewCentOS9() distro.Distro {
return newDistro("centos", 0)
}
func NewRHEL90() distro.Distro {
return newDistro("rhel", 0)
}
func NewRHEL91() distro.Distro {
return newDistro("rhel", 1)
}
func NewRHEL92() distro.Distro {
return newDistro("rhel", 2)
}
func NewRHEL93() distro.Distro {
return newDistro("rhel", 3)
}
func NewRHEL94() distro.Distro {
return newDistro("rhel", 4)
}
func newDistro(name string, minor int) *distribution {
var rd distribution
switch name {
case "rhel":
rd = distribution{
name: fmt.Sprintf("rhel-9%d", minor),
name: fmt.Sprintf("rhel-9.%d", minor),
product: "Red Hat Enterprise Linux",
osVersion: fmt.Sprintf("9.%d", minor),
releaseVersion: "9",
@ -494,3 +463,49 @@ func newDistro(name string, minor int) *distribution {
rd.addArches(x86_64, aarch64, ppc64le, s390x)
return &rd
}
func ParseID(idStr string) (*distro.ID, error) {
id, err := distro.ParseID(idStr)
if err != nil {
return nil, err
}
if id.Name != "rhel" && id.Name != "centos" {
return nil, fmt.Errorf("invalid distro name: %s", id.Name)
}
// Backward compatibility layer for "rhel-93" and friends
if id.Name == "rhel" && id.MinorVersion == -1 {
if id.MajorVersion/10 == 9 {
// handle single digit minor version
id.MinorVersion = id.MajorVersion % 10
id.MajorVersion = 9
}
// two digit minor versions in the old format are not supported
}
if id.MajorVersion != 9 {
return nil, fmt.Errorf("invalid distro major version: %d", id.MajorVersion)
}
// CentOS does not use minor version
if id.Name == "centos" && id.MinorVersion != -1 {
return nil, fmt.Errorf("centos does not use minor version, but got: %d", id.MinorVersion)
}
// RHEL uses minor version
if id.Name == "rhel" && id.MinorVersion == -1 {
return nil, fmt.Errorf("rhel requires minor version, but got: %d", id.MinorVersion)
}
return id, nil
}
func DistroFactory(idStr string) distro.Distro {
id, err := ParseID(idStr)
if err != nil {
return nil
}
return newDistro(id.Name, id.MinorVersion)
}

View file

@ -152,6 +152,19 @@ func osCustomizations(
panic(fmt.Sprintf("failed to convert file customizations to fs node files: %v", err))
}
// OSTree commits do not include data in `/var` since that is tied to the
// deployment, rather than the commit. Therefore the containers need to be
// stored in a different location, like `/usr/share`, and the container
// storage engine configured accordingly.
if t.rpmOstree && len(containers) > 0 {
storagePath := "/usr/share/containers/storage"
osc.ContainersStorage = &storagePath
}
if containerStorage := c.GetContainerStorage(); containerStorage != nil {
osc.ContainersStorage = containerStorage.StoragePath
}
// set yum repos first, so it doesn't get overridden by
// imageConfig.YUMRepos
osc.YUMRepos = imageConfig.YUMRepos

View file

@ -10,7 +10,6 @@ import (
"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/internal/environment"
"github.com/osbuild/images/internal/pathpolicy"
"github.com/osbuild/images/internal/workload"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/container"
@ -20,6 +19,7 @@ import (
"github.com/osbuild/images/pkg/image"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/policies"
"github.com/osbuild/images/pkg/rpmmd"
)
@ -243,8 +243,14 @@ func (t *imageType) Manifest(bp *blueprint.Blueprint,
}
containerSources := make([]container.SourceSpec, len(bp.Containers))
for idx := range bp.Containers {
containerSources[idx] = container.SourceSpec(bp.Containers[idx])
for idx, cont := range bp.Containers {
containerSources[idx] = container.SourceSpec{
Source: cont.Source,
Name: cont.Name,
TLSVerify: cont.TLSVerify,
ContainersTransport: cont.ContainersTransport,
StoragePath: cont.StoragePath,
}
}
source := rand.NewSource(seed)
@ -281,7 +287,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
// set of customizations. The current set of customizations defined in
// the blueprint spec corresponds to the Custom workflow.
if customizations != nil {
return warnings, fmt.Errorf("image type %q does not support customizations", t.name)
return warnings, fmt.Errorf(distro.NoCustomizationsAllowedError, t.name)
}
}
@ -290,6 +296,14 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name)
}
if len(bp.Containers) > 0 {
for _, container := range bp.Containers {
if err := container.Validate(); err != nil {
return nil, err
}
}
}
if options.OSTree != nil {
if err := options.OSTree.Validate(); err != nil {
return nil, err
@ -305,7 +319,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if t.name == "edge-simplified-installer" {
allowed := []string{"InstallationDevice", "FDO", "Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
if customizations.GetInstallationDevice() == "" {
return warnings, fmt.Errorf("boot ISO image type %q requires specifying an installation device to install to", t.name)
@ -343,7 +357,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
} else if t.name == "edge-installer" {
allowed := []string{"User", "Group", "FIPS"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for boot ISO image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
}
}
@ -355,7 +369,7 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
}
allowed := []string{"Ignition", "Kernel", "User", "Group", "FIPS", "Filesystem"}
if err := customizations.CheckAllowed(allowed...); err != nil {
return warnings, fmt.Errorf("unsupported blueprint customizations found for image type %q: (allowed: %s)", t.name, strings.Join(allowed, ", "))
return warnings, fmt.Errorf(distro.UnsupportedCustomizationError, t.name, strings.Join(allowed, ", "))
}
// TODO: consider additional checks, such as those in "edge-simplified-installer"
}
@ -384,13 +398,13 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, fmt.Errorf("Custom mountpoints are not supported for edge-container and edge-commit")
} else if mountpoints != nil && t.rpmOstree && !(t.name == "edge-container" || t.name == "edge-commit") {
//customization allowed for edge-raw-image,edge-ami,edge-vsphere,edge-simplified-installer
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.OstreeMountpointPolicies)
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.OstreeMountpointPolicies)
if err != nil {
return warnings, err
}
}
err := blueprint.CheckMountpointsPolicy(mountpoints, pathpolicy.MountpointPolicies)
err := blueprint.CheckMountpointsPolicy(mountpoints, policies.MountpointPolicies)
if err != nil {
return warnings, err
}
@ -418,12 +432,12 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
if err != nil {
return warnings, err
}
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, pathpolicy.CustomDirectoriesPolicies)
err = blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.CustomDirectoriesPolicies)
if err != nil {
return warnings, err
}
err = blueprint.CheckFileCustomizationsPolicy(fc, pathpolicy.CustomFilesPolicies)
err = blueprint.CheckFileCustomizationsPolicy(fc, policies.CustomFilesPolicies)
if err != nil {
return warnings, err
}
@ -434,5 +448,11 @@ func (t *imageType) checkOptions(bp *blueprint.Blueprint, options distro.ImageOp
return warnings, err
}
if customizations.GetFIPS() && !common.IsBuildHostFIPSEnabled() {
w := fmt.Sprintln(common.FIPSEnabledImageWarning)
log.Print(w)
warnings = append(warnings, w)
}
return warnings, nil
}

View file

@ -7,7 +7,6 @@ import (
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/distro"
"github.com/osbuild/images/pkg/distroregistry"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/ostree"
"github.com/osbuild/images/pkg/rpmmd"
@ -46,12 +45,13 @@ type TestImageType struct {
}
const (
TestDistroName = "test-distro"
TestDistro2Name = "test-distro-2"
TestDistroReleasever = "1"
TestDistro2Releasever = "2"
TestDistroModulePlatformID = "platform:test"
TestDistro2ModulePlatformID = "platform:test-2"
// The Test Distro name base. It can't be used to get a distro.Distro
// instance from the DistroFactory(), because it does not include any
// release version.
TestDistroNameBase = "test-distro"
// An ID string for a Test Distro instance with release version 1.
TestDistro1Name = TestDistroNameBase + "-1"
TestArchName = "test_arch"
TestArch2Name = "test_arch2"
@ -294,18 +294,18 @@ func (t *TestImageType) Manifest(b *blueprint.Blueprint, options distro.ImageOpt
return m, nil, nil
}
// NewTestDistro returns a new instance of TestDistro with the
// given name and modulePlatformID.
// newTestDistro returns a new instance of TestDistro with the
// given release version.
//
// It contains two architectures "test_arch" and "test_arch2".
// "test_arch" contains one image type "test_type".
// "test_arch2" contains two image types "test_type" and "test_type2".
func NewTestDistro(name, modulePlatformID, releasever string) *TestDistro {
func newTestDistro(releasever string) *TestDistro {
td := TestDistro{
name: name,
name: fmt.Sprintf("%s-%s", TestDistroNameBase, releasever),
releasever: releasever,
modulePlatformID: modulePlatformID,
ostreeRef: "test/13/x86_64/edge",
modulePlatformID: fmt.Sprintf("platform:%s-%s", TestDistroNameBase, releasever),
ostreeRef: fmt.Sprintf("test/%s/x86_64/edge", releasever),
}
ta1 := TestArch{
@ -373,19 +373,19 @@ func NewTestDistro(name, modulePlatformID, releasever string) *TestDistro {
return &td
}
// New returns new instance of TestDistro named "test-distro".
func New() *TestDistro {
return NewTestDistro(TestDistroName, TestDistroModulePlatformID, TestDistroReleasever)
}
func NewRegistry() *distroregistry.Registry {
td := New()
registry, err := distroregistry.New(td, td)
func DistroFactory(idStr string) distro.Distro {
id, err := distro.ParseID(idStr)
if err != nil {
panic(err)
return nil
}
// Override the host's architecture name with the test's name
registry.SetHostArchName(TestArchName)
return registry
if id.Name != TestDistroNameBase {
return nil
}
if id.MinorVersion != -1 {
return nil
}
return newTestDistro(fmt.Sprint(id.MajorVersion))
}