Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 161 additions & 1 deletion data/distrodefs/fedora/imagetypes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,97 @@
aarch64:
<<: *iot_simplified_installer_partition_tables_x86

supported_options_lists:
# common options supported by all disk image types this includes everything
# that is not specific to installers or ostree-based images
supported_options_disk: &supported_options_disk
- "name"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(wondering) Should we make name/version/description implicit? They are not really concepts that are relevant for the image types, i.e. it would be weird to have an image type that refuses a blueprint with a "name"?

Similar wondering about "distro", it goes away in UBP and its a bit of a odd one, so maybe the image types should not list it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that hiding it makes it slightly more difficult to get up to speed with it. It's supposed to be a list of blueprint fields, just make it 1:1 without any magic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to do this but since it might be up for discussion, let's reconsider it in a follow-up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, after a bit of time to think about this I'm less and less convinced we should make this explicit. Name/Description/Version are essentially metadata and not customizations, adding it to our yaml like this will be confusing for people creating image types because they will wonder why this is something that needs to be explicitly allow-listed. It will also just lead to a unnecessary boilerplate. Sorry for being so negative, I will not block this but I don't think its right thing to do.

- "version"
- "description"
- "distro"
- "packages"
- "modules"
- "groups"
- "containers"
- "minimal"
- "customizations.cacerts"
- "customizations.directories"
- "customizations.disk"
- "customizations.files"
- "customizations.filesystem"
- "customizations.partitioning_mode"
- "customizations.fips"
- "customizations.firewall"
- "customizations.user"
- "customizations.sshkey"
- "customizations.group"
- "customizations.hostname"
- "customizations.kernel"
- "customizations.locale"
- "customizations.openscap"
- "customizations.repositories"
- "customizations.rpm"
- "customizations.services"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing customizations.sshkey and customizations.partition_mode which I stumbled into by accident when trying a blueprint I had laying around from something else, not through any thorough examination so there may be others :/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The former only exists in osbuild-composer and (AFAIK) gets translated to a customizations.user we mention it as deprecated in the documentation though I've gotten bitten by it before as well.

The latter is indeed missing and documented to exist.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into this, I think it will cause a problem though.

Projects that use the blueprint generally shouldn't have to worry about the sshkey customization, because they should use the GetUsers() method, which merges ssh keys with users. But the validator doesn't care about that and uses reflection to check any set properties. So if a blueprint goes into the validator and has ssh keys set, it will fail to validate. Deprecated or not, we should consider it supported here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorted.

- "customizations.timezone"

# options supported by base ostree image types (commit and container)
supported_options_ostree_commit: &supported_options_ostree_commit
- "name"
- "version"
- "description"
- "distro"
- "packages"
- "modules"
- "groups"
- "minimal"
- "customizations.directories"
- "customizations.files"
- "customizations.fips"
- "customizations.firewall"
- "customizations.user"
- "customizations.sshkey"
- "customizations.group"
- "customizations.hostname"
- "customizations.kernel.name"
- "customizations.locale"
- "customizations.repositories"
- "customizations.services"
- "customizations.timezone"

# options supported by ostree disk (deployment) image types
supported_options_ostree_disk: &supported_options_ostree_disk
- "name"
- "version"
- "description"
- "distro"
- "customizations.files"
- "customizations.directories"
- "customizations.disk"
- "customizations.filesystem"
- "customizations.partitioning_mode"
- "customizations.fips"
- "customizations.user"
- "customizations.sshkey"
- "customizations.group"
- "customizations.kernel.append"
- "customizations.locale"
- "customizations.services"

# options supported by Anaconda installer (ISO) image types
supported_options_anaconda: &supported_options_anaconda
- "name"
- "version"
- "description"
- "distro"
- "customizations.installer"
- "customizations.user"
- "customizations.sshkey"
- "customizations.group"
- "customizations.fips"
- "customizations.timezone"
- "customizations.locale"


image_config:
default:
default_oscap_datastream: "/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml"
Expand Down Expand Up @@ -813,6 +904,7 @@ image_types:
image_format: "vagrant_libvirt"
- <<: *aarch64_platform
image_format: "vagrant_libvirt"
supported_blueprint_options: *supported_options_disk

"server-vagrant-virtualbox": &server_vagrant_virtualbox
<<: *server_vagrant_libvirt
Expand Down Expand Up @@ -863,6 +955,7 @@ image_types:
image_format: "qcow2"
- <<: *s390x_zipl_platform
image_format: "qcow2"
supported_blueprint_options: *supported_options_disk

"server-ami":
<<: *server_qcow2
Expand Down Expand Up @@ -970,6 +1063,7 @@ image_types:
- "zram-generator-defaults"
- "grubby-deprecated"
- "extlinux-bootloader"
supported_blueprint_options: *supported_options_disk

