From d2448dd29fb58cedffdf1491040d9aa2dfb2e4ea Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Nava Date: Mon, 27 Oct 2025 18:26:08 +0100 Subject: [PATCH] Read the new osimgurl CM format --- cmd/machine-config-operator/bootstrap.go | 14 +- .../0000_80_machine-config_05_osimageurl.yaml | 15 +- .../build/buildrequest/buildrequest.go | 7 +- pkg/controller/common/images.go | 145 +++++--- pkg/controller/common/images_test.go | 323 ++++++++++++++++++ pkg/operator/bootstrap.go | 15 +- pkg/operator/sync.go | 38 +-- 7 files changed, 476 insertions(+), 81 deletions(-) create mode 100644 pkg/controller/common/images_test.go diff --git a/cmd/machine-config-operator/bootstrap.go b/cmd/machine-config-operator/bootstrap.go index 2c75f685aa..3246c751ce 100644 --- a/cmd/machine-config-operator/bootstrap.go +++ b/cmd/machine-config-operator/bootstrap.go @@ -154,14 +154,12 @@ func runBootstrapCmd(_ *cobra.Command, _ []string) { imgs := ctrlcommon.Images{ RenderConfigImages: ctrlcommon.RenderConfigImages{ - MachineConfigOperator: bootstrapOpts.mcoImage, - KeepalivedBootstrap: bootstrapOpts.keepalivedImage, - CorednsBootstrap: bootstrapOpts.corednsImage, - BaremetalRuntimeCfgBootstrap: bootstrapOpts.baremetalRuntimeCfgImage, - OauthProxy: bootstrapOpts.oauthProxyImage, - KubeRbacProxy: bootstrapOpts.kubeRbacProxyImage, - BaseOSContainerImage: bootstrapOpts.baseOSContainerImage, - BaseOSExtensionsContainerImage: bootstrapOpts.baseOSExtensionsContainerImage, + MachineConfigOperator: bootstrapOpts.mcoImage, + KeepalivedBootstrap: bootstrapOpts.keepalivedImage, + CorednsBootstrap: bootstrapOpts.corednsImage, + BaremetalRuntimeCfgBootstrap: bootstrapOpts.baremetalRuntimeCfgImage, + OauthProxy: bootstrapOpts.oauthProxyImage, + KubeRbacProxy: bootstrapOpts.kubeRbacProxyImage, }, ControllerConfigImages: ctrlcommon.ControllerConfigImages{ InfraImage: bootstrapOpts.infraImage, diff --git a/install/0000_80_machine-config_05_osimageurl.yaml b/install/0000_80_machine-config_05_osimageurl.yaml index 255bf9658c..7ef975f366 100644 --- a/install/0000_80_machine-config_05_osimageurl.yaml +++ b/install/0000_80_machine-config_05_osimageurl.yaml @@ -9,11 +9,16 @@ metadata: include.release.openshift.io/single-node-developer: "true" data: releaseVersion: 0.0.1-snapshot - # This (will eventually) replace the below when https://github.com/openshift/enhancements/pull/1032 - # progresses towards the default. baseOSContainerImage: "placeholder.url.oc.will.replace.this.org/placeholdernamespace:rhel-coreos" baseOSExtensionsContainerImage: "placeholder.url.oc.will.replace.this.org/placeholdernamespace:rhel-coreos-extensions" - # The OS payload used for 4.10 and below; more information in - # https://github.com/openshift/machine-config-operator/blob/master/docs/OSUpgrades.md - # (The original issue was https://github.com/openshift/machine-config-operator/issues/183 ) osImageURL: "" + streams.json: > + { + "default": "rhel-coreos", + "streams": { + "rhel-coreos": { + "baseOSContainerImage": "placeholder.url.oc.will.replace.this.org/placeholdernamespace:rhel-coreos", + "baseOSExtensionsContainerImage": "placeholder.url.oc.will.replace.this.org/placeholdernamespace:rhel-coreos-extensions" + } + } + } diff --git a/pkg/controller/build/buildrequest/buildrequest.go b/pkg/controller/build/buildrequest/buildrequest.go index 5bd5b300e3..51976b4f15 100644 --- a/pkg/controller/build/buildrequest/buildrequest.go +++ b/pkg/controller/build/buildrequest/buildrequest.go @@ -322,6 +322,7 @@ func (br buildRequestImpl) renderContainerfile() (string, error) { // lowercase fields. Additionally, since there are a few fields where we // default to a value from a different location, it makes more sense for us // to implement that logic in Go as opposed to the Go template language. + osImageStreamImages := br.opts.OSImageURLConfig.StreamsConfig.GetOSImageURLsForDefaultStream() items := struct { MachineOSBuild *mcfgv1.MachineOSBuild MachineOSConfig *mcfgv1.MachineOSConfig @@ -335,8 +336,8 @@ func (br buildRequestImpl) renderContainerfile() (string, error) { MachineOSBuild: br.opts.MachineOSBuild, MachineOSConfig: br.opts.MachineOSConfig, UserContainerfile: br.userContainerfile, - BaseOSImage: br.opts.OSImageURLConfig.BaseOSContainerImage, - ExtensionsImage: br.opts.OSImageURLConfig.BaseOSExtensionsContainerImage, + BaseOSImage: osImageStreamImages.BaseOSContainerImage, + ExtensionsImage: osImageStreamImages.BaseOSExtensionsContainerImage, ExtensionsPackages: extPkgs, KernelType: kernelType, KernelPackages: kernelPackages, @@ -671,7 +672,7 @@ func (br buildRequestImpl) toBuildahPod() *corev1.Pod { // us to avoid parsing log files. Name: "create-digest-configmap", Command: append(command, digestCMScript), - Image: br.opts.OSImageURLConfig.BaseOSContainerImage, + Image: br.opts.OSImageURLConfig.StreamsConfig.GetOSImageURLsForDefaultStream().BaseOSContainerImage, Env: env, ImagePullPolicy: corev1.PullAlways, SecurityContext: securityContext, diff --git a/pkg/controller/common/images.go b/pkg/controller/common/images.go index abd24c580a..6f0195ed4b 100644 --- a/pkg/controller/common/images.go +++ b/pkg/controller/common/images.go @@ -2,9 +2,11 @@ package common import ( "context" - "fmt" - "encoding/json" + "fmt" + "maps" + "slices" + "strings" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -12,6 +14,12 @@ import ( clientset "k8s.io/client-go/kubernetes" ) +const ( + imagesConfigMapImagesField = "images.json" + osImageUrlConfigMapStreamsField = "streams.json" + osImageUrlConfigMapStreamsDefaultImagesTag = "rhel-coreos" +) + // Images contain data derived from what github.com/openshift/installer's // bootkube.sh provides. If you want to add a new image, you need // to "ratchet" the change as follows: @@ -28,10 +36,6 @@ type Images struct { // RenderConfigImages are image names used to render templates under ./manifests/ type RenderConfigImages struct { MachineConfigOperator string `json:"machineConfigOperator"` - // The new format image - BaseOSContainerImage string `json:"baseOSContainerImage"` - // The matching extensions container for the new format image - BaseOSExtensionsContainerImage string `json:"baseOSExtensionsContainerImage"` // These have to be named differently from the ones in ControllerConfigImages // or we get errors about ambiguous selectors because both structs are // combined in the Images struct. @@ -51,47 +55,107 @@ type ControllerConfigImages struct { BaremetalRuntimeCfg string `json:"baremetalRuntimeCfgImage"` } -// Parses the JSON blob containing the images information into an Images struct. -func ParseImagesFromBytes(in []byte) (*Images, error) { - img := &Images{} +type OSImageURLStreamConfig struct { + BaseOSContainerImage string `json:"baseOSContainerImage"` + BaseOSExtensionsContainerImage string `json:"baseOSExtensionsContainerImage"` +} +type OSImageURLStreamsConfig struct { + Default string `json:"default"` + Streams map[string]OSImageURLStreamConfig `json:"streams"` +} - if err := json.Unmarshal(in, img); err != nil { - return nil, fmt.Errorf("could not parse images.json bytes: %w", err) +func (o *OSImageURLStreamsConfig) GetOSImageURLsForStream(stream string) OSImageURLStreamConfig { + tagetStream, exists := o.Streams[stream] + if !exists { + return o.GetOSImageURLsForDefaultStream() } + return tagetStream +} - return img, nil +func (o *OSImageURLStreamsConfig) GetOSImageURLsForDefaultStream() OSImageURLStreamConfig { + return o.Streams[o.Default] } -// Reads the contents of the provided ConfigMap into an Images struct. -func ParseImagesFromConfigMap(cm *corev1.ConfigMap) (*Images, error) { - if err := validateMCOConfigMap(cm, MachineConfigOperatorImagesConfigMapName, []string{"images.json"}, nil); err != nil { - return nil, err +func (o *OSImageURLStreamsConfig) OSImageURLStreamExists(stream string) bool { + _, exists := o.Streams[stream] + return exists +} + +func NewOSImageURLStreamsConfigFromBytes(buf []byte) (*OSImageURLStreamsConfig, error) { + streamsConfig := &OSImageURLStreamsConfig{} + if err := json.Unmarshal(buf, &streamsConfig); err != nil { + return nil, fmt.Errorf("could not parse streams config bytes: %w", err) + } + if streamsConfig.Default == "" { + return nil, fmt.Errorf("invalid osimagerul ConfigMap. The default stream cannot be empty") } - return ParseImagesFromBytes([]byte(cm.Data["images.json"])) + if _, ok := streamsConfig.Streams[streamsConfig.Default]; !ok { + return nil, fmt.Errorf( + "invalid osimagerul ConfigMap. The default stream %s is not part of the declared streams %s", + streamsConfig.Default, + strings.Join(slices.Collect(maps.Keys(streamsConfig.Streams)), ", "), + ) + } + return streamsConfig, nil +} + +func NewOSImageURLStreamsConfigDefault(osContainerImage, osContainerExtensionImage string) *OSImageURLStreamsConfig { + return &OSImageURLStreamsConfig{ + Default: osImageUrlConfigMapStreamsDefaultImagesTag, + Streams: map[string]OSImageURLStreamConfig{ + osImageUrlConfigMapStreamsDefaultImagesTag: { + BaseOSContainerImage: osContainerImage, + BaseOSExtensionsContainerImage: osContainerExtensionImage, + }, + }, + } } -// Holds the contents of the machine-config-osimageurl ConfigMap. type OSImageURLConfig struct { - BaseOSContainerImage string - BaseOSExtensionsContainerImage string - OSImageURL string - ReleaseVersion string + ReleaseVersion string + StreamsConfig OSImageURLStreamsConfig +} + +func ParseImagesFromBytes(in []byte) (*Images, error) { + img := &Images{} + if err := json.Unmarshal(in, img); err != nil { + return nil, fmt.Errorf("could not parse images.json bytes: %w", err) + } + return img, nil } // Reads the contents of the provided ConfigMap into an OSImageURLConfig struct. func ParseOSImageURLConfigMap(cm *corev1.ConfigMap) (*OSImageURLConfig, error) { - reqKeys := []string{"baseOSContainerImage", "baseOSExtensionsContainerImage", "osImageURL", "releaseVersion"} - - if err := validateMCOConfigMap(cm, MachineConfigOSImageURLConfigMapName, reqKeys, nil); err != nil { + if err := validateMCOConfigMap( + cm, + MachineConfigOSImageURLConfigMapName, + []string{"baseOSContainerImage", "baseOSExtensionsContainerImage", "releaseVersion"}, + ); err != nil { return nil, err } + // For now handle the streams like they are optional and populate them with a sane default + // in case they are not present + streamsData, ok := cm.Data[osImageUrlConfigMapStreamsField] + var streamsConfig *OSImageURLStreamsConfig + if ok { + var err error + streamsConfig, err = NewOSImageURLStreamsConfigFromBytes([]byte(streamsData)) + if err != nil { + return nil, err + } + } else { + // The pre-streams fields that holds the cluster-wide OS images + // Always pointing to the rhel-coreos (osImageUrlConfigMapStreamsDefaultImagesTag) tag + legacyBaseOSContainerImage := cm.Data["baseOSContainerImage"] + legacyBaseOSExtensionsContainerImage := cm.Data["baseOSExtensionsContainerImage"] + streamsConfig = NewOSImageURLStreamsConfigDefault(legacyBaseOSContainerImage, legacyBaseOSExtensionsContainerImage) + } + return &OSImageURLConfig{ - BaseOSContainerImage: cm.Data["baseOSContainerImage"], - BaseOSExtensionsContainerImage: cm.Data["baseOSExtensionsContainerImage"], - OSImageURL: cm.Data["osImageURL"], - ReleaseVersion: cm.Data["releaseVersion"], + ReleaseVersion: cm.Data["releaseVersion"], + StreamsConfig: *streamsConfig, }, nil } @@ -99,8 +163,7 @@ func ParseOSImageURLConfigMap(cm *corev1.ConfigMap) (*OSImageURLConfig, error) { // 1. The name matches what was provided. // 2. The namespace is set to the MCO's namespace. // 3. The data field has all of the expected keys. -// 4. The BinarayData field has all of the expected keys. -func validateMCOConfigMap(cm *corev1.ConfigMap, name string, reqDataKeys, reqBinaryKeys []string) error { +func validateMCOConfigMap(cm *corev1.ConfigMap, name string, reqDataKeys []string) error { if cm.Name != name { return fmt.Errorf("invalid ConfigMap, expected %s", name) } @@ -116,15 +179,17 @@ func validateMCOConfigMap(cm *corev1.ConfigMap, name string, reqDataKeys, reqBin } } } + return nil +} - if reqBinaryKeys != nil { - for _, reqKey := range reqBinaryKeys { - if _, ok := cm.BinaryData[reqKey]; !ok { - return fmt.Errorf("expecting missing binary data key %s to be present in ConfigMap %s", reqKey, cm.Name) - } - } +func parseJsonFromConfigMap[T any](cm *corev1.ConfigMap, name string, value *T) error { + if err := validateMCOConfigMap(cm, MachineConfigOperatorImagesConfigMapName, []string{name}); err != nil { + return err } + if err := json.Unmarshal([]byte(cm.Data[name]), value); err != nil { + return fmt.Errorf("could not parse %s bytes: %w", name, err) + } return nil } @@ -145,5 +210,9 @@ func GetImagesConfig(ctx context.Context, kubeclient clientset.Interface) (*Imag return nil, fmt.Errorf("could not get configmap %s: %w", MachineConfigOperatorImagesConfigMapName, err) } - return ParseImagesFromConfigMap(cm) + images := &Images{} + if err := parseJsonFromConfigMap(cm, imagesConfigMapImagesField, images); err != nil { + return nil, fmt.Errorf("could not parse configmap %s: %w", cm.Name, err) + } + return images, nil } diff --git a/pkg/controller/common/images_test.go b/pkg/controller/common/images_test.go new file mode 100644 index 0000000000..4e7e0b1c4b --- /dev/null +++ b/pkg/controller/common/images_test.go @@ -0,0 +1,323 @@ +package common + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/fake" +) + +func TestParseOSImageURLConfigMap(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + cm *corev1.ConfigMap + expectError bool + expected *OSImageURLConfig + }{ + { + name: "valid ConfigMap with streams.json", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + "streams.json": `{ + "default": "rhel-coreos", + "streams": { + "rhel-coreos": { + "baseOSContainerImage": "quay.io/openshift/rhcos:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/rhcos-ext:latest" + }, + "rhel10-coreos": { + "baseOSContainerImage": "quay.io/openshift/rhel10:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/rhel10-ext:latest" + } + } + }`, + }, + }, + expectError: false, + expected: &OSImageURLConfig{ + ReleaseVersion: "4.21.0", + StreamsConfig: OSImageURLStreamsConfig{ + Default: "rhel-coreos", + Streams: map[string]OSImageURLStreamConfig{ + "rhel-coreos": { + BaseOSContainerImage: "quay.io/openshift/rhcos:latest", + BaseOSExtensionsContainerImage: "quay.io/openshift/rhcos-ext:latest", + }, + "rhel10-coreos": { + BaseOSContainerImage: "quay.io/openshift/rhel10:latest", + BaseOSExtensionsContainerImage: "quay.io/openshift/rhel10-ext:latest", + }, + }, + }, + }, + }, + { + name: "valid ConfigMap without streams.json (uses default)", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + }, + }, + expectError: false, + expected: &OSImageURLConfig{ + ReleaseVersion: "4.21.0", + StreamsConfig: OSImageURLStreamsConfig{ + Default: "rhel-coreos", + Streams: map[string]OSImageURLStreamConfig{ + "rhel-coreos": { + BaseOSContainerImage: "quay.io/openshift/base:latest", + BaseOSExtensionsContainerImage: "quay.io/openshift/extensions:latest", + }, + }, + }, + }, + }, + { + name: "invalid streams.json format", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + "streams.json": `{"invalid json`, + }, + }, + expectError: true, + }, + { + name: "missing required field baseOSContainerImage", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + }, + }, + expectError: true, + }, + { + name: "missing required field baseOSExtensionsContainerImage", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "releaseVersion": "4.21.0", + }, + }, + expectError: true, + }, + { + name: "missing required field releaseVersion", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + }, + }, + expectError: true, + }, + { + name: "wrong ConfigMap name", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "wrong-configmap-name", + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + }, + }, + expectError: true, + }, + { + name: "wrong namespace", + cm: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: "wrong-namespace", + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + }, + }, + expectError: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + result, err := ParseOSImageURLConfigMap(testCase.cm) + if testCase.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, testCase.expected, result) + } + }) + } +} + +func TestGetOSImageURLConfig(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + configMaps []*corev1.ConfigMap + expectError bool + expected *OSImageURLConfig + }{ + { + name: "successfully retrieve and parse ConfigMap", + configMaps: []*corev1.ConfigMap{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.21.0", + }, + }, + }, + expectError: false, + expected: &OSImageURLConfig{ + ReleaseVersion: "4.21.0", + StreamsConfig: OSImageURLStreamsConfig{ + Default: "rhel-coreos", + Streams: map[string]OSImageURLStreamConfig{ + "rhel-coreos": { + BaseOSContainerImage: "quay.io/openshift/base:latest", + BaseOSExtensionsContainerImage: "quay.io/openshift/extensions:latest", + }, + }, + }, + }, + }, + { + name: "successfully retrieve and parse ConfigMap with streams.json", + configMaps: []*corev1.ConfigMap{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: MCONamespace, + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.15.0", + "streams.json": `{ + "default": "rhel10-coreos", + "streams": { + "rhel10-coreos": { + "baseOSContainerImage": "quay.io/openshift/rhel10:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/rhel10-ext:latest" + } + } + }`, + }, + }, + }, + expectError: false, + expected: &OSImageURLConfig{ + ReleaseVersion: "4.15.0", + StreamsConfig: OSImageURLStreamsConfig{ + Default: "rhel10-coreos", + Streams: map[string]OSImageURLStreamConfig{ + "rhel10-coreos": { + BaseOSContainerImage: "quay.io/openshift/rhel10:latest", + BaseOSExtensionsContainerImage: "quay.io/openshift/rhel10-ext:latest", + }, + }, + }, + }, + }, + { + name: "ConfigMap not found", + configMaps: []*corev1.ConfigMap{}, + expectError: true, + }, + { + name: "ConfigMap in wrong namespace", + configMaps: []*corev1.ConfigMap{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: MachineConfigOSImageURLConfigMapName, + Namespace: "default", + }, + Data: map[string]string{ + "baseOSContainerImage": "quay.io/openshift/base:latest", + "baseOSExtensionsContainerImage": "quay.io/openshift/extensions:latest", + "releaseVersion": "4.15.0", + }, + }, + }, + expectError: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + // Convert ConfigMaps to runtime.Object slice for fake client + objects := make([]runtime.Object, len(testCase.configMaps)) + for i, cm := range testCase.configMaps { + objects[i] = cm + } + + // Create fake client with ConfigMaps + client := fake.NewClientset(objects...) + + result, err := GetOSImageURLConfig(context.Background(), client) + + if testCase.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, testCase.expected, result) + } + }) + } +} diff --git a/pkg/operator/bootstrap.go b/pkg/operator/bootstrap.go index 5ec86ce5b7..8d8da3f431 100644 --- a/pkg/operator/bootstrap.go +++ b/pkg/operator/bootstrap.go @@ -144,14 +144,13 @@ func RenderBootstrap( spec.ReleaseImage = releaseImage spec.Images = map[string]string{ templatectrl.MachineConfigOperatorKey: imgs.MachineConfigOperator, - - templatectrl.APIServerWatcherKey: imgs.MachineConfigOperator, - templatectrl.InfraImageKey: imgs.InfraImage, - templatectrl.KeepalivedKey: imgs.Keepalived, - templatectrl.CorednsKey: imgs.Coredns, - templatectrl.HaproxyKey: imgs.Haproxy, - templatectrl.BaremetalRuntimeCfgKey: imgs.BaremetalRuntimeCfg, - templatectrl.KubeRbacProxyKey: imgs.KubeRbacProxy, + templatectrl.APIServerWatcherKey: imgs.MachineConfigOperator, + templatectrl.InfraImageKey: imgs.InfraImage, + templatectrl.KeepalivedKey: imgs.Keepalived, + templatectrl.CorednsKey: imgs.Coredns, + templatectrl.HaproxyKey: imgs.Haproxy, + templatectrl.BaremetalRuntimeCfgKey: imgs.BaremetalRuntimeCfg, + templatectrl.KubeRbacProxyKey: imgs.KubeRbacProxy, } config := getRenderConfig("", string(filesData[kubeAPIServerServingCA]), spec, &imgs.RenderConfigImages, infra, nil, nil, "2") diff --git a/pkg/operator/sync.go b/pkg/operator/sync.go index 1cf5309f55..f1c64ce461 100644 --- a/pkg/operator/sync.go +++ b/pkg/operator/sync.go @@ -555,15 +555,6 @@ func (optr *Operator) syncRenderConfig(_ *renderConfig, _ *configv1.ClusterOpera internalRegistryPullSecret = nil } - // sync up os image url - // TODO: this should probably be part of the imgs - oscontainer, osextensionscontainer, err := optr.getOsImageURLs(optr.namespace) - if err != nil { - return err - } - imgs.BaseOSContainerImage = oscontainer - imgs.BaseOSExtensionsContainerImage = osextensionscontainer - // sync up the ControllerConfigSpec infra, network, proxy, dns, apiServer, err := optr.getGlobalConfig() if err != nil { @@ -613,8 +604,17 @@ func (optr *Operator) syncRenderConfig(_ *renderConfig, _ *configv1.ClusterOpera spec.ImageRegistryBundleUserData = imgRegistryUsrData spec.PullSecret = &corev1.ObjectReference{Namespace: "openshift-config", Name: "pull-secret"} spec.InternalRegistryPullSecret = internalRegistryPullSecret - spec.BaseOSContainerImage = imgs.BaseOSContainerImage - spec.BaseOSExtensionsContainerImage = imgs.BaseOSExtensionsContainerImage + + // sync up os image url + // TODO: this should probably be part of the imgs + osImageUrlCfg, err := optr.getOsImageURLs(optr.namespace) + if err != nil { + return err + } + // Fill the ControllerConfig fields (not used, but preserved) with sane defaults + osImageStreamsDefaultCfg := osImageUrlCfg.StreamsConfig.GetOSImageURLsForDefaultStream() + spec.BaseOSContainerImage = osImageStreamsDefaultCfg.BaseOSContainerImage + spec.BaseOSExtensionsContainerImage = osImageStreamsDefaultCfg.BaseOSExtensionsContainerImage spec.Images = map[string]string{ templatectrl.MachineConfigOperatorKey: imgs.MachineConfigOperator, templatectrl.APIServerWatcherKey: imgs.MachineConfigOperator, @@ -1718,14 +1718,14 @@ func (optr *Operator) syncRequiredMachineConfigPools(config *renderConfig, co *c _, hasRequiredPoolLabel := pool.Labels[requiredForUpgradeMachineConfigPoolLabelKey] if hasRequiredPoolLabel { - opURL, _, err := optr.getOsImageURLs(optr.namespace) + osImageUrlCfg, err := optr.getOsImageURLs(optr.namespace) if err != nil { klog.Errorf("Error getting configmap osImageURL: %q", err) return false, nil } releaseVersion, _ := optr.vStore.Get("operator") - - if err := isMachineConfigPoolConfigurationValid(optr.fgHandler, pool, version.Hash, releaseVersion, opURL, optr.mcLister.Get); err != nil { + osStreaDefaultConfig := osImageUrlCfg.StreamsConfig.GetOSImageURLsForDefaultStream() + if err := isMachineConfigPoolConfigurationValid(optr.fgHandler, pool, version.Hash, releaseVersion, osStreaDefaultConfig.BaseOSContainerImage, optr.mcLister.Get); err != nil { lastErr = fmt.Errorf("MachineConfigPool %s has not progressed to latest configuration: %w, retrying", pool.Name, err) newCO := co.DeepCopy() syncerr := optr.syncUpgradeableStatus(newCO) @@ -1884,23 +1884,23 @@ func (optr *Operator) waitForControllerConfigToBeCompleted(resource *mcfgv1.Cont } // getOsImageURLs returns (new type, new extensions, old type) for operating system update images. -func (optr *Operator) getOsImageURLs(namespace string) (string, string, error) { +func (optr *Operator) getOsImageURLs(namespace string) (*ctrlcommon.OSImageURLConfig, error) { cm, err := optr.mcoCmLister.ConfigMaps(namespace).Get(ctrlcommon.MachineConfigOSImageURLConfigMapName) if err != nil { - return "", "", err + return nil, err } cfg, err := ctrlcommon.ParseOSImageURLConfigMap(cm) if err != nil { - return "", "", err + return nil, err } optrVersion, _ := optr.vStore.Get("operator") if cfg.ReleaseVersion != optrVersion { - return "", "", fmt.Errorf("refusing to read osImageURL version %q, operator version %q", cfg.ReleaseVersion, optrVersion) + return nil, fmt.Errorf("refusing to read osImageURL version %q, operator version %q", cfg.ReleaseVersion, optrVersion) } - return cfg.BaseOSContainerImage, cfg.BaseOSExtensionsContainerImage, nil + return cfg, nil } func (optr *Operator) getCAsFromConfigMap(namespace, name, key string) ([]byte, error) {