Skip to content

Commit 4d1da92

Browse files
committed
conditionally aggregate the machineapimigration controllers conditions
1 parent 89bde08 commit 4d1da92

File tree

5 files changed

+102
-47
lines changed

5 files changed

+102
-47
lines changed

cmd/cluster-capi-operator/main.go

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package main
1515

1616
import (
1717
"context"
18+
"errors"
1819
"flag"
1920
"fmt"
2021
"os"
@@ -49,8 +50,11 @@ import (
4950
crwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
5051

5152
configv1 "github.com/openshift/api/config/v1"
53+
"github.com/openshift/api/features"
5254
mapiv1 "github.com/openshift/api/machine/v1"
5355
mapiv1beta1 "github.com/openshift/api/machine/v1beta1"
56+
configv1client "github.com/openshift/client-go/config/clientset/versioned"
57+
configinformers "github.com/openshift/client-go/config/informers/externalversions"
5458
"github.com/openshift/cluster-capi-operator/pkg/controllers"
5559
"github.com/openshift/cluster-capi-operator/pkg/controllers/capiinstaller"
5660
"github.com/openshift/cluster-capi-operator/pkg/controllers/clusteroperator"
@@ -61,12 +65,17 @@ import (
6165
"github.com/openshift/cluster-capi-operator/pkg/operatorstatus"
6266
"github.com/openshift/cluster-capi-operator/pkg/util"
6367
"github.com/openshift/cluster-capi-operator/pkg/webhook"
68+
featuregates "github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
69+
"github.com/openshift/library-go/pkg/operator/events"
6470
)
6571

6672
const (
6773
defaultImagesLocation = "./dev-images.json"
6874
)
6975

76+
// errTimedOutWaitingForFeatureGates is returned when the feature gates are not initialized within the timeout.
77+
var errTimedOutWaitingForFeatureGates = errors.New("timed out waiting for feature gates to be initialized")
78+
7079
func initScheme(scheme *runtime.Scheme) {
7180
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
7281
utilruntime.Must(configv1.AddToScheme(scheme))
@@ -226,7 +235,22 @@ func main() {
226235
os.Exit(1)
227236
}
228237

229-
setupPlatformReconcilers(mgr, infra, platform, containerImages, applyClient, apiextensionsClient, *managedNamespace, *sourceNamespace)
238+
featureGateAccessor, err := getFeatureGates(mgr)
239+
if err != nil {
240+
klog.Error(err, "unable to get feature gates")
241+
os.Exit(1)
242+
}
243+
244+
currentFeatureGates, err := featureGateAccessor.CurrentFeatureGates()
245+
if err != nil {
246+
klog.Error(err, "unable to get current feature gates")
247+
os.Exit(1)
248+
}
249+
250+
if currentFeatureGates.Enabled(features.FeatureGateMachineAPIMigration) {
251+
}
252+
253+
setupPlatformReconcilers(mgr, infra, platform, containerImages, applyClient, apiextensionsClient, currentFeatureGates, *managedNamespace, *sourceNamespace)
230254

231255
// +kubebuilder:scaffold:builder
232256

@@ -248,57 +272,60 @@ func main() {
248272
}
249273
}
250274

251-
func getClusterOperatorStatusClient(mgr manager.Manager, controller string, managedNamespace string) operatorstatus.ClusterOperatorStatusClient {
275+
func getClusterOperatorStatusClient(mgr manager.Manager, currentFeatureGates featuregates.FeatureGate, controller string, managedNamespace string) operatorstatus.ClusterOperatorStatusClient {
252276
return operatorstatus.ClusterOperatorStatusClient{
253277
Client: mgr.GetClient(),
254278
Recorder: mgr.GetEventRecorderFor(controller),
255279
ReleaseVersion: util.GetReleaseVersion(),
256280
ManagedNamespace: managedNamespace,
281+
FeatureGates: currentFeatureGates,
257282
}
258283
}
259284

260-
func setupPlatformReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platform configv1.PlatformType, containerImages map[string]string, applyClient *kubernetes.Clientset, apiextensionsClient *apiextensionsclient.Clientset, managedNamespace, sourceNamespace string) {
285+
func setupPlatformReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platform configv1.PlatformType, containerImages map[string]string, applyClient *kubernetes.Clientset,
286+
apiextensionsClient *apiextensionsclient.Clientset, currentFeatureGates featuregates.FeatureGate, managedNamespace, sourceNamespace string) {
261287
// Only setup reconcile controllers and webhooks when the platform is supported.
262288
// This avoids unnecessary CAPI providers discovery, installs and reconciles when the platform is not supported.
263289
switch platform {
264290
case configv1.AWSPlatformType:
265-
setupReconcilers(mgr, infra, platform, &awsv1.AWSCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace, sourceNamespace)
291+
setupReconcilers(mgr, infra, platform, &awsv1.AWSCluster{}, containerImages, applyClient, apiextensionsClient, currentFeatureGates, managedNamespace, sourceNamespace)
266292
setupWebhooks(mgr)
267293
case configv1.GCPPlatformType:
268-
setupReconcilers(mgr, infra, platform, &gcpv1.GCPCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace, sourceNamespace)
294+
setupReconcilers(mgr, infra, platform, &gcpv1.GCPCluster{}, containerImages, applyClient, apiextensionsClient, currentFeatureGates, managedNamespace, sourceNamespace)
269295
setupWebhooks(mgr)
270296
case configv1.AzurePlatformType:
271297
azureCloudEnvironment := getAzureCloudEnvironment(infra.Status.PlatformStatus)
272298
if azureCloudEnvironment == configv1.AzureStackCloud {
273299
klog.Infof("Detected Azure Cloud Environment %q on platform %q is not supported, skipping capi controllers setup", azureCloudEnvironment, platform)
274-
setupClusterOperatorController(mgr, managedNamespace, true)
300+
setupClusterOperatorController(mgr, managedNamespace, currentFeatureGates, true)
275301
} else {
276302
// The ClusterOperator Controller must run in all cases.
277-
setupReconcilers(mgr, infra, platform, &azurev1.AzureCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace, sourceNamespace)
303+
setupReconcilers(mgr, infra, platform, &azurev1.AzureCluster{}, containerImages, applyClient, apiextensionsClient, currentFeatureGates, managedNamespace, sourceNamespace)
278304
setupWebhooks(mgr)
279305
}
280306
case configv1.PowerVSPlatformType:
281-
setupReconcilers(mgr, infra, platform, &ibmpowervsv1.IBMPowerVSCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace, sourceNamespace)
307+
setupReconcilers(mgr, infra, platform, &ibmpowervsv1.IBMPowerVSCluster{}, containerImages, applyClient, apiextensionsClient, currentFeatureGates, managedNamespace, sourceNamespace)
282308
setupWebhooks(mgr)
283309
case configv1.VSpherePlatformType:
284-
setupReconcilers(mgr, infra, platform, &vspherev1.VSphereCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace, sourceNamespace)
310+
setupReconcilers(mgr, infra, platform, &vspherev1.VSphereCluster{}, containerImages, applyClient, apiextensionsClient, currentFeatureGates, managedNamespace, sourceNamespace)
285311
setupWebhooks(mgr)
286312
case configv1.OpenStackPlatformType:
287-
setupReconcilers(mgr, infra, platform, &openstackv1.OpenStackCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace, sourceNamespace)
313+
setupReconcilers(mgr, infra, platform, &openstackv1.OpenStackCluster{}, containerImages, applyClient, apiextensionsClient, currentFeatureGates, managedNamespace, sourceNamespace)
288314
setupWebhooks(mgr)
289315
default:
290316
klog.Infof("Detected platform %q is not supported, skipping capi controllers setup", platform)
291317
// The ClusterOperator Controller must run under all circumstances as it manages the ClusterOperator object for this operator.
292-
setupClusterOperatorController(mgr, managedNamespace, true)
318+
setupClusterOperatorController(mgr, managedNamespace, currentFeatureGates, true)
293319
}
294320
}
295321

296-
func setupReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platform configv1.PlatformType, infraClusterObject client.Object, containerImages map[string]string, applyClient *kubernetes.Clientset, apiextensionsClient *apiextensionsclient.Clientset, managedNamespace, sourceNamespace string) {
322+
func setupReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platform configv1.PlatformType, infraClusterObject client.Object, containerImages map[string]string,
323+
applyClient *kubernetes.Clientset, apiextensionsClient *apiextensionsclient.Clientset, currentFeatureGates featuregates.FeatureGate, managedNamespace, sourceNamespace string) {
297324
// The ClusterOperator Controller must run under all circumstances as it manages the ClusterOperator object for this operator.
298-
setupClusterOperatorController(mgr, managedNamespace, false)
325+
setupClusterOperatorController(mgr, managedNamespace, currentFeatureGates, false)
299326

300327
if err := (&corecluster.CoreClusterController{
301-
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, "cluster-capi-operator-cluster-resource-controller", managedNamespace),
328+
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, currentFeatureGates, "cluster-capi-operator-cluster-resource-controller", managedNamespace),
302329
Cluster: &clusterv1.Cluster{},
303330
Platform: platform,
304331
Infra: infra,
@@ -308,7 +335,7 @@ func setupReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platf
308335
}
309336

310337
if err := (&secretsync.SecretSyncController{
311-
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, "cluster-capi-operator-secret-sync-controller", managedNamespace),
338+
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, currentFeatureGates, "cluster-capi-operator-secret-sync-controller", managedNamespace),
312339
Scheme: mgr.GetScheme(),
313340
SourceNamespace: sourceNamespace,
314341
}).SetupWithManager(mgr); err != nil {
@@ -317,7 +344,7 @@ func setupReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platf
317344
}
318345