"server-ova":
<<: *server_vmdk
Expand Down Expand Up @@ -1135,6 +1229,7 @@ image_types:
append:
include:
- "filesystem"
supported_blueprint_options: *supported_options_ostree_commit

"iot-container":
<<: *iot_commit
Expand Down Expand Up @@ -1228,6 +1323,7 @@ image_types:
- *iot_base_partition_table_part_efi_aarch64
- *iot_base_partition_table_part_boot_aarch64
- *iot_base_partition_table_part_root_fstab_ro_aarch64
supported_blueprint_options: *supported_options_ostree_disk

"iot-qcow2":
<<: *rpm_ostree_imgtype_common
Expand Down Expand Up @@ -1255,6 +1351,7 @@ image_types:
- <<: *aarch64_platform
image_format: "qcow2"
qcow2_compat: "1.1"
supported_blueprint_options: *supported_options_ostree_disk

"iot-bootable-container":
<<: *rpm_ostree_imgtype_common
Expand Down Expand Up @@ -1401,6 +1498,17 @@ image_types:
exclude:
- "perl"
- "perl-interpreter"
supported_blueprint_options:
# Only supporting a few basic options for now because we never tested any
# other customization with this image type
- "name"
- "version"
- "description"
- "distro"
- "packages"
- "modules"
- "groups"
- "minimal"

"minimal-raw-xz": &minimal_raw_xz
name_aliases: ["minimal-raw"]
Expand Down Expand Up @@ -1494,6 +1602,8 @@ image_types:
append:
exclude:
- "firewalld"
supported_blueprint_options: *supported_options_disk

"minimal-raw-zst":
<<: *minimal_raw_xz
name_aliases: []
Expand Down Expand Up @@ -1529,6 +1639,7 @@ image_types:
platforms:
- *x86_64_installer_platform
- *aarch64_installer_platform
supported_blueprint_options: *supported_options_anaconda

"workstation-live-installer":
name_aliases: ["live-installer"]
Expand All @@ -1540,7 +1651,7 @@ image_types:
iso_label: "Workstation"
exports: ["bootiso"]
required_partition_sizes: *default_required_dir_sizes
installer_config:
installer_config:
<<: *default_installer_config
# for some reason the live-installer never had or never took into account
# the additional dracut modules. This might be a bug but for now we reset
Expand Down Expand Up @@ -1595,6 +1706,12 @@ image_types:
platforms:
- *x86_64_installer_platform
- *aarch64_installer_platform
supported_blueprint_options:
- "name"
- "version"
- "description"
- "distro"
- "customizations.installer"

"minimal-installer":
name_aliases: ["image-installer", "fedora-image-installer"]
Expand Down Expand Up @@ -1637,6 +1754,7 @@ image_types:
- *minimal_raw_pkgset
installer:
- *anaconda_pkgset
supported_blueprint_options: *supported_options_anaconda

container: &container
filename: "container.tar"
Expand Down Expand Up @@ -1702,6 +1820,17 @@ image_types:
- "trousers"
- "whois-nls"
- "xkeyboard-config"
supported_blueprint_options:
# Only supporting a few basic options for now because we never tested any
# other customization with this image type
- "name"
- "version"
- "description"
- "distro"
- "packages"
- "modules"
- "groups"
- "minimal"

wsl:
# this is the eventual name, and `wsl` the alias but we've been
Expand Down Expand Up @@ -1807,6 +1936,17 @@ image_types:
append:
exclude:
- "fuse-libs"
supported_blueprint_options:
# Only supporting a few basic options for now because we never tested any
# other customization with this image type
- "name"
- "version"
- "description"
- "distro"
- "packages"
- "modules"
- "groups"
- "minimal"

"iot-simplified-installer":
<<: *rpm_ostree_imgtype_common
Expand Down Expand Up @@ -1927,6 +2067,21 @@ image_types:
- "iwlwifi-mvm-firmware"
- "realtek-firmware"
- "uboot-images-armv8"
supported_blueprint_options:
- "name"
- "version"
- "description"
- "distro"
- "customizations.installation_device"
- "customizations.fdo"
- "customizations.ignition"
- "customizations.kernel"
- "customizations.user"
- "customizations.sshkey"
- "customizations.group"
- "customizations.fips"
required_blueprint_options:
- "customizations.installation_device"

