manifest: support for container embedding

Adding support for container embedding.
The containers need to be specified in the image function (imageFunc)
arguments and when specified, propagate down to the OS pipeline
generator to add the necessary stages.

Support is added for RHEL 9.x and Fedora.

Requires a temporary container spec array with the info from the
blueprint for the first initialization of the manifest that's needed
when collecting required packages.
This should be simplified in the future.
This commit is contained in:
Achilleas Koutsou 2022-11-08 13:08:50 +01:00 committed by Christian Kellner
parent c4b5c229fb
commit 09903bd0db
9 changed files with 118 additions and 22 deletions

View file

@ -464,7 +464,7 @@ func (a *architecture) Distro() distro.Distro {
return a.distro
}
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, rng *rand.Rand) (image.ImageKind, error)
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.Spec, rng *rand.Rand) (image.ImageKind, error)
type packageSetFunc func(t *imageType) rpmmd.PackageSet
@ -574,8 +574,19 @@ func (t *imageType) PackageSets(bp blueprint.Blueprint, options distro.ImageOpti
logrus.Warn("FIXME: Requesting package sets for iot-installer without a resolved ostree ref. Faking one.")
}
// create a temporary container spec array with the info from the blueprint
// to initialize the manifest
containers := make([]container.Spec, len(bp.Containers))
for idx := range bp.Containers {
containers[idx] = container.Spec{
Source: bp.Containers[idx].Source,
TLSVerify: bp.Containers[idx].TLSVerify,
LocalName: bp.Containers[idx].Name,
}
}
// create a manifest object and instantiate it with the computed packageSetChains
manifest, err := t.initializeManifest(&bp, options, globalRepos, packageSets, nil, 0)
manifest, err := t.initializeManifest(&bp, options, globalRepos, packageSets, containers, 0)
if err != nil {
// TODO: handle manifest initialization errors more gracefully, we
// refuse to initialize manifests with invalid config.
@ -674,7 +685,7 @@ func (t *imageType) initializeManifest(bp *blueprint.Blueprint,
/* #nosec G404 */
rng := rand.New(source)
img, err := t.image(w, t, bp.Customizations, options, packageSets, rng)
img, err := t.image(w, t, bp.Customizations, options, packageSets, containers, rng)
if err != nil {
return nil, err
}
@ -711,7 +722,8 @@ func (t *imageType) Manifest(customizations *blueprint.Customizations,
// checkOptions checks the validity and compatibility of options and customizations for the image type.
func (t *imageType) checkOptions(customizations *blueprint.Customizations, options distro.ImageOptions, containers []container.Spec) error {
if len(containers) > 0 {
// we do not support embedding containers on ostree-derived images, only on commits themselves
if len(containers) > 0 && t.rpmOstree && (t.name != "iot-commit" && t.name != "iot-container") {
return fmt.Errorf("embedding containers is not supported for %s on %s", t.name, t.arch.distro.name)
}

View file

@ -7,6 +7,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/container"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/image"
"github.com/osbuild/osbuild-composer/internal/manifest"
@ -22,6 +23,7 @@ import (
func osCustomizations(
t *imageType,
osPackageSet rpmmd.PackageSet,
containers []container.Spec,
c *blueprint.Customizations) manifest.OSCustomizations {
imageConfig := t.getDefaultImageConfig()
@ -45,6 +47,8 @@ func osCustomizations(
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories
osc.Containers = containers
osc.GPGKeyFiles = imageConfig.GPGKeyFiles
if imageConfig.ExcludeDocs != nil {
osc.ExcludeDocs = *imageConfig.ExcludeDocs
@ -153,11 +157,12 @@ func liveImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewLiveImage()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, customizations)
img.Environment = t.environment
img.Workload = workload
// TODO: move generation into LiveImage
@ -177,11 +182,12 @@ func containerImage(workload workload.Workload,
c *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewBaseContainer()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], c)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, c)
img.Environment = t.environment
img.Workload = workload
@ -195,6 +201,7 @@ func imageInstallerImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewImageInstaller()
@ -212,7 +219,7 @@ func imageInstallerImage(workload workload.Workload,
}
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, customizations)
img.ExtraBasePackages = packageSets[installerPkgsKey]
img.Users = users.UsersFromBP(customizations.GetUsers())
img.Groups = users.GroupsFromBP(customizations.GetGroups())
@ -235,12 +242,13 @@ func iotCommitImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewOSTreeArchive(options.OSTree.ImageRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, customizations)
img.Environment = t.environment
img.Workload = workload
@ -264,12 +272,13 @@ func iotContainerImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewOSTreeContainer(options.OSTree.ImageRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], containers, customizations)
img.ContainerLanguage = img.OSCustomizations.Language
img.Environment = t.environment
img.Workload = workload
@ -296,6 +305,7 @@ func iotInstallerImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
d := t.arch.distro
@ -330,6 +340,7 @@ func iotRawImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
commit := ostree.CommitSpec{

View file

@ -5,6 +5,7 @@ import (
"math/rand"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/container"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/image"
"github.com/osbuild/osbuild-composer/internal/manifest"
@ -19,6 +20,7 @@ func osCustomizations(
t *imageType,
osPackageSet rpmmd.PackageSet,
options distro.ImageOptions,
containers []container.Spec,
c *blueprint.Customizations,
) manifest.OSCustomizations {
@ -43,6 +45,8 @@ func osCustomizations(
osc.ExcludeBasePackages = osPackageSet.Exclude
osc.ExtraBaseRepos = osPackageSet.Repositories
osc.Containers = containers
osc.GPGKeyFiles = imageConfig.GPGKeyFiles
if imageConfig.ExcludeDocs != nil {
osc.ExcludeDocs = *imageConfig.ExcludeDocs
@ -159,11 +163,12 @@ func liveImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewLiveImage()
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
img.Workload = workload
img.Compression = t.compression
@ -184,12 +189,13 @@ func edgeCommitImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewOSTreeArchive(options.OSTree.ImageRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.Environment = t.environment
img.Workload = workload
@ -213,12 +219,13 @@ func edgeContainerImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
img := image.NewOSTreeContainer(options.OSTree.ImageRef)
img.Platform = t.platform
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, customizations)
img.OSCustomizations = osCustomizations(t, packageSets[osPkgsKey], options, containers, customizations)
img.ContainerLanguage = img.OSCustomizations.Language
img.Environment = t.environment
img.Workload = workload
@ -245,6 +252,7 @@ func edgeInstallerImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
d := t.arch.distro
@ -279,6 +287,7 @@ func edgeRawImage(workload workload.Workload,
customizations *blueprint.Customizations,
options distro.ImageOptions,
packageSets map[string]rpmmd.PackageSet,
containers []container.Spec,
rng *rand.Rand) (image.ImageKind, error) {
commit := ostree.CommitSpec{

View file

@ -42,7 +42,7 @@ const (
blueprintPkgsKey = "blueprint"
)
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, rng *rand.Rand) (image.ImageKind, error)
type imageFunc func(workload workload.Workload, t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, packageSets map[string]rpmmd.PackageSet, containers []container.Spec, rng *rand.Rand) (image.ImageKind, error)
type pipelinesFunc func(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, containers []container.Spec, rng *rand.Rand) ([]osbuild.Pipeline, error)
@ -320,7 +320,7 @@ func (t *imageType) initializeManifest(bp *blueprint.Blueprint,
/* #nosec G404 */
rng := rand.New(source)
img, err := t.image(w, t, bp.Customizations, options, packageSets, rng)
img, err := t.image(w, t, bp.Customizations, options, packageSets, containers, rng)
if err != nil {
return nil, err
}
@ -460,8 +460,19 @@ func (t *imageType) PackageSetsNew(bp blueprint.Blueprint, options distro.ImageO
logrus.Warn("FIXME: Requesting package sets for iot-installer without a resolved ostree ref. Faking one.")
}
// create a temporary container spec array with the info from the blueprint
// to initialize the manifest
containers := make([]container.Spec, len(bp.Containers))
for idx := range bp.Containers {
containers[idx] = container.Spec{
Source: bp.Containers[idx].Source,
TLSVerify: bp.Containers[idx].TLSVerify,
LocalName: bp.Containers[idx].Name,
}
}
// create a manifest object and instantiate it with the computed packageSetChains
manifest, err := t.initializeManifest(&bp, options, globalRepos, packageSets, nil, 0)
manifest, err := t.initializeManifest(&bp, options, globalRepos, packageSets, containers, 0)
if err != nil {
// TODO: handle manifest initialization errors more gracefully, we
// refuse to initialize manifests with invalid config.