319346
if err := (&kubeconfig.KubeconfigController{
320-
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, "cluster-capi-operator-kubeconfig-controller", managedNamespace),
347+
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, currentFeatureGates, "cluster-capi-operator-kubeconfig-controller", managedNamespace),
321348
Scheme: mgr.GetScheme(),
322349
RestCfg: mgr.GetConfig(),
323350
}).SetupWithManager(mgr); err != nil {
@@ -326,7 +353,7 @@ func setupReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platf
326353
}
327354

328355
if err := (&capiinstaller.CapiInstallerController{
329-
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, "cluster-capi-operator-capi-installer-controller", managedNamespace),
356+
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, currentFeatureGates, "cluster-capi-operator-capi-installer-controller", managedNamespace),
330357
Scheme: mgr.GetScheme(),
331358
Images: containerImages,
332359
RestCfg: mgr.GetConfig(),
@@ -339,7 +366,7 @@ func setupReconcilers(mgr manager.Manager, infra *configv1.Infrastructure, platf
339366
}
340367

341368
if err := (&infracluster.InfraClusterController{
342-
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, "cluster-capi-operator-infracluster-controller", managedNamespace),
369+
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, currentFeatureGates, "cluster-capi-operator-infracluster-controller", managedNamespace),
343370
Scheme: mgr.GetScheme(),
344371
Images: containerImages,
345372
RestCfg: mgr.GetConfig(),
@@ -383,14 +410,48 @@ func getAzureCloudEnvironment(ps *configv1.PlatformStatus) configv1.AzureCloudEn
383410
return ps.Azure.CloudName
384411
}
385412

386-
func setupClusterOperatorController(mgr manager.Manager, ns string, isUnsupportedPlatform bool) {
413+
func setupClusterOperatorController(mgr manager.Manager, ns string, currentFeatureGates featuregates.FeatureGate, isUnsupportedPlatform bool) {
387414
// ClusterOperator watches and keeps the cluster-api ClusterObject up to date.
388415
if err := (&clusteroperator.ClusterOperatorController{
389-
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, "cluster-capi-operator-clusteroperator-controller", ns),
416+
ClusterOperatorStatusClient: getClusterOperatorStatusClient(mgr, currentFeatureGates, "cluster-capi-operator-clusteroperator-controller", ns),
390417
Scheme: mgr.GetScheme(),
391418
IsUnsupportedPlatform: isUnsupportedPlatform,
392419
}).SetupWithManager(mgr); err != nil {
393420
klog.Error(err, "unable to create clusteroperator controller", "controller", "ClusterOperator")
394421
os.Exit(1)
395422
}
396423
}
424+
425+
// getFeatureGates is used to fetch the current feature gates from the cluster.
426+
// We use this to check if the machine api migration is actually enabled or not.
427+
func getFeatureGates(mgr ctrl.Manager) (featuregates.FeatureGateAccess, error) {
428+
desiredVersion := util.GetReleaseVersion()
429+
missingVersion := "0.0.1-snapshot"
430+
431+
configClient, err := configv1client.NewForConfig(mgr.GetConfig())
432+
if err != nil {
433+
return nil, fmt.Errorf("failed to create config client: %w", err)
434+
}
435+
436+
configInformers := configinformers.NewSharedInformerFactory(configClient, 10*time.Minute)
437+
438+
// By default, this will exit(0) if the featuregates change.
439+
featureGateAccessor := featuregates.NewFeatureGateAccess(
440+
desiredVersion, missingVersion,
441+
configInformers.Config().V1().ClusterVersions(),
442+
configInformers.Config().V1().FeatureGates(),
443+
events.NewLoggingEventRecorder("machineapimigration"),
444+
)
445+
go featureGateAccessor.Run(context.Background())
446+
go configInformers.Start(context.Background().Done())
447+
448+
select {
449+
case <-featureGateAccessor.InitialFeatureGatesObserved():
450+
featureGates, _ := featureGateAccessor.CurrentFeatureGates()
451+
klog.Infof("FeatureGates initialized: %v", featureGates.KnownFeatures())
452+
case <-time.After(1 * time.Minute):
453+
return nil, errTimedOutWaitingForFeatureGates
454+
}
455+
456+
return featureGateAccessor, nil
457+
}

pkg/controllers/clusteroperator/clusteroperator_controller.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
configv1 "github.com/openshift/api/config/v1"
3030
"github.com/openshift/cluster-capi-operator/pkg/controllers"
3131
"github.com/openshift/cluster-capi-operator/pkg/operatorstatus"
32+
featuregates "github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
3233
)
3334

3435
const (
@@ -40,6 +41,7 @@ type ClusterOperatorController struct {
4041
operatorstatus.ClusterOperatorStatusClient
4142
Scheme *runtime.Scheme
4243
IsUnsupportedPlatform bool
44+
FeatureGates featuregates.FeatureGate
4345
}
4446

4547
// Reconcile reconciles the cluster-api ClusterOperator object.

0 commit comments

Comments
 (0)