Skip to content

Commit f17c784

Browse files
committed
implement recreation of lost clusters still referenced by ClusterRequests
1 parent d936d4b commit f17c784

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

internal/controllers/scheduler/controller.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,35 @@ func (r *ClusterScheduler) handleCreateOrUpdate(ctx context.Context, req reconci
136136

137137
// check if request is already granted
138138
if cr.Status.Cluster != nil {
139-
log.Info("Request already contains a cluster reference, nothing to do", "clusterName", cr.Status.Cluster.Name, "clusterNamespace", cr.Status.Cluster.Namespace)
140-
return rr
139+
// verify that the referenced cluster still exists
140+
existingCluster := &clustersv1alpha1.Cluster{}
141+
existingCluster.Namespace = cr.Status.Cluster.Namespace
142+
existingCluster.Name = cr.Status.Cluster.Name
143+
if err := r.PlatformCluster.Client().Get(ctx, client.ObjectKeyFromObject(existingCluster), existingCluster); err == nil {
144+
fin := cr.FinalizerForCluster()
145+
if !controllerutil.ContainsFinalizer(existingCluster, fin) {
146+
log.Info("Referenced cluster does not contain expected finalizer, adding it", "clusterName", existingCluster.Name, "clusterNamespace", existingCluster.Namespace, "finalizer", fin)
147+
oldCluster := existingCluster.DeepCopy()
148+
controllerutil.AddFinalizer(existingCluster, fin)
149+
if err := r.PlatformCluster.Client().Patch(ctx, existingCluster, client.MergeFrom(oldCluster)); err != nil {
150+
rr.ReconcileError = errutils.WithReason(fmt.Errorf("error patching finalizer '%s' on cluster '%s/%s': %w", fin, existingCluster.Namespace, existingCluster.Name, err), cconst.ReasonPlatformClusterInteractionProblem)
151+
return rr
152+
}
153+
}
154+
log.Info("Request already contains a reference to an existing cluster, nothing to do", "clusterName", cr.Status.Cluster.Name, "clusterNamespace", cr.Status.Cluster.Namespace)
155+
return rr
156+
} else if !apierrors.IsNotFound(err) {
157+
rr.ReconcileError = errutils.WithReason(fmt.Errorf("error checking whether cluster '%s/%s' exists: %w", existingCluster.Namespace, existingCluster.Name, err), cconst.ReasonPlatformClusterInteractionProblem)
158+
return rr
159+
} else {
160+
log.Info("Referenced cluster does not exist, resetting request status to recreate it", "clusterName", existingCluster.Name, "clusterNamespace", existingCluster.Namespace)
161+
rr.Object.Status.Cluster = nil
162+
rr.Result.RequeueAfter = 1
163+
return rr
164+
}
165+
} else {
166+
log.Debug("Request status does not contain a cluster reference, checking for existing clusters with referencing finalizers")
141167
}
142-
log.Debug("Request status does not contain a cluster reference, checking for existing clusters with referencing finalizers")
143168

144169
// fetch cluster definition
145170
purpose := cr.Spec.Purpose

internal/controllers/scheduler/controller_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ var _ = Describe("Scheduler", func() {
538538
Expect(cluster2.GenerateName).To(Equal(req2.Spec.Purpose + "-"))
539539
})
540540

541-
It("should recreate a deleted cluster for an existing request", func() {
541+
It("should restore a missing finalizer and recreate a deleted cluster for an existing request", func() {
542542
clusterNamespace := "exclusive"
543543
sc, env := defaultTestSetup("testdata", "test-01")
544544
Expect(sc.Config.Scope).To(Equal(config.SCOPE_NAMESPACED))
@@ -561,6 +561,14 @@ var _ = Describe("Scheduler", func() {
561561
Expect(cluster.Name).To(Equal(req.Status.Cluster.Name))
562562
Expect(cluster.Namespace).To(Equal(clusterNamespace))
563563

564+
// remove finalizer from cluster and reconcile, which should add it again
565+
cluster.Finalizers = []string{}
566+
Expect(env.Client().Update(env.Ctx, &cluster)).To(Succeed())
567+
Expect(cluster.Finalizers).To(BeEmpty())
568+
env.ShouldReconcile(testutils.RequestFromObject(req))
569+
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(&cluster), &cluster)).To(Succeed())
570+
Expect(cluster.Finalizers).To(ContainElements(req.FinalizerForCluster()), "Finalizer should be restored on cluster")
571+
564572
// remove all finalizers and delete the cluster
565573
cluster.Finalizers = []string{}
566574
Expect(env.Client().Update(env.Ctx, &cluster)).To(Succeed())
@@ -570,7 +578,14 @@ var _ = Describe("Scheduler", func() {
570578
return apierrors.IsNotFound(err)
571579
}, 3).Should(BeTrue(), "Cluster should be deleted")
572580

573-
// reconcile again, this should recreate the cluster
581+
// reconciliation should remove the request status and set it to pending
582+
rr := env.ShouldReconcile(testutils.RequestFromObject(req))
583+
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(req), req)).To(Succeed())
584+
Expect(req.Status.Cluster).To(BeNil())
585+
Expect(req.Status.Phase).To(Equal(clustersv1alpha1.REQUEST_PENDING))
586+
Expect(rr.RequeueAfter).ToNot(BeZero(), "RequeueAfter should be set")
587+
588+
// reconcile again, this should re-create the cluster
574589
env.ShouldReconcile(testutils.RequestFromObject(req))
575590
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(req), req)).To(Succeed())
576591
Expect(req.Status.Cluster).ToNot(BeNil())

0 commit comments

Comments
 (0)