diff --git a/pkg/controllers/cloud_config_sync_controller.go b/pkg/controllers/cloud_config_sync_controller.go index 4ad41e972..df1c9dd36 100644 --- a/pkg/controllers/cloud_config_sync_controller.go +++ b/pkg/controllers/cloud_config_sync_controller.go @@ -187,6 +187,8 @@ func (r *CloudConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) klog.Infof("Initializing minimal config for platform %s", platformType) minimalConfig := getMinimalConfigForPlatform(platformType) sourceCM.Data = map[string]string{defaultConfigKey: minimalConfig} + } else { + return ctrl.Result{}, fmt.Errorf("cloud-config source configmap %s/%s not found", openshiftUnmanagedCMKey.Namespace, openshiftUnmanagedCMKey.Name) } } else if err != nil { klog.Errorf("unable to get cloud-config for sync: %v", err) diff --git a/pkg/controllers/cloud_config_sync_controller_test.go b/pkg/controllers/cloud_config_sync_controller_test.go index a9e370ef9..fba962d47 100644 --- a/pkg/controllers/cloud_config_sync_controller_test.go +++ b/pkg/controllers/cloud_config_sync_controller_test.go @@ -428,6 +428,15 @@ var _ = Describe("Cloud config sync reconciler", func() { targetNamespaceName := testManagedNamespace BeforeEach(func() { + deleteOptions := &client.DeleteOptions{ + GracePeriodSeconds: ptr.To[int64](0), + } + existingCMs := &corev1.ConfigMapList{} + Expect(cl.List(ctx, existingCMs, &client.ListOptions{Namespace: targetNamespaceName})).To(Succeed()) + for _, cm := range existingCMs.Items { + Expect(cl.Delete(ctx, cm.DeepCopy(), deleteOptions)).To(Succeed()) + } + reconciler = &CloudConfigReconciler{ ClusterOperatorStatusClient: ClusterOperatorStatusClient{ Client: cl, @@ -548,6 +557,31 @@ var _ = Describe("Cloud config sync reconciler", func() { Expect(degradedCond.Status).To(Equal(configv1.ConditionTrue)) }) + It("should treat a missing source configmap as transient until it reappears", func() { + Expect(cl.Delete(ctx, makeInfraCloudConfig(configv1.AWSPlatformType))).To(Succeed()) + + infraResource := makeInfrastructureResource(configv1.AWSPlatformType) + Expect(cl.Create(ctx, infraResource)).To(Succeed()) + + infraResource.Status = makeInfraStatus(infraResource.Spec.PlatformSpec.Type) + Expect(cl.Status().Update(ctx, infraResource.DeepCopy())).To(Succeed()) + + _, err := reconciler.Reconcile(context.TODO(), ctrl.Request{}) + Expect(err).To(HaveOccurred()) + + co := &configv1.ClusterOperator{} + Expect(cl.Get(ctx, client.ObjectKey{Name: clusterOperatorName}, co)).To(MatchError(apierrors.IsNotFound, "IsNotFound")) + + Expect(cl.Create(ctx, makeInfraCloudConfig(configv1.AWSPlatformType))).To(Succeed()) + + _, err = reconciler.Reconcile(context.TODO(), ctrl.Request{}) + Expect(err).NotTo(HaveOccurred()) + + Expect(cl.Get(ctx, client.ObjectKey{Name: clusterOperatorName}, co)).To(Succeed()) + Expect(v1helpers.IsStatusConditionTrue(co.Status.Conditions, cloudConfigControllerDegradedCondition)).To(BeFalse()) + Expect(v1helpers.IsStatusConditionTrue(co.Status.Conditions, cloudConfigControllerAvailableCondition)).To(BeTrue()) + }) + It("should continue with reconcile when feature gates are available", func() { reconciler.FeatureGateAccess = featuregates.NewHardcodedFeatureGateAccessForTesting( []configv1.FeatureGateName{"CloudControllerManagerWebhook", "ChocobombVanilla", "ChocobombStrawberry"}, @@ -604,9 +638,8 @@ var _ = Describe("Cloud config sync reconciler", func() { Expect(cl.Status().Update(ctx, infraResource.DeepCopy())).To(Succeed()) _, err := reconciler.Reconcile(context.TODO(), ctrl.Request{}) Expect(err).To(BeNil()) - allCMs := &corev1.ConfigMapList{} - Expect(cl.List(ctx, allCMs, &client.ListOptions{Namespace: targetNamespaceName})).To(Succeed()) - Expect(len(allCMs.Items)).To(BeZero()) + Expect(cl.Get(ctx, client.ObjectKey{Namespace: targetNamespaceName, Name: syncedCloudConfigMapName}, &corev1.ConfigMap{})). + To(MatchError(apierrors.IsNotFound, "IsNotFound")) }) })