# Based on lorax runtime-install.tmpl
"everything-netinst":
Expand Down Expand Up @@ -2039,3 +2194,8 @@ image_types:
platforms:
- *x86_64_installer_platform
- *aarch64_installer_platform
supported_blueprint_options:
- "name"
- "version"
- "description"
- "distro"
3 changes: 3 additions & 0 deletions pkg/distro/defs/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ type ImageTypeYAML struct {

SupportedPartitioningModes []partition.PartitioningMode `yaml:"supported_partitioning_modes"`

SupportedBlueprintOptions []string `yaml:"supported_blueprint_options"`
RequiredBlueprintOptions []string `yaml:"required_blueprint_options"`

// name is set by the loader
name string
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/distro/distro.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ type ImageType interface {
// Returns the names of the stages that will produce the build output.
Exports() []string

// A list of customization options that this image requires.
RequiredBlueprintOptions() []string

// A list of customization options that this image supports.
SupportedBlueprintOptions() []string

// Returns an osbuild manifest, containing the sources and pipeline necessary
// to build an image, given output format with all packages and customizations
// specified in the given blueprint; it also returns any warnings (e.g.
Expand Down
32 changes: 27 additions & 5 deletions pkg/distro/distro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,19 @@ func TestPipelineRepositories(t *testing.T) {
// based on this information. For image types with
// a preset workload, payload packages are ignored
// and dropped.
// This is now supported in Fedora. RHEL coming
// soon.
continue
}
t.Run(fmt.Sprintf("%s/%s/%s", distroName, archName, imageTypeName), func(t *testing.T) {
t.Parallel()
require := require.New(t)
imageType, err := arch.GetImageType(imageTypeName)
require.Nil(err)
// skip any image type that does not support custom packages
if !slices.Contains(imageType.SupportedBlueprintOptions(), "packages") {
return
}

// set up bare minimum args for image type
var customizations *blueprint.Customizations
Expand Down Expand Up @@ -589,6 +595,7 @@ func TestDistro_ManifestFIPSWarning(t *testing.T) {
noCustomizableImages := []string{
"workstation-live-installer",
"azure-eap7-rhui",
"container",
}

distroFactory := distrofactory.NewDefault()
Expand Down Expand Up @@ -626,12 +633,27 @@ func TestDistro_ManifestFIPSWarning(t *testing.T) {
bp.Customizations.InstallationDevice = "/dev/dummy"
}
_, warn, err := imgType.Manifest(&bp, imgOpts, nil, nil)
if err != nil {
assert.True(t, slices.Contains(noCustomizableImages, imgTypeName))
assert.Equal(t, err, fmt.Errorf(distro.NoCustomizationsAllowedError, imgTypeName))
if strings.Contains(distroName, "fedora") {
// NOTE: Fedora uses the new customization validation
// functionality which produces different error
// messages. These will be added to RHEL as well soon.
switch imgTypeName {
case "workstation-live-installer":
assert.EqualError(t, err, fmt.Sprintf("blueprint validation failed for image type %q: customizations.fips: not supported", imgTypeName))
case "wsl", "iot-bootable-container", "container", "everything-netinst":
assert.EqualError(t, err, fmt.Sprintf("blueprint validation failed for image type %q: customizations: not supported", imgTypeName))
default:
assert.Equal(t, slices.Contains(warn, msg), !common.IsBuildHostFIPSEnabled(),
"FIPS warning not shown for image: distro='%s', imgTypeName='%s', archName='%s', warn='%v'", distroName, imgTypeName, archName, warn)
}
} else {
assert.Equal(t, slices.Contains(warn, msg), !common.IsBuildHostFIPSEnabled(),
"FIPS warning not shown for image: distro='%s', imgTypeName='%s', archName='%s', warn='%v'", distroName, imgTypeName, archName, warn)
if err != nil {
assert.True(t, slices.Contains(noCustomizableImages, imgTypeName))
assert.Equal(t, err, fmt.Errorf(distro.NoCustomizationsAllowedError, imgTypeName))
} else {
assert.Equal(t, slices.Contains(warn, msg), !common.IsBuildHostFIPSEnabled(),
"FIPS warning not shown for image: distro='%s', imgTypeName='%s', archName='%s', warn='%v'", distroName, imgTypeName, archName, warn)
}
}
})
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/distro/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package distro

import "reflect"

// We wrap our internal functions in exported functions instead of defining
// aliases so we can return an error type instead of validationError. Our
// recursive functions need to return validationError so that the path can be
// constructed when returning up the stack. But if the function at the top
// returns a nil valued validationError, it will fail the NoError() check. This
// is not a problem outside of testing since the public entrypoint,
// ValidateConfig(), returns nil when everything is ok.

func ValidateSupportedConfig(supported []string, conf reflect.Value) error {
if err := validateSupportedConfig(supported, conf); err != nil {
return err
}
return nil
}

func ValidateRequiredConfig(required []string, conf reflect.Value) error {
if err := validateRequiredConfig(required, conf); err != nil {
return err
}
return nil
}
Loading
Loading