From 73cd189bd56b49bd1e2432e9fa7cb32fd9d1cc0a Mon Sep 17 00:00:00 2001 From: Claudia Beresford Date: Wed, 7 Dec 2022 14:10:33 +0000 Subject: [PATCH] feat: MicrovmDeployment Delete --- api/v1alpha1/condition_consts.go | 6 ++ controllers/microvmdeployment_controller.go | 55 ++++++++++++++++++- .../microvmdeployment_controller_test.go | 55 ++++++++++++++++++- .../microvmreplicaset_controller_test.go | 4 +- 4 files changed, 116 insertions(+), 4 deletions(-) diff --git a/api/v1alpha1/condition_consts.go b/api/v1alpha1/condition_consts.go index 508e0e9..ce43590 100644 --- a/api/v1alpha1/condition_consts.go +++ b/api/v1alpha1/condition_consts.go @@ -57,4 +57,10 @@ const ( // MicrovmDeploymentUpdateFailed indicates the microvm deployment is in a pending state. MicrovmDeploymentUpdateFailedReason = "MicrovmDeploymentUpdateFailed" + + // MicrovmDeploymentDeletingReason indicates the microvmreplicaset is in a deleted state. + MicrovmDeploymentDeletingReason = "MicrovmDeploymentDeleting" + + // MicrovmDeploymentDeleteFailedReason indicates the microvmreplicaset failed to deleted cleanly. + MicrovmDeploymentDeleteFailedReason = "MicrovmDeploymentDeleteFailed" ) diff --git a/controllers/microvmdeployment_controller.go b/controllers/microvmdeployment_controller.go index f7b5590..d755d58 100644 --- a/controllers/microvmdeployment_controller.go +++ b/controllers/microvmdeployment_controller.go @@ -93,7 +93,60 @@ func (r *MicrovmDeploymentReconciler) reconcileDelete( ctx context.Context, mvmDeploymentScope *scope.MicrovmDeploymentScope, ) (reconcile.Result, error) { - return ctrl.Result{}, nil + mvmDeploymentScope.Info("Reconciling MicrovmReplicaSet delete") + + // get all owned microvmreplicasets + rsList, err := r.getOwnedReplicaSets(ctx, mvmDeploymentScope) + if err != nil { + mvmDeploymentScope.Error(err, "failed getting owned microvms") + return ctrl.Result{}, fmt.Errorf("failed to list microvms: %w", err) + } + + // if there are no owned sets left we are done, we can leave now + if len(rsList) == 0 { + controllerutil.RemoveFinalizer(mvmDeploymentScope.MicrovmDeployment, infrav1.MvmDeploymentFinalizer) + mvmDeploymentScope.Info("microvmreplicaset deleted", "name", mvmDeploymentScope.Name()) + + return ctrl.Result{}, nil + } + + // there are still some resources to clear + // + // set the object to not ready before we remove anything + mvmDeploymentScope.SetNotReady(infrav1.MicrovmDeploymentDeletingReason, "Info", "") + // just to be complete, mark all replicas as not ready too + mvmDeploymentScope.SetReadyReplicas(0) + + defer func() { + if err := mvmDeploymentScope.Patch(); err != nil { + mvmDeploymentScope.Error(err, "failed to patch microvmreplicaset") + } + }() + + var created int32 = 0 + + for _, rs := range rsList { + created += rs.Status.Replicas + + // if the object is already being deleted, skip this + if !rs.DeletionTimestamp.IsZero() { + continue + } + + // otherwise send a delete call + go func(rs infrav1.MicrovmReplicaSet) { + if err := r.Delete(ctx, &rs); err != nil { + mvmDeploymentScope.Error(err, "failed deleting microvmreplicaset", "set", rs.Name) + mvmDeploymentScope.SetNotReady(infrav1.MicrovmDeploymentDeleteFailedReason, "Error", "") + } + }(rs) + } + + // reset the number of still existing replicas, just so we know what is still there. + // we'll come back around to ensure they are really gone. + mvmDeploymentScope.SetCreatedReplicas(created) + + return ctrl.Result{RequeueAfter: requeuePeriod}, nil } func (r *MicrovmDeploymentReconciler) reconcileNormal( diff --git a/controllers/microvmdeployment_controller_test.go b/controllers/microvmdeployment_controller_test.go index 0d104d5..4a9032b 100644 --- a/controllers/microvmdeployment_controller_test.go +++ b/controllers/microvmdeployment_controller_test.go @@ -99,7 +99,7 @@ func TestMicrovmDep_ReconcileNormal_UpdateSucceeds(t *testing.T) { client := createFakeClient(g, objects) // create - g.Expect(reconcileMicrovmDeploymentNTimes(g, client, initialReplicaSetCount+4, expectedReplicas, expectedReplicas)).To(Succeed()) + g.Expect(reconcileMicrovmDeploymentNTimes(g, client, initialReplicaSetCount+1, expectedReplicas, expectedReplicas)).To(Succeed()) reconciled, err := getMicrovmDeployment(client, testMicrovmDeploymentName, testNamespace) g.Expect(err).NotTo(HaveOccurred(), "Getting microvm should not fail") @@ -142,3 +142,56 @@ func TestMicrovmDep_ReconcileNormal_UpdateSucceeds(t *testing.T) { g.Expect(reconciled.Status.ReadyReplicas).To(Equal(scaledReplicaCount), "Expected all replicas to be ready") g.Expect(microvmReplicaSetsCreated(g, client)).To(Equal(int(scaledReplicaSetCount)), "Expected replicasets to have been scaled down after two reconciliations") } + +func TestMicrovmDep_ReconcileDelete_DeleteSucceeds(t *testing.T) { + g := NewWithT(t) + + // updating a replicaset with 2 replicas + var ( + initialReplicaSetCount int = 2 + expectedReplicas int32 = 2 + initialReplicaCount int32 = 4 + ) + + mvmD := createMicrovmDeployment(expectedReplicas, initialReplicaSetCount) + objects := []runtime.Object{mvmD} + client := createFakeClient(g, objects) + + // create + g.Expect(reconcileMicrovmDeploymentNTimes(g, client, initialReplicaSetCount+1, expectedReplicas, expectedReplicas)).To(Succeed()) + + reconciled, err := getMicrovmDeployment(client, testMicrovmDeploymentName, testNamespace) + g.Expect(err).NotTo(HaveOccurred(), "Getting microvm should not fail") + + assertMDFinalizer(g, reconciled) + assertConditionTrue(g, reconciled, infrav1.MicrovmDeploymentReadyCondition) + g.Expect(reconciled.Status.Ready).To(BeTrue(), "MicrovmDeployment should be ready now") + g.Expect(reconciled.Status.Replicas).To(Equal(initialReplicaCount), "Expected the record to contain 4 replicas") + g.Expect(reconciled.Status.ReadyReplicas).To(Equal(initialReplicaCount), "Expected all replicas to be ready") + g.Expect(microvmReplicaSetsCreated(g, client)).To(Equal(initialReplicaSetCount), "Expected 2 replicasets to exist") + + // delete + g.Expect(client.Delete(context.TODO(), reconciled)).To(Succeed()) + + // first reconciliation + result, err := reconcileMicrovmDeployment(client) + g.Expect(err).NotTo(HaveOccurred(), "Reconciling microvmdeployment the first time should not error") + g.Expect(result.IsZero()).To(BeFalse(), "Expect requeue to be requested after update") + + reconciled, err = getMicrovmDeployment(client, testMicrovmDeploymentName, testNamespace) + g.Expect(err).NotTo(HaveOccurred(), "Getting microvmdeployment should not fail") + + assertConditionFalse(g, reconciled, infrav1.MicrovmDeploymentReadyCondition, infrav1.MicrovmDeploymentDeletingReason) + g.Expect(reconciled.Status.Ready).To(BeFalse(), "MicrovmDeployment should not be ready") + g.Expect(reconciled.Status.Replicas).To(Equal(initialReplicaCount), "Expected the record to contain 4 replicas") + g.Expect(reconciled.Status.ReadyReplicas).To(Equal(int32(0)), "Expected no replicas to be ready") + g.Expect(microvmReplicaSetsCreated(g, client)).To(Equal(0), "Expected all replicasets to have been deleted") + + // second reconciliation + result, err = reconcileMicrovmDeployment(client) + g.Expect(err).NotTo(HaveOccurred(), "Reconciling microvmdeployment the second time should not error") + g.Expect(result.IsZero()).To(BeTrue(), "Expect requeue to not be requested after reconcile") + + reconciled, err = getMicrovmDeployment(client, testMicrovmDeploymentName, testNamespace) + g.Expect(err).To(HaveOccurred(), "Getting microvmdeployment should fail") +} diff --git a/controllers/microvmreplicaset_controller_test.go b/controllers/microvmreplicaset_controller_test.go index ff935dc..473391a 100644 --- a/controllers/microvmreplicaset_controller_test.go +++ b/controllers/microvmreplicaset_controller_test.go @@ -170,7 +170,7 @@ func TestMicrovmRS_ReconcileDelete_DeleteSucceeds(t *testing.T) { // second reconciliation result, err = reconcileMicrovmReplicaSet(client) - g.Expect(err).NotTo(HaveOccurred(), "Reconciling microvmreplicaset the third time should not error") + g.Expect(err).NotTo(HaveOccurred(), "Reconciling microvmreplicaset the second time should not error") g.Expect(result.IsZero()).To(BeFalse(), "Expect requeue to be requested after reconcile") reconciled, err = getMicrovmReplicaSet(client, testMicrovmReplicaSetName, testNamespace) @@ -188,5 +188,5 @@ func TestMicrovmRS_ReconcileDelete_DeleteSucceeds(t *testing.T) { g.Expect(result.IsZero()).To(BeTrue(), "Expect requeue to not be requested after reconcile") reconciled, err = getMicrovmReplicaSet(client, testMicrovmReplicaSetName, testNamespace) - g.Expect(err).To(HaveOccurred(), "Getting microvm not fail") + g.Expect(err).To(HaveOccurred(), "Getting microvmreplicaset should fail") }