Skip to content

Commit 09e7b26

Browse files
authored
Merge pull request #473 from gianlucam76/unhealthy-cluster
If cluster is not ready, don't queue for reconciliation
2 parents 6377fc0 + 08864b6 commit 09e7b26

8 files changed

+111
-15
lines changed

controllers/clusterprofile_predicates.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,6 @@ func ClusterPredicates(logger logr.Logger) predicate.Funcs {
4545
return true
4646
}
4747

48-
// return true if Cluster.Spec.Paused has changed from true to false
49-
if oldCluster.Spec.Paused && !newCluster.Spec.Paused {
50-
log.V(logs.LogVerbose).Info(
51-
"Cluster was unpaused. Will attempt to reconcile associated ClusterProfiles.")
52-
return true
53-
}
54-
5548
// a label change migth change which clusters match which clusterprofile
5649
if !reflect.DeepEqual(oldCluster.Labels, newCluster.Labels) {
5750
log.V(logs.LogVerbose).Info(
@@ -68,6 +61,20 @@ func ClusterPredicates(logger logr.Logger) predicate.Funcs {
6861
return true
6962
}
7063

64+
// return true if Cluster.Spec.Paused has changed from true to false
65+
if oldCluster.Spec.Paused && !newCluster.Spec.Paused {
66+
log.V(logs.LogVerbose).Info(
67+
"Cluster was unpaused. Will attempt to reconcile associated ClusterProfiles.")
68+
return true
69+
}
70+
71+
// return true if Cluster.Status.ControlPlaneReady has changed from false to true
72+
if !oldCluster.Status.ControlPlaneReady && newCluster.Status.ControlPlaneReady {
73+
log.V(logs.LogVerbose).Info(
74+
"Cluster was not ready. Will attempt to reconcile associated ClusterProfiles.")
75+
return true
76+
}
77+
7178
// otherwise, return false
7279
log.V(logs.LogVerbose).Info(
7380
"Cluster did not match expected conditions. Will not attempt to reconcile associated ClusterProfiles.")

controllers/clustersummary_controller.go

+35
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,17 @@ func (r *ClusterSummaryReconciler) Reconcile(ctx context.Context, req ctrl.Reque
204204
return reconcile.Result{Requeue: true, RequeueAfter: normalRequeueAfter}, nil
205205
}
206206

207+
isReady, err := r.isReady(ctx, clusterSummary)
208+
if err != nil {
209+
return reconcile.Result{Requeue: true, RequeueAfter: normalRequeueAfter}, nil
210+
}
211+
if !isReady {
212+
logger.V(logs.LogInfo).Info("cluster is not ready.")
213+
// if cluster is not ready, do nothing and don't queue for reconciliation.
214+
// When cluster becomes ready, all matching clusterSummaries will be requeued for reconciliation
215+
return reconcile.Result{}, r.updateMaps(ctx, clusterSummaryScope, logger)
216+
}
217+
207218
// Always close the scope when exiting this function so we can persist any ClusterSummary
208219
// changes.
209220
defer func() {
@@ -760,6 +771,13 @@ func (r *ClusterSummaryReconciler) shouldReconcile(clusterSummaryScope *scope.Cl
760771
}
761772
}
762773

774+
if len(clusterSummary.Spec.ClusterProfileSpec.KustomizationRefs) != 0 {
775+
if !r.isFeatureDeployed(clusterSummaryScope.ClusterSummary, configv1alpha1.FeatureKustomize) {
776+
logger.V(logs.LogDebug).Info("Mode set to one time. Kustomization resources not deployed yet. Reconciliation is needed.")
777+
return true
778+
}
779+
}
780+
763781
return false
764782
}
765783

@@ -812,6 +830,23 @@ func (r *ClusterSummaryReconciler) getReferenceMapForEntry(entry *corev1.ObjectR
812830
return s
813831
}
814832

833+
// isReady returns true if Sveltos/Cluster is ready
834+
func (r *ClusterSummaryReconciler) isReady(ctx context.Context,
835+
clusterSummary *configv1alpha1.ClusterSummary) (bool, error) {
836+
837+
isClusterReady, err := clusterproxy.IsClusterReady(ctx, r.Client, clusterSummary.Spec.ClusterNamespace,
838+
clusterSummary.Spec.ClusterName, clusterSummary.Spec.ClusterType)
839+
840+
if err != nil {
841+
if apierrors.IsNotFound(err) {
842+
return false, nil
843+
}
844+
return false, err
845+
}
846+
847+
return isClusterReady, nil
848+
}
849+
815850
// isPaused returns true if Sveltos/Cluster is paused or ClusterSummary has paused annotation.
816851
func (r *ClusterSummaryReconciler) isPaused(ctx context.Context,
817852
clusterSummary *configv1alpha1.ClusterSummary) (bool, error) {

controllers/clustersummary_controller_test.go

+51-4
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ var _ = Describe("ClustersummaryController", func() {
6565
"dc": "eng",
6666
},
6767
},
68+
Status: clusterv1.ClusterStatus{
69+
ControlPlaneReady: true,
70+
},
6871
}
6972

7073
clusterProfile = &configv1alpha1.ClusterProfile{
@@ -92,11 +95,42 @@ var _ = Describe("ClustersummaryController", func() {
9295

9396
prepareForDeployment(clusterProfile, clusterSummary, cluster)
9497

98+
cluster.Status.ControlPlaneReady = true
99+
95100
// Get ClusterSummary so OwnerReference is set
96101
Expect(testEnv.Get(context.TODO(),
97102
types.NamespacedName{Namespace: clusterSummary.Namespace, Name: clusterSummary.Name}, clusterSummary)).To(Succeed())
98103
})
99104

105+
It("isReady returns true if CAPI Cluster has Status.ControlPlaneReady set to true", func() {
106+
cluster.Status.ControlPlaneReady = true
107+
108+
initObjects := []client.Object{
109+
clusterProfile,
110+
clusterSummary,
111+
cluster,
112+
}
113+
114+
c := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(initObjects...).WithObjects(initObjects...).Build()
115+
116+
reconciler := &controllers.ClusterSummaryReconciler{
117+
Client: c,
118+
Scheme: scheme,
119+
Deployer: nil,
120+
ClusterMap: make(map[corev1.ObjectReference]*libsveltosset.Set),
121+
ReferenceMap: make(map[corev1.ObjectReference]*libsveltosset.Set),
122+
ClusterSummaryMap: make(map[types.NamespacedName]*libsveltosset.Set),
123+
PolicyMux: sync.Mutex{},
124+
}
125+
126+
Expect(controllers.IsReady(reconciler, context.TODO(), clusterSummary)).To(BeTrue())
127+
128+
cluster.Status.ControlPlaneReady = false
129+
Expect(c.Status().Update(context.TODO(), cluster)).To(Succeed())
130+
131+
Expect(controllers.IsReady(reconciler, context.TODO(), clusterSummary)).To(BeFalse())
132+
})
133+
100134
It("isPaused returns true if CAPI Cluster has Spec.Paused set", func() {
101135
initObjects := []client.Object{
102136
clusterProfile,
@@ -964,6 +998,13 @@ var _ = Describe("ClusterSummaryReconciler: requeue methods", func() {
964998
Expect(waitForObject(context.TODO(), testEnv.Client, ns)).To(Succeed())
965999

9661000
Expect(testEnv.Client.Create(context.TODO(), cluster)).To(Succeed())
1001+
Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
1002+
currentCluster := clusterv1.Cluster{}
1003+
Expect(testEnv.Client.Get(context.TODO(),
1004+
types.NamespacedName{Namespace: cluster.Namespace, Name: cluster.Name},
1005+
&currentCluster)).To(Succeed())
1006+
currentCluster.Status.ControlPlaneReady = true
1007+
Expect(testEnv.Client.Status().Update(ctx, &currentCluster)).To(Succeed())
9671008

9681009
configMap := createConfigMapWithPolicy(namespace, randomString(), fmt.Sprintf(editClusterRole, randomString()))
9691010
By(fmt.Sprintf("Creating %s %s/%s", configMap.Kind, configMap.Namespace, configMap.Name))
@@ -1033,6 +1074,16 @@ var _ = Describe("ClusterSummaryReconciler: requeue methods", func() {
10331074
Expect(testEnv.Client.Create(context.TODO(), ns)).To(Succeed())
10341075
Expect(waitForObject(context.TODO(), testEnv.Client, ns)).To(Succeed())
10351076

1077+
Expect(testEnv.Client.Create(context.TODO(), cluster)).To(Succeed())
1078+
Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
1079+
Expect(addTypeInformationToObject(scheme, cluster)).To(Succeed())
1080+
currentCluster := clusterv1.Cluster{}
1081+
Expect(testEnv.Client.Get(context.TODO(),
1082+
types.NamespacedName{Namespace: cluster.Namespace, Name: cluster.Name},
1083+
&currentCluster)).To(Succeed())
1084+
currentCluster.Status.ControlPlaneReady = true
1085+
Expect(testEnv.Client.Status().Update(ctx, &currentCluster)).To(Succeed())
1086+
10361087
Expect(testEnv.Client.Create(context.TODO(), referencingClusterSummary)).To(Succeed())
10371088
Expect(waitForObject(context.TODO(), testEnv.Client, referencingClusterSummary)).To(Succeed())
10381089
addOwnerReference(ctx, testEnv.Client, referencingClusterSummary, clusterProfile)
@@ -1041,10 +1092,6 @@ var _ = Describe("ClusterSummaryReconciler: requeue methods", func() {
10411092
Expect(waitForObject(context.TODO(), testEnv.Client, nonReferencingClusterSummary)).To(Succeed())
10421093
addOwnerReference(ctx, testEnv.Client, nonReferencingClusterSummary, clusterProfile)
10431094

1044-
Expect(testEnv.Client.Create(context.TODO(), cluster)).To(Succeed())
1045-
Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
1046-
Expect(addTypeInformationToObject(scheme, cluster)).To(Succeed())
1047-
10481095
clusterSummaryName := client.ObjectKey{
10491096
Name: referencingClusterSummary.Name,
10501097
Namespace: referencingClusterSummary.Namespace,

controllers/clustersummary_transformations.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func (r *ClusterSummaryReconciler) requeueClusterSummaryForCluster(
176176
cluster.GetName(),
177177
)
178178

179-
logger.V(logs.LogDebug).Info("reacting to CAPI Cluster change")
179+
logger.V(logs.LogDebug).Info("reacting to Cluster change")
180180

181181
r.PolicyMux.Lock()
182182
defer r.PolicyMux.Unlock()

controllers/export_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ var (
5252
UndeployFeature = (*ClusterSummaryReconciler).undeployFeature
5353
GetCurrentReferences = (*ClusterSummaryReconciler).getCurrentReferences
5454
IsPaused = (*ClusterSummaryReconciler).isPaused
55+
IsReady = (*ClusterSummaryReconciler).isReady
5556
ShouldReconcile = (*ClusterSummaryReconciler).shouldReconcile
5657
UpdateChartMap = (*ClusterSummaryReconciler).updateChartMap
5758
ShouldRedeploy = (*ClusterSummaryReconciler).shouldRedeploy

controllers/suite_helpers_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,12 @@ func prepareForDeployment(clusterProfile *configv1alpha1.ClusterProfile,
284284

285285
Expect(testEnv.Client.Create(context.TODO(), cluster)).To(Succeed())
286286
Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
287+
currentCluster := clusterv1.Cluster{}
288+
Expect(testEnv.Client.Get(context.TODO(),
289+
types.NamespacedName{Namespace: cluster.Namespace, Name: cluster.Name},
290+
&currentCluster)).To(Succeed())
291+
currentCluster.Status.ControlPlaneReady = true
292+
Expect(testEnv.Client.Status().Update(ctx, &currentCluster)).To(Succeed())
287293

288294
// This method is invoked by different tests in parallel, all touching same clusterConfiguration.
289295
// So add this logic in a Retry

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ require (
1515
github.com/onsi/ginkgo/v2 v2.15.0
1616
github.com/onsi/gomega v1.31.1
1717
github.com/pkg/errors v0.9.1
18-
github.com/projectsveltos/libsveltos v0.24.0
18+
github.com/projectsveltos/libsveltos v0.24.1-0.20240228174147-47c5e43b510a
1919
github.com/prometheus/client_golang v1.18.0
2020
github.com/spf13/pflag v1.0.5
2121
github.com/yuin/gopher-lua v1.1.1

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
335335
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
336336
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
337337
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
338-
github.com/projectsveltos/libsveltos v0.24.0 h1:2wxUqLhIEJMRye9rHypc+uT0M++CunByuOA5Pu6TGH8=
339-
github.com/projectsveltos/libsveltos v0.24.0/go.mod h1:h2NUzyHkIc9u6T4NOQzpPnJmX8Rrumpmszo8wM8BUkA=
338+
github.com/projectsveltos/libsveltos v0.24.1-0.20240228174147-47c5e43b510a h1:6XlVKNkVn38RCz8kvLTejRg9VPEBnmSJ+cjcKA62o08=
339+
github.com/projectsveltos/libsveltos v0.24.1-0.20240228174147-47c5e43b510a/go.mod h1:h2NUzyHkIc9u6T4NOQzpPnJmX8Rrumpmszo8wM8BUkA=
340340
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
341341
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
342342
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=

0 commit comments

Comments
 (0)