diff --git a/controllers/clustersummary_controller.go b/controllers/clustersummary_controller.go index fc5e2154..c93a3df0 100644 --- a/controllers/clustersummary_controller.go +++ b/controllers/clustersummary_controller.go @@ -223,6 +223,8 @@ func (r *ClusterSummaryReconciler) Reconcile(ctx context.Context, req ctrl.Reque } if !isReady { logger.V(logs.LogInfo).Info("cluster is not ready.") + r.setFailureMessage(clusterSummaryScope, "cluster is not ready") + r.resetFeatureStatus(clusterSummaryScope, configv1alpha1.FeatureStatusFailed) // if cluster is not ready, do nothing and don't queue for reconciliation. // When cluster becomes ready, all matching clusterSummaries will be requeued for reconciliation return reconcile.Result{}, r.updateMaps(ctx, clusterSummaryScope, logger) @@ -1083,3 +1085,27 @@ func (r *ClusterSummaryReconciler) areDependenciesDeployed(ctx context.Context, return true, dependencyMessage, nil } + +func (r *ClusterSummaryReconciler) setFailureMessage(clusterSummaryScope *scope.ClusterSummaryScope, failureMessage string) { + if clusterSummaryScope.ClusterSummary.Spec.ClusterProfileSpec.HelmCharts != nil { + clusterSummaryScope.SetFailureMessage(configv1alpha1.FeatureHelm, &failureMessage) + } + if clusterSummaryScope.ClusterSummary.Spec.ClusterProfileSpec.PolicyRefs != nil { + clusterSummaryScope.SetFailureMessage(configv1alpha1.FeatureResources, &failureMessage) + } + if clusterSummaryScope.ClusterSummary.Spec.ClusterProfileSpec.KustomizationRefs != nil { + clusterSummaryScope.SetFailureMessage(configv1alpha1.FeatureKustomize, &failureMessage) + } +} + +func (r *ClusterSummaryReconciler) resetFeatureStatus(clusterSummaryScope *scope.ClusterSummaryScope, status configv1alpha1.FeatureStatus) { + if clusterSummaryScope.ClusterSummary.Spec.ClusterProfileSpec.HelmCharts != nil { + clusterSummaryScope.SetFeatureStatus(configv1alpha1.FeatureHelm, status, nil) + } + if clusterSummaryScope.ClusterSummary.Spec.ClusterProfileSpec.PolicyRefs != nil { + clusterSummaryScope.SetFeatureStatus(configv1alpha1.FeatureResources, status, nil) + } + if clusterSummaryScope.ClusterSummary.Spec.ClusterProfileSpec.KustomizationRefs != nil { + clusterSummaryScope.SetFeatureStatus(configv1alpha1.FeatureKustomize, status, nil) + } +} diff --git a/controllers/clustersummary_controller_test.go b/controllers/clustersummary_controller_test.go index 0e04764c..3cea52f8 100644 --- a/controllers/clustersummary_controller_test.go +++ b/controllers/clustersummary_controller_test.go @@ -320,6 +320,167 @@ var _ = Describe("ClustersummaryController", func() { Expect(controllers.ShouldReconcile(reconciler, clusterSummaryScope, textlogger.NewLogger(textlogger.NewConfig()))).To(BeTrue()) }) + It("setFailureMessage set failure message for every features in ClusterSummary", func() { + clusterSummary.Spec.ClusterProfileSpec.HelmCharts = []configv1alpha1.HelmChart{ + { + RepositoryURL: randomString(), + RepositoryName: randomString(), + ChartName: randomString(), + ChartVersion: randomString(), + ReleaseName: randomString(), + ReleaseNamespace: randomString(), + }, + } + + clusterSummary.Spec.ClusterProfileSpec.PolicyRefs = []configv1alpha1.PolicyRef{ + { + Kind: string(libsveltosv1alpha1.ConfigMapReferencedResourceKind), + Namespace: randomString(), + Name: randomString(), + }, + } + + clusterSummary.Spec.ClusterProfileSpec.KustomizationRefs = []configv1alpha1.KustomizationRef{ + { + Kind: string(libsveltosv1alpha1.ConfigMapReferencedResourceKind), + Namespace: randomString(), + Name: randomString(), + Path: randomString(), + }, + } + + c := fake.NewClientBuilder().WithScheme(scheme).Build() + + clusterSummaryScope, err := scope.NewClusterSummaryScope(&scope.ClusterSummaryScopeParams{ + Client: c, + Logger: textlogger.NewLogger(textlogger.NewConfig()), + ClusterSummary: clusterSummary, + ControllerName: "clustersummary", + }) + Expect(err).To(BeNil()) + + reconciler := &controllers.ClusterSummaryReconciler{ + Client: c, + Scheme: scheme, + Deployer: nil, + ClusterMap: make(map[corev1.ObjectReference]*libsveltosset.Set), + ReferenceMap: make(map[corev1.ObjectReference]*libsveltosset.Set), + ClusterSummaryMap: make(map[types.NamespacedName]*libsveltosset.Set), + PolicyMux: sync.Mutex{}, + } + + failureMsg := randomString() + controllers.SetFailureMessage(reconciler, clusterSummaryScope, failureMsg) + + featureHelmVerified := false + featureResourcesVerified := false + featureKustomizeVerified := false + for i := range clusterSummary.Status.FeatureSummaries { + if clusterSummary.Status.FeatureSummaries[i].FeatureID == configv1alpha1.FeatureHelm { + Expect(clusterSummary.Status.FeatureSummaries[i].FailureMessage).ToNot(BeNil()) + Expect(*clusterSummary.Status.FeatureSummaries[i].FailureMessage).To(Equal(failureMsg)) + featureHelmVerified = true + } + if clusterSummary.Status.FeatureSummaries[i].FeatureID == configv1alpha1.FeatureResources { + Expect(clusterSummary.Status.FeatureSummaries[i].FailureMessage).ToNot(BeNil()) + Expect(*clusterSummary.Status.FeatureSummaries[i].FailureMessage).To(Equal(failureMsg)) + featureResourcesVerified = true + } + if clusterSummary.Status.FeatureSummaries[i].FeatureID == configv1alpha1.FeatureKustomize { + Expect(clusterSummary.Status.FeatureSummaries[i].FailureMessage).ToNot(BeNil()) + Expect(*clusterSummary.Status.FeatureSummaries[i].FailureMessage).To(Equal(failureMsg)) + featureKustomizeVerified = true + } + } + + Expect(featureHelmVerified).To(BeTrue()) + Expect(featureResourcesVerified).To(BeTrue()) + Expect(featureKustomizeVerified).To(BeTrue()) + }) + + It("resetFeatureStatus set failure message for every features in ClusterSummary", func() { + clusterSummary.Spec.ClusterProfileSpec.HelmCharts = []configv1alpha1.HelmChart{ + { + RepositoryURL: randomString(), + RepositoryName: randomString(), + ChartName: randomString(), + ChartVersion: randomString(), + ReleaseName: randomString(), + ReleaseNamespace: randomString(), + }, + } + + clusterSummary.Spec.ClusterProfileSpec.PolicyRefs = []configv1alpha1.PolicyRef{ + { + Kind: string(libsveltosv1alpha1.ConfigMapReferencedResourceKind), + Namespace: randomString(), + Name: randomString(), + }, + } + + clusterSummary.Spec.ClusterProfileSpec.KustomizationRefs = []configv1alpha1.KustomizationRef{ + { + Kind: string(libsveltosv1alpha1.ConfigMapReferencedResourceKind), + Namespace: randomString(), + Name: randomString(), + Path: randomString(), + }, + } + + clusterSummary.Status.FeatureSummaries = []configv1alpha1.FeatureSummary{ + {FeatureID: configv1alpha1.FeatureHelm, Status: configv1alpha1.FeatureStatusProvisioned, Hash: []byte(randomString())}, + {FeatureID: configv1alpha1.FeatureResources, Status: configv1alpha1.FeatureStatusProvisioned, Hash: []byte(randomString())}, + {FeatureID: configv1alpha1.FeatureKustomize, Status: configv1alpha1.FeatureStatusProvisioned, Hash: []byte(randomString())}, + } + + c := fake.NewClientBuilder().WithScheme(scheme).Build() + + clusterSummaryScope, err := scope.NewClusterSummaryScope(&scope.ClusterSummaryScopeParams{ + Client: c, + Logger: textlogger.NewLogger(textlogger.NewConfig()), + ClusterSummary: clusterSummary, + ControllerName: "clustersummary", + }) + Expect(err).To(BeNil()) + + reconciler := &controllers.ClusterSummaryReconciler{ + Client: c, + Scheme: scheme, + Deployer: nil, + ClusterMap: make(map[corev1.ObjectReference]*libsveltosset.Set), + ReferenceMap: make(map[corev1.ObjectReference]*libsveltosset.Set), + ClusterSummaryMap: make(map[types.NamespacedName]*libsveltosset.Set), + PolicyMux: sync.Mutex{}, + } + + controllers.ResetFeatureStatus(reconciler, clusterSummaryScope, configv1alpha1.FeatureStatusFailed) + + featureHelmVerified := false + featureResourcesVerified := false + featureKustomizeVerified := false + for i := range clusterSummary.Status.FeatureSummaries { + if clusterSummary.Status.FeatureSummaries[i].FeatureID == configv1alpha1.FeatureHelm { + Expect(clusterSummary.Status.FeatureSummaries[i].Status).To(Equal(configv1alpha1.FeatureStatusFailed)) + Expect(clusterSummary.Status.FeatureSummaries[i].Hash).To(BeNil()) + featureHelmVerified = true + } + if clusterSummary.Status.FeatureSummaries[i].FeatureID == configv1alpha1.FeatureResources { + Expect(clusterSummary.Status.FeatureSummaries[i].Status).To(Equal(configv1alpha1.FeatureStatusFailed)) + Expect(clusterSummary.Status.FeatureSummaries[i].Hash).To(BeNil()) + featureResourcesVerified = true + } + if clusterSummary.Status.FeatureSummaries[i].FeatureID == configv1alpha1.FeatureKustomize { + Expect(clusterSummary.Status.FeatureSummaries[i].Status).To(Equal(configv1alpha1.FeatureStatusFailed)) + Expect(clusterSummary.Status.FeatureSummaries[i].Hash).To(BeNil()) + featureKustomizeVerified = true + } + } + + Expect(featureHelmVerified).To(BeTrue()) + Expect(featureResourcesVerified).To(BeTrue()) + Expect(featureKustomizeVerified).To(BeTrue()) + }) + It("shouldReconcile returns true when mode is OneTime but not all helm charts are deployed", func() { clusterSummary.Spec.ClusterProfileSpec.SyncMode = configv1alpha1.SyncModeOneTime clusterSummary.Spec.ClusterProfileSpec.HelmCharts = []configv1alpha1.HelmChart{ diff --git a/controllers/export_test.go b/controllers/export_test.go index c30d0e04..db2713d2 100644 --- a/controllers/export_test.go +++ b/controllers/export_test.go @@ -59,6 +59,8 @@ var ( CanRemoveFinalizer = (*ClusterSummaryReconciler).canRemoveFinalizer ReconcileDelete = (*ClusterSummaryReconciler).reconcileDelete AreDependenciesDeployed = (*ClusterSummaryReconciler).areDependenciesDeployed + SetFailureMessage = (*ClusterSummaryReconciler).setFailureMessage + ResetFeatureStatus = (*ClusterSummaryReconciler).resetFeatureStatus ConvertResultStatus = (*ClusterSummaryReconciler).convertResultStatus RequeueClusterSummaryForReference = (*ClusterSummaryReconciler).requeueClusterSummaryForReference