From a67ab8d57a265029eed61062f8151cb98f68e131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Golicz?= Date: Thu, 1 Aug 2024 23:40:02 +0200 Subject: [PATCH] Extending integration tests for processing of deleting of Runtime CR and delete GardenerCluster CR and Shoot --- .../fsm/runtime_fsm_create_kubeconfig_test.go | 3 +- .../runtime/runtime_controller_test.go | 69 +++++++++++++++---- internal/controller/runtime/suite_test.go | 51 ++++++++++---- .../runtime/test_client_obj_tracker.go | 16 +++++ 4 files changed, 112 insertions(+), 27 deletions(-) diff --git a/internal/controller/runtime/fsm/runtime_fsm_create_kubeconfig_test.go b/internal/controller/runtime/fsm/runtime_fsm_create_kubeconfig_test.go index b62a0edb..3f167ca5 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_create_kubeconfig_test.go +++ b/internal/controller/runtime/fsm/runtime_fsm_create_kubeconfig_test.go @@ -3,6 +3,7 @@ package fsm import ( "context" "fmt" + "k8s.io/utils/ptr" "time" gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" @@ -57,7 +58,7 @@ var _ = Describe("KIM sFnCreateKubeconfig", func() { }, Spec: gardener.ShootSpec{ DNS: &gardener.DNS{ - Domain: ptrTo("test-domain"), + Domain: ptr.To("test-domain"), }, }, } diff --git a/internal/controller/runtime/runtime_controller_test.go b/internal/controller/runtime/runtime_controller_test.go index 8bcee559..4015ee45 100644 --- a/internal/controller/runtime/runtime_controller_test.go +++ b/internal/controller/runtime/runtime_controller_test.go @@ -18,6 +18,7 @@ package runtime import ( "context" + k8serrors "k8s.io/apimachinery/pkg/api/errors" "time" gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" @@ -40,16 +41,7 @@ var _ = Describe("Runtime Controller", func() { Namespace: "default", } - AfterEach(func() { - resource := &imv1.Runtime{} - err := k8sClient.Get(ctx, typeNamespacedName, resource) - Expect(err).NotTo(HaveOccurred()) - - }) - It("Should successfully create new Shoot from provided Runtime and set Ready status on CR", func() { - - By("Setup the fake gardener client for Provisioning") setupGardenerTestClientForProvisioning() By("Create Runtime CR") @@ -101,6 +93,7 @@ var _ = Describe("Runtime Controller", func() { return false } + // the second controller normally should do that if gardenCluster.Status.State != imv1.ReadyState { gardenCluster.Status.State = imv1.ReadyState k8sClient.Status().Update(ctx, &gardenCluster) @@ -173,9 +166,61 @@ var _ = Describe("Runtime Controller", func() { Expect(customTracker.IsSequenceFullyUsed()).To(BeTrue()) // next test will be for runtime deletion - // - // By("Delete Runtime CR") - // Expect(k8sClient.Delete(ctx, &runtime)).To(Succeed()) + + By("Process deleting of Runtime CR and delete GardenerCluster CR and Shoot") + setupGardenerTestClientForDelete() + + Expect(k8sClient.Delete(ctx, &runtime)).To(Succeed()) + + // should delete GardenerCluster CR and go into RuntimeStateTerminating state with condition GardenerClusterCRDeleted + Eventually(func() bool { + runtime := imv1.Runtime{} + if err := k8sClient.Get(ctx, typeNamespacedName, &runtime); err != nil { + return false + } + + // check if GardenerCluster CR is deleted + gardenCluster := imv1.GardenerCluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: runtime.Labels[imv1.LabelKymaRuntimeID], Namespace: runtime.Namespace}, &gardenCluster) + if err == nil || !k8serrors.IsNotFound(err) { + return false + } + + // check runtime state + if runtime.Status.State != imv1.RuntimeStateTerminating { + return false + } + + if !runtime.IsConditionSet(imv1.ConditionTypeRuntimeDeprovisioned, imv1.ConditionReasonGardenerCRDeleted) { + return false + } + + return true + }, time.Second*300, time.Second*3).Should(BeTrue()) + + // should delete Shoot and go into RuntimeStateTerminating state with condition GardenerClusterCRDeleted + Eventually(func() bool { + runtime := imv1.Runtime{} + if err := k8sClient.Get(ctx, typeNamespacedName, &runtime); err != nil { + return false + } + + if !runtime.IsConditionSet(imv1.ConditionTypeRuntimeDeprovisioned, imv1.ConditionReasonGardenerShootDeleted) { + return false + } + return true + }, time.Second*300, time.Second*3).Should(BeTrue()) + + // Make sure the instance is finally deleted + Eventually(func() bool { + runtime := imv1.Runtime{} + if err := k8sClient.Get(ctx, typeNamespacedName, &runtime); err == nil { + return false + } + return true + }, time.Second*300, time.Second*3).Should(BeTrue()) + + Expect(customTracker.IsSequenceFullyUsed()).To(BeTrue()) }) }) }) diff --git a/internal/controller/runtime/suite_test.go b/internal/controller/runtime/suite_test.go index 0536bfac..9a4d9658 100644 --- a/internal/controller/runtime/suite_test.go +++ b/internal/controller/runtime/suite_test.go @@ -18,8 +18,10 @@ package runtime import ( "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "path/filepath" "testing" + "time" gardener_api "github.com/gardener/gardener/pkg/apis/core/v1beta1" infrastructuremanagerv1 "github.com/kyma-project/infrastructure-manager/api/v1" @@ -137,6 +139,12 @@ func setupGardenerTestClientForUpdate() { setupShootClientWithSequence(shoots) } +func setupGardenerTestClientForDelete() { + baseShoot := getBaseShootForTestingSequence() + shoots := fixShootsSequenceForDelete(&baseShoot) + setupShootClientWithSequence(shoots) +} + func setupShootClientWithSequence(shoots []*gardener_api.Shoot) { clientScheme := runtime.NewScheme() _ = gardener_api.AddToScheme(clientScheme) @@ -159,20 +167,6 @@ func getBaseShootForTestingSequence() gardener_api.Shoot { return convertedShoot } -// func setupGardenerTestClientForDeleting() { -// runtimeStub := CreateRuntimeStub("test-resource") -// converterConfig := fixConverterConfigForTests() -// converter := gardener_shoot.NewConverter(converterConfig) -// convertedShoot, err := converter.ToShoot(*runtimeStub) -// if err != nil { -// panic(err) -// } -// -// shoots := fixGardenerShootsForProvisioning(&convertedShoot) -// -// objectTestTracker.SetShootListForTracker(shoots) -//} - func fixShootsSequenceForProvisioning(shoot *gardener_api.Shoot) []*gardener_api.Shoot { var missingShoot *gardener_api.Shoot initialisedShoot := shoot.DeepCopy() @@ -232,6 +226,35 @@ func fixShootsSequenceForUpdate(shoot *gardener_api.Shoot) []*gardener_api.Shoot return []*gardener_api.Shoot{pendingShoot, processingShoot, readyShoot, readyShoot} } +func fixShootsSequenceForDelete(shoot *gardener_api.Shoot) []*gardener_api.Shoot { + currentShoot := shoot.DeepCopy() + + currentShoot.Spec.DNS = &gardener_api.DNS{ + Domain: ptr.To("test.domain"), + } + + // To workaround limitation that apply patches are not supported in the fake client. + // We need to set the annotation manually. https://github.com/kubernetes/kubernetes/issues/115598 + currentShoot.Annotations = map[string]string{ + "confirmation.gardener.cloud/deletion": "true", + } + + currentShoot.Status = gardener_api.ShootStatus{ + LastOperation: &gardener_api.LastOperation{ + Type: gardener_api.LastOperationTypeCreate, + State: gardener_api.LastOperationStateSucceeded, + }, + } + + pendingDeleteShoot := currentShoot.DeepCopy() + + pendingDeleteShoot.SetDeletionTimestamp(&metav1.Time{Time: time.Now()}) + pendingDeleteShoot.Status.LastOperation.Type = gardener_api.LastOperationTypeDelete + pendingDeleteShoot.Status.LastOperation.State = gardener_api.LastOperationStatePending + + return []*gardener_api.Shoot{currentShoot, currentShoot, currentShoot, pendingDeleteShoot, nil} +} + func fixConverterConfigForTests() gardener_shoot.ConverterConfig { return gardener_shoot.ConverterConfig{ Kubernetes: gardener_shoot.KubernetesConfig{ diff --git a/internal/controller/runtime/test_client_obj_tracker.go b/internal/controller/runtime/test_client_obj_tracker.go index 9c2115ab..65e8c6ba 100644 --- a/internal/controller/runtime/test_client_obj_tracker.go +++ b/internal/controller/runtime/test_client_obj_tracker.go @@ -53,3 +53,19 @@ func (t *CustomTracker) Get(gvr schema.GroupVersionResource, ns, name string) (r } return t.ObjectTracker.Get(gvr, ns, name) } + +func (t *CustomTracker) Delete(gvr schema.GroupVersionResource, ns, name string) error { + t.mu.Lock() + defer t.mu.Unlock() + + if gvr.Resource == "shoots" { + for index, shoot := range t.shootSequence { + if shoot != nil && shoot.Name == name { + t.shootSequence[index] = nil + return nil + } + } + return k8serrors.NewNotFound(schema.GroupResource{}, "") + } + return t.ObjectTracker.Delete(gvr, ns, name) +}