Skip to content

Commit 5175173

Browse files
committed
MCO-1961: Introduce the OSImageStream controller
1 parent 74271d5 commit 5175173

File tree

12 files changed

+403
-92
lines changed

12 files changed

+403
-92
lines changed

cmd/machine-config-controller/start.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
kubeletconfig "github.com/openshift/machine-config-operator/pkg/controller/kubelet-config"
1717
machinesetbootimage "github.com/openshift/machine-config-operator/pkg/controller/machine-set-boot-image"
1818
"github.com/openshift/machine-config-operator/pkg/controller/node"
19+
"github.com/openshift/machine-config-operator/pkg/controller/osimagestream"
1920
"github.com/openshift/machine-config-operator/pkg/controller/pinnedimageset"
2021
"github.com/openshift/machine-config-operator/pkg/controller/render"
2122
"github.com/openshift/machine-config-operator/pkg/controller/template"
@@ -149,6 +150,29 @@ func runStartCmd(_ *cobra.Command, _ []string) {
149150
ctrlctx.OperatorInformerFactory.Start(ctrlctx.Stop)
150151
}
151152

153+
if ctrlctx.FeatureGatesHandler.Enabled(features.FeatureGateOSStreams) {
154+
osImageStreamController := osimagestream.NewController(
155+
ctrlctx.ClientBuilder.KubeClientOrDie("osimagestream-controller"),
156+
ctrlctx.ClientBuilder.MachineConfigClientOrDie("osimagestream-controller"),
157+
ctrlctx.InformerFactory.Machineconfiguration().V1().ControllerConfigs(),
158+
ctrlctx.KubeNamespacedInformerFactory.Core().V1().ConfigMaps(),
159+
ctrlctx.InformerFactory.Machineconfiguration().V1alpha1().OSImageStreams(),
160+
ctrlctx.ConfigInformerFactory.Config().V1().ClusterVersions(),
161+
nil,
162+
)
163+
164+
go osImageStreamController.Run(ctrlctx.Stop)
165+
// start the informers again to enable feature gated types.
166+
// see comments in SharedInformerFactory interface.
167+
ctrlctx.KubeNamespacedInformerFactory.Start(ctrlctx.Stop)
168+
ctrlctx.InformerFactory.Start(ctrlctx.Stop)
169+
ctrlctx.ConfigInformerFactory.Start(ctrlctx.Stop)
170+
171+
if err = osImageStreamController.WaitBoot(); err != nil {
172+
klog.Fatal(fmt.Errorf("failed to initialize the OSImageStream controller %w", err))
173+
}
174+
}
175+
152176
for _, c := range controllers {
153177
go c.Run(2, ctrlctx.Stop)
154178
}
@@ -187,17 +211,21 @@ func createControllers(ctx *ctrlcommon.ControllerContext) []ctrlcommon.Controlle
187211
rootOpts.templates,
188212
ctx.InformerFactory.Machineconfiguration().V1().ControllerConfigs(),
189213
ctx.InformerFactory.Machineconfiguration().V1().MachineConfigs(),
214+
ctx.InformerFactory.Machineconfiguration().V1().MachineConfigPools(),
215+
ctx.InformerFactory.Machineconfiguration().V1alpha1().OSImageStreams(),
190216
ctx.OpenShiftConfigKubeNamespacedInformerFactory.Core().V1().Secrets(),
191217
ctx.ConfigInformerFactory.Config().V1().APIServers(),
192218
ctx.ClientBuilder.KubeClientOrDie("template-controller"),
193219
ctx.ClientBuilder.MachineConfigClientOrDie("template-controller"),
220+
ctx.FeatureGatesHandler,
194221
),
195222
// Add all "sub-renderers here"
196223
kubeletconfig.New(
197224
rootOpts.templates,
198225
ctx.InformerFactory.Machineconfiguration().V1().MachineConfigPools(),
199226
ctx.InformerFactory.Machineconfiguration().V1().ControllerConfigs(),
200227
ctx.InformerFactory.Machineconfiguration().V1().KubeletConfigs(),
228+
ctx.InformerFactory.Machineconfiguration().V1alpha1().OSImageStreams(),
201229
ctx.ConfigInformerFactory.Config().V1().FeatureGates(),
202230
ctx.ConfigInformerFactory.Config().V1().Nodes(),
203231
ctx.ConfigInformerFactory.Config().V1().APIServers(),
@@ -211,6 +239,7 @@ func createControllers(ctx *ctrlcommon.ControllerContext) []ctrlcommon.Controlle
211239
ctx.InformerFactory.Machineconfiguration().V1().MachineConfigPools(),
212240
ctx.InformerFactory.Machineconfiguration().V1().ControllerConfigs(),
213241
ctx.InformerFactory.Machineconfiguration().V1().ContainerRuntimeConfigs(),
242+
ctx.InformerFactory.Machineconfiguration().V1alpha1().OSImageStreams(),
214243
ctx.ConfigInformerFactory.Config().V1().Images(),
215244
ctx.ConfigInformerFactory.Config().V1().ImageDigestMirrorSets(),
216245
ctx.ConfigInformerFactory.Config().V1().ImageTagMirrorSets(),
@@ -231,6 +260,7 @@ func createControllers(ctx *ctrlcommon.ControllerContext) []ctrlcommon.Controlle
231260
ctx.InformerFactory.Machineconfiguration().V1().ContainerRuntimeConfigs(),
232261
ctx.InformerFactory.Machineconfiguration().V1().KubeletConfigs(),
233262
ctx.OperatorInformerFactory.Operator().V1().MachineConfigurations(),
263+
ctx.InformerFactory.Machineconfiguration().V1alpha1().OSImageStreams(),
234264
ctx.ClientBuilder.KubeClientOrDie("render-controller"),
235265
ctx.ClientBuilder.MachineConfigClientOrDie("render-controller"),
236266
ctx.FeatureGatesHandler,

pkg/controller/bootstrap/bootstrap.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ package bootstrap
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
67
"fmt"
78
"io"
89
"os"
910
"path/filepath"
11+
"time"
1012

13+
"github.com/openshift/api/features"
1114
imagev1 "github.com/openshift/api/image/v1"
15+
"github.com/openshift/api/machineconfiguration/v1alpha1"
16+
"github.com/openshift/machine-config-operator/pkg/controller/osimagestream"
1217
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1318

1419
corev1 "k8s.io/api/core/v1"
@@ -68,7 +73,7 @@ func (b *Bootstrap) Run(destDir string) error {
6873
return err
6974
}
7075

71-
psraw, err := getPullSecretFromSecret(psfraw)
76+
pullSecret, err := getValidatePullSecretFromBytes(psfraw)
7277
if err != nil {
7378
return err
7479
}
@@ -195,15 +200,46 @@ func (b *Bootstrap) Run(destDir string) error {
195200
return fmt.Errorf("error creating feature gates handler: %w", err)
196201
}
197202

198-
iconfigs, err := template.RunBootstrap(b.templatesDir, cconfig, psraw, apiServer)
203+
var osImageStream *v1alpha1.OSImageStream
204+
if fgHandler.Enabled(features.FeatureGateOSStreams) {
205+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
206+
defer cancel()
207+
208+
// TODO @pablintino we need to change the factory API to avoid passing that cmLister at bootstrap
209+
osImageStream, err = osimagestream.BuildOsImageStreamBootstrap(ctx,
210+
pullSecret,
211+
cconfig,
212+
imageStream,
213+
&osimagestream.OSImageTuple{
214+
OSImage: cconfig.Spec.BaseOSContainerImage,
215+
OSExtensionsImage: cconfig.Spec.BaseOSExtensionsContainerImage,
216+
},
217+
osimagestream.NewDefaultStreamSourceFactory(nil, &osimagestream.DefaultImagesInspectorFactory{}),
218+
)
219+
if err != nil {
220+
return fmt.Errorf("error inspecting available OSImageStreams: %w", err)
221+
}
222+
223+
// For sanity reasons we override the ControllerConfig URLs with the default stream ones
224+
defaultStreamSet, err := osimagestream.GetOSImageStreamSetByName(osImageStream, "")
225+
if err != nil {
226+
// Should never happen
227+
return fmt.Errorf("error getting default OSImageStreamSet: %w", err)
228+
}
229+
cconfig.Spec.BaseOSContainerImage = string(defaultStreamSet.OSImage)
230+
cconfig.Spec.BaseOSExtensionsContainerImage = string(defaultStreamSet.OSExtensionsImage)
231+
}
232+
233+
pullSecretBytes := pullSecret.Data[corev1.DockerConfigJsonKey]
234+
iconfigs, err := template.RunBootstrap(b.templatesDir, cconfig, pools, pullSecretBytes, apiServer, osImageStream)
199235
if err != nil {
200236
return err
201237
}
202238
klog.Infof("Successfully generated MachineConfigs from templates.")
203239

204240
configs = append(configs, iconfigs...)
205241

206-
rconfigs, err := containerruntimeconfig.RunImageBootstrap(b.templatesDir, cconfig, pools, icspRules, idmsRules, itmsRules, imgCfg, clusterImagePolicies, imagePolicies, fgHandler)
242+
rconfigs, err := containerruntimeconfig.RunImageBootstrap(b.templatesDir, cconfig, pools, icspRules, idmsRules, itmsRules, imgCfg, clusterImagePolicies, imagePolicies, fgHandler, osImageStream)
207243
if err != nil {
208244
return err
209245
}
@@ -212,7 +248,7 @@ func (b *Bootstrap) Run(destDir string) error {
212248
configs = append(configs, rconfigs...)
213249

214250
if len(crconfigs) > 0 {
215-
containerRuntimeConfigs, err := containerruntimeconfig.RunContainerRuntimeBootstrap(b.templatesDir, crconfigs, cconfig, pools)
251+
containerRuntimeConfigs, err := containerruntimeconfig.RunContainerRuntimeBootstrap(b.templatesDir, crconfigs, cconfig, pools, osImageStream)
216252
if err != nil {
217253
return err
218254
}
@@ -221,7 +257,7 @@ func (b *Bootstrap) Run(destDir string) error {
221257
klog.Infof("Successfully generated MachineConfigs from containerruntime.")
222258

223259
if featureGate != nil {
224-
featureConfigs, err := kubeletconfig.RunFeatureGateBootstrap(b.templatesDir, fgHandler, nodeConfig, cconfig, pools, apiServer)
260+
featureConfigs, err := kubeletconfig.RunFeatureGateBootstrap(b.templatesDir, fgHandler, nodeConfig, cconfig, pools, apiServer, osImageStream)
225261
if err != nil {
226262
return err
227263
}
@@ -238,7 +274,7 @@ func (b *Bootstrap) Run(destDir string) error {
238274
}
239275
}
240276
if nodeConfig != nil {
241-
nodeConfigs, err := kubeletconfig.RunNodeConfigBootstrap(b.templatesDir, fgHandler, cconfig, nodeConfig, pools, apiServer)
277+
nodeConfigs, err := kubeletconfig.RunNodeConfigBootstrap(b.templatesDir, fgHandler, cconfig, nodeConfig, pools, apiServer, osImageStream)
242278
if err != nil {
243279
return err
244280
}
@@ -247,7 +283,7 @@ func (b *Bootstrap) Run(destDir string) error {
247283
klog.Infof("Successfully generated MachineConfigs from node.Configs.")
248284

249285
if len(kconfigs) > 0 {
250-
kconfigs, err := kubeletconfig.RunKubeletBootstrap(b.templatesDir, kconfigs, cconfig, fgHandler, nodeConfig, pools, apiServer)
286+
kconfigs, err := kubeletconfig.RunKubeletBootstrap(b.templatesDir, kconfigs, cconfig, fgHandler, nodeConfig, pools, apiServer, osImageStream)
251287
if err != nil {
252288
return err
253289
}
@@ -267,7 +303,7 @@ func (b *Bootstrap) Run(destDir string) error {
267303
klog.Infof("Successfully created %d pre-built image component MachineConfigs for hybrid OCL.", len(preBuiltImageMCs))
268304
}
269305

270-
fpools, gconfigs, err := render.RunBootstrap(pools, configs, cconfig)
306+
fpools, gconfigs, err := render.RunBootstrap(pools, configs, cconfig, osImageStream)
271307
if err != nil {
272308
return err
273309
}
@@ -345,16 +381,12 @@ func (b *Bootstrap) Run(destDir string) error {
345381
return err
346382
}
347383

348-
if imageStream != nil {
349-
klog.Infof("ImageStream found!")
350-
}
351-
352384
klog.Infof("writing the following controllerConfig to disk: %s", string(buf.Bytes()))
353385
return os.WriteFile(filepath.Join(cconfigDir, "machine-config-controller.yaml"), buf.Bytes(), 0o664)
354386

355387
}
356388

357-
func getPullSecretFromSecret(sData []byte) ([]byte, error) {
389+
func getValidatePullSecretFromBytes(sData []byte) (*corev1.Secret, error) {
358390
obji, err := runtime.Decode(kscheme.Codecs.UniversalDecoder(corev1.SchemeGroupVersion), sData)
359391
if err != nil {
360392
return nil, err
@@ -366,7 +398,7 @@ func getPullSecretFromSecret(sData []byte) ([]byte, error) {
366398
if s.Type != corev1.SecretTypeDockerConfigJson {
367399
return nil, fmt.Errorf("expected secret type %s found %s", corev1.SecretTypeDockerConfigJson, s.Type)
368400
}
369-
return s.Data[corev1.DockerConfigJsonKey], nil
401+
return s, nil
370402
}
371403

372404
type manifest struct {

pkg/controller/common/helpers.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
ign2types "github.com/coreos/ignition/config/v2_2/types"
2929
validate2 "github.com/coreos/ignition/config/validate"
3030
ign3error "github.com/coreos/ignition/v2/config/shared/errors"
31+
"github.com/openshift/api/machineconfiguration/v1alpha1"
3132

3233
ign3 "github.com/coreos/ignition/v2/config/v3_5"
3334
ign3types "github.com/coreos/ignition/v2/config/v3_5/types"
@@ -68,7 +69,7 @@ func boolToPtr(b bool) *bool {
6869
// It uses the Ignition config from first object as base and appends all the rest.
6970
// Kernel arguments are concatenated.
7071
// It defaults to the OSImageURL provided by the CVO but allows a MC provided OSImageURL to take precedence.
71-
func MergeMachineConfigs(configs []*mcfgv1.MachineConfig, cconfig *mcfgv1.ControllerConfig) (*mcfgv1.MachineConfig, error) {
72+
func MergeMachineConfigs(configs []*mcfgv1.MachineConfig, cconfig *mcfgv1.ControllerConfig, imageStream *v1alpha1.OSImageStreamSet) (*mcfgv1.MachineConfig, error) {
7273
if len(configs) == 0 {
7374
return nil, nil
7475
}
@@ -187,15 +188,15 @@ func MergeMachineConfigs(configs []*mcfgv1.MachineConfig, cconfig *mcfgv1.Contro
187188
// For layering, we want to let the user override OSImageURL again
188189
// The template configs always match what's in controllerconfig because they get rendered from there,
189190
// so the only way we get an override here is if the user adds something different
190-
osImageURL := GetDefaultBaseImageContainer(&cconfig.Spec)
191+
osImageURL := GetBaseImageContainer(&cconfig.Spec, imageStream)
191192
for _, cfg := range configs {
192193
if cfg.Spec.OSImageURL != "" {
193194
osImageURL = cfg.Spec.OSImageURL
194195
}
195196
}
196197

197198
// Allow overriding the extensions container
198-
baseOSExtensionsContainerImage := cconfig.Spec.BaseOSExtensionsContainerImage
199+
baseOSExtensionsContainerImage := GetBaseExtensionsImageContainer(&cconfig.Spec, imageStream)
199200
for _, cfg := range configs {
200201
if cfg.Spec.BaseOSExtensionsContainerImage != "" {
201202
baseOSExtensionsContainerImage = cfg.Spec.BaseOSExtensionsContainerImage
@@ -1035,9 +1036,20 @@ func GetIgnitionFileDataByPath(config *ign3types.Config, path string) ([]byte, e
10351036
return nil, nil
10361037
}
10371038

1038-
// GetDefaultBaseImageContainer returns the default bootable host base image.
1039-
func GetDefaultBaseImageContainer(cconfigspec *mcfgv1.ControllerConfigSpec) string {
1040-
return cconfigspec.BaseOSContainerImage
1039+
// GetBaseImageContainer returns the default bootable host base image.
1040+
func GetBaseImageContainer(cconfigspec *mcfgv1.ControllerConfigSpec, imageStream *v1alpha1.OSImageStreamSet) string {
1041+
if imageStream == nil {
1042+
return cconfigspec.BaseOSContainerImage
1043+
}
1044+
return string(imageStream.OSImage)
1045+
}
1046+
1047+
// GetBaseExtensionsImageContainer returns the default bootable host base image.
1048+
func GetBaseExtensionsImageContainer(cconfigspec *mcfgv1.ControllerConfigSpec, imageStream *v1alpha1.OSImageStreamSet) string {
1049+
if imageStream == nil {
1050+
return cconfigspec.BaseOSExtensionsContainerImage
1051+
}
1052+
return string(imageStream.OSExtensionsImage)
10411053
}
10421054

10431055
// Configures common template FuncMaps used across all renderers.

pkg/controller/container-runtime-config/container_runtime_config_bootstrap.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ import (
44
"fmt"
55

66
mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
7+
"github.com/openshift/api/machineconfiguration/v1alpha1"
78
ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common"
9+
"github.com/openshift/machine-config-operator/pkg/controller/osimagestream"
810
"github.com/openshift/machine-config-operator/pkg/version"
911
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1012
"k8s.io/apimachinery/pkg/labels"
1113
"k8s.io/klog/v2"
1214
)
1315

1416
// RunContainerRuntimeBootstrap generates ignition configs at bootstrap
15-
func RunContainerRuntimeBootstrap(templateDir string, crconfigs []*mcfgv1.ContainerRuntimeConfig, controllerConfig *mcfgv1.ControllerConfig, mcpPools []*mcfgv1.MachineConfigPool) ([]*mcfgv1.MachineConfig, error) {
17+
func RunContainerRuntimeBootstrap(templateDir string, crconfigs []*mcfgv1.ContainerRuntimeConfig, controllerConfig *mcfgv1.ControllerConfig, mcpPools []*mcfgv1.MachineConfigPool, osImageStream *v1alpha1.OSImageStream) ([]*mcfgv1.MachineConfig, error) {
1618
var res []*mcfgv1.MachineConfig
1719
managedKeyExist := make(map[string]bool)
1820
for _, cfg := range crconfigs {
@@ -32,7 +34,12 @@ func RunContainerRuntimeBootstrap(templateDir string, crconfigs []*mcfgv1.Contai
3234
}
3335
role := pool.Name
3436
// Generate the original ContainerRuntimeConfig
35-
originalStorageIgn, _, _, err := generateOriginalContainerRuntimeConfigs(templateDir, controllerConfig, role)
37+
originalStorageIgn, _, _, err := generateOriginalContainerRuntimeConfigs(
38+
templateDir,
39+
controllerConfig,
40+
role,
41+
osimagestream.TryGetOSImageStreamFromPoolListByPoolName(osImageStream, mcpPools, pool.Name),
42+
)
3643
if err != nil {
3744
return nil, fmt.Errorf("could not generate origin ContainerRuntime Configs: %w", err)
3845
}

0 commit comments

Comments
 (0)