From 1a891eb2f38875b97787a6061ee147000a32058b Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Nava Date: Fri, 27 Feb 2026 17:57:17 +0100 Subject: [PATCH] MCO-2116: Generate OSImageStream manifest When the OSStreams feature gate is enabled and generate the OSImageStream CR in the openshift manifests so the cluster can boot with the desired stream. If not stream was selected the default one is picked. Signed-off-by: Pablo Rodriguez Nava --- hack/build-coreos-manifest.go | 1 + pkg/asset/manifests/openshift.go | 6 +- pkg/asset/manifests/osimagestream.go | 92 ++++++++++++++++++++++++++++ pkg/rhcos/stream.go | 6 ++ pkg/rhcos/stream_scos.go | 5 ++ 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 pkg/asset/manifests/osimagestream.go diff --git a/hack/build-coreos-manifest.go b/hack/build-coreos-manifest.go index f81952d92cb..82112e1879d 100644 --- a/hack/build-coreos-manifest.go +++ b/hack/build-coreos-manifest.go @@ -119,6 +119,7 @@ func mergeMarketplaceStream(streamJSON []byte) ([]byte, error) { arch.RHELCoreOSExtensions = &rhcos.Extensions{} } arch.RHELCoreOSExtensions.Marketplace = mkt + stream.Architectures[name] = arch } } diff --git a/pkg/asset/manifests/openshift.go b/pkg/asset/manifests/openshift.go index 0f5771998c6..227c5fca101 100644 --- a/pkg/asset/manifests/openshift.go +++ b/pkg/asset/manifests/openshift.go @@ -76,6 +76,7 @@ func (o *Openshift) Dependencies() []asset.Asset { &openshift.BaremetalConfig{}, new(rhcos.Image), &openshift.AzureCloudProviderSecret{}, + &OSImageStream{}, } } @@ -260,13 +261,15 @@ func (o *Openshift) Generate(ctx context.Context, dependencies asset.Parents) er roleCloudCredsSecretReader := &openshift.RoleCloudCredsSecretReader{} baremetalConfig := &openshift.BaremetalConfig{} rhcosImage := new(rhcos.Image) + osImageStream := &OSImageStream{} dependencies.Get( cloudCredsSecret, kubeadminPasswordSecret, roleCloudCredsSecretReader, baremetalConfig, - rhcosImage) + rhcosImage, + osImageStream) assetData := map[string][]byte{ "99_kubeadmin-password-secret.yaml": applyTemplateData(kubeadminPasswordSecret.Files()[0].Data, templateData), @@ -299,6 +302,7 @@ func (o *Openshift) Generate(ctx context.Context, dependencies asset.Parents) er o.FileList = append(o.FileList, openshiftInstall.Files()...) o.FileList = append(o.FileList, featureGate.Files()...) + o.FileList = append(o.FileList, osImageStream.Files()...) asset.SortFiles(o.FileList) diff --git a/pkg/asset/manifests/osimagestream.go b/pkg/asset/manifests/osimagestream.go new file mode 100644 index 00000000000..4c77ac80bef --- /dev/null +++ b/pkg/asset/manifests/osimagestream.go @@ -0,0 +1,92 @@ +package manifests + +import ( + "context" + "github.com/openshift/installer/pkg/rhcos" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "path" + + "github.com/openshift/api/features" + "github.com/pkg/errors" + "sigs.k8s.io/yaml" + + mcfgv1alpha "github.com/openshift/api/machineconfiguration/v1alpha1" + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" +) + +var osImageStreamFileName = path.Join(openshiftManifestDir, "99_osimagestream.yaml") + +// OSImageStream generates the OSImageStream manifest. +type OSImageStream struct { + FileList []*asset.File +} + +var _ asset.WritableAsset = (*OSImageStream)(nil) + +// Name returns a human-friendly name for the asset. +func (*OSImageStream) Name() string { + return "OSImageStream" +} + +// Dependencies returns all of the dependencies directly needed to generate +// the asset. +func (*OSImageStream) Dependencies() []asset.Asset { + return []asset.Asset{ + &installconfig.InstallConfig{}, + } +} + +// Generate generates the OSImageStream CRD. +func (f *OSImageStream) Generate(_ context.Context, dependencies asset.Parents) error { + installConfig := &installconfig.InstallConfig{} + dependencies.Get(installConfig) + + // If one of the following are true the OSImageStream CR is not generated + // 1. The feature is not enabled + // 2. The target is CentOS Stream CoreOS + if !installConfig.Config.EnabledFeatureGates().Enabled(features.FeatureGateOSStreams) || installConfig.Config.IsSCOS() { + // FG disabled or not OCP + return nil + } + + // If no stream was set just report the default one for the current version + stream := installConfig.Config.OSImageStream + if stream == "" { + stream = rhcos.DefaultOSImageStream + } + + osImageStream := &mcfgv1alpha.OSImageStream{ + TypeMeta: metav1.TypeMeta{ + APIVersion: mcfgv1alpha.SchemeGroupVersion.String(), + Kind: "OSImageStream", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + }, + Spec: &mcfgv1alpha.OSImageStreamSpec{ + DefaultStream: string(stream), + }, + } + + osImageStreamData, err := yaml.Marshal(osImageStream) + if err != nil { + return errors.Wrapf(err, "failed to create %s manifests from InstallConfig", f.Name()) + } + + f.FileList = append(f.FileList, &asset.File{ + Filename: osImageStreamFileName, + Data: osImageStreamData, + }) + return nil +} + +// Files returns the files generated by the asset. +func (f *OSImageStream) Files() []*asset.File { + return f.FileList +} + +// Load loads the already-rendered files back from disk. +func (f *OSImageStream) Load(_ asset.FileFetcher) (bool, error) { + return false, nil +} diff --git a/pkg/rhcos/stream.go b/pkg/rhcos/stream.go index 8326382bfb5..f9cf2b0e291 100644 --- a/pkg/rhcos/stream.go +++ b/pkg/rhcos/stream.go @@ -2,6 +2,12 @@ package rhcos +import "github.com/openshift/installer/pkg/types" + +// DefaultOSImageStream is the OS image stream used when the install-config +// does not specify one. +const DefaultOSImageStream = types.OSImageStreamRHCOS9 + func getStreamFileName() string { return "coreos/rhcos.json" } diff --git a/pkg/rhcos/stream_scos.go b/pkg/rhcos/stream_scos.go index d5db6b94a64..02de35c6964 100644 --- a/pkg/rhcos/stream_scos.go +++ b/pkg/rhcos/stream_scos.go @@ -2,6 +2,11 @@ package rhcos +import "github.com/openshift/installer/pkg/types" + +// DefaultOSImageStream Not used in SCOS +const DefaultOSImageStream types.OSImageStream = "" + func getStreamFileName() string { return "coreos/scos.json" }