diff --git a/Makefile b/Makefile index 3e3bf35..245b8b7 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OPERATOR_SDK_VERSION ?= v1.25.4 # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) VERSION ?= 0.3.0 -RDS_VERSION ?= 0.1.3 +RDS_VERSION ?= 1.0.0 # QUAY_ORG indicates the organization that docker images will be build for & pushed to # CHANGE THIS TO YOUR OWN QUAY USERNAME FOR DEV/TESTING/PUSHING @@ -277,7 +277,7 @@ RDS_TEMP = ./controllers/yaml/temp RDS_CONFIG = ./controllers/yaml/rds rds-crds-clean: ## Cleanup the RDS CRD files. find $(RDS_CONFIG) -type f -delete - rm $(RDS_TEMP)/v$(RDS_VERSION).zip + rm $(RDS_TEMP)/* .PHONY: sdk SDK = ./bin/operator-sdk.$(OPERATOR_SDK_VERSION) diff --git a/bundle/manifests/rds-dbaas-operator.clusterserviceversion.yaml b/bundle/manifests/rds-dbaas-operator.clusterserviceversion.yaml index 7a89a69..35411c8 100644 --- a/bundle/manifests/rds-dbaas-operator.clusterserviceversion.yaml +++ b/bundle/manifests/rds-dbaas-operator.clusterserviceversion.yaml @@ -234,6 +234,7 @@ spec: resources: - dbclusters verbs: + - delete - get - list - update diff --git a/bundle/metadata/dependencies.yaml b/bundle/metadata/dependencies.yaml index 575affe..9333aa9 100644 --- a/bundle/metadata/dependencies.yaml +++ b/bundle/metadata/dependencies.yaml @@ -2,4 +2,4 @@ dependencies: - type: olm.package value: packageName: ack-rds-controller - version: ">=0.0.27 <=0.1.3" + version: "1.0.0" diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 6649b70..5cbffb7 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -142,6 +142,7 @@ rules: resources: - dbclusters verbs: + - delete - get - list - update diff --git a/controllers/rds/test/dbcluster_mock.go b/controllers/rds/test/dbcluster_mock.go index 09c9e66..17ab253 100644 --- a/controllers/rds/test/dbcluster_mock.go +++ b/controllers/rds/test/dbcluster_mock.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "strings" + "sync/atomic" "k8s.io/utils/pointer" @@ -29,6 +30,16 @@ import ( controllersrds "github.com/RHEcosystemAppEng/rds-dbaas-operator/controllers/rds" ) +var inventoryTestDBClusterCounter int32 = 6 + +func GetInventoryTestDBClusterCounter() int32 { + return atomic.LoadInt32(&inventoryTestDBClusterCounter) +} + +func SetInventoryTestDBClusterCounter(counter int32) { + atomic.StoreInt32(&inventoryTestDBClusterCounter, counter) +} + var inventoryTestDBClusters = []*rds.DescribeDBClustersOutput{ { DBClusters: []types.DBCluster{ @@ -222,6 +233,17 @@ var inventoryTestDBClusters = []*rds.DescribeDBClustersOutput{ }, }, }, + { + // To be deleted + DBClusters: []types.DBCluster{ + { + DBClusterIdentifier: pointer.String("mock-db-cluster-delete-1"), + Status: pointer.String("available"), + Engine: pointer.String("postgres"), + DBClusterArn: pointer.String("mock-db-cluster-delete-1"), + }, + }, + }, } var connectionTestDBClusters = []*rds.DescribeDBClustersOutput{ @@ -250,7 +272,7 @@ type mockDescribeDBClustersPaginator struct { func NewDescribeDBClustersPaginator(accessKey, secretKey, region string) controllersrds.DescribeDBClustersPaginatorAPI { counter := 0 if strings.HasSuffix(accessKey, ClusterInventoryControllerTestAccessKeySuffix) { - counter = 5 + counter = int(GetInventoryTestDBClusterCounter()) } else if strings.HasSuffix(accessKey, ClusterConnectionControllerTestAccessKeySuffix) { counter = 1 } diff --git a/controllers/rds/test/dbinstance_mock.go b/controllers/rds/test/dbinstance_mock.go index f6474a9..4891364 100644 --- a/controllers/rds/test/dbinstance_mock.go +++ b/controllers/rds/test/dbinstance_mock.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "strings" + "sync/atomic" "k8s.io/utils/pointer" @@ -28,6 +29,16 @@ import ( "github.com/aws/aws-sdk-go-v2/service/rds/types" ) +var inventoryTestDBInstanceCounter int32 = 6 + +func GetInventoryTestDBInstanceCounter() int32 { + return atomic.LoadInt32(&inventoryTestDBInstanceCounter) +} + +func SetInventoryTestDBInstanceCounter(counter int32) { + atomic.StoreInt32(&inventoryTestDBInstanceCounter, counter) +} + var inventoryTestDBInstances = []*rds.DescribeDBInstancesOutput{ { DBInstances: []types.DBInstance{ @@ -199,6 +210,17 @@ var inventoryTestDBInstances = []*rds.DescribeDBInstancesOutput{ }, }, }, + { + // To be deleted + DBInstances: []types.DBInstance{ + { + DBInstanceIdentifier: pointer.String("mock-db-instance-delete-1"), + DBInstanceStatus: pointer.String("available"), + Engine: pointer.String("postgres"), + DBInstanceArn: pointer.String("mock-db-instance-delete-1"), + }, + }, + }, } var connectionTestDBInstances = []*rds.DescribeDBInstancesOutput{ @@ -240,7 +262,7 @@ type mockDescribeDBInstancesPaginator struct { func NewDescribeDBInstancesPaginator(accessKey, secretKey, region string) controllersrds.DescribeDBInstancesPaginatorAPI { counter := 0 if strings.HasSuffix(accessKey, InventoryControllerTestAccessKeySuffix) { - counter = 5 + counter = int(GetInventoryTestDBInstanceCounter()) } else if strings.HasSuffix(accessKey, ConnectionControllerTestAccessKeySuffix) { counter = 1 } diff --git a/controllers/rdsinventory_controller.go b/controllers/rdsinventory_controller.go index 3e85144..f461acb 100644 --- a/controllers/rdsinventory_controller.go +++ b/controllers/rdsinventory_controller.go @@ -83,6 +83,8 @@ const ( inventoryStatusMessageUpdateError = "Failed to update Inventory" inventoryStatusMessageGetInstancesError = "Failed to get Instances" inventoryStatusMessageGetClustersError = "Failed to get clusters" + inventoryStatusMessageDeleteInstancesError = "Failed to delete Instances" + inventoryStatusMessageDeleteClustersError = "Failed to delete clusters" inventoryStatusMessageAdoptInstanceError = "Failed to adopt DB Instance" inventoryStatusMessageAdoptClusterError = "Failed to adopt DB Cluster" inventoryStatusMessageUpdateInstanceError = "Failed to update DB Instance" @@ -124,9 +126,9 @@ type RDSInventoryReconciler struct { //+kubebuilder:rbac:groups=dbaas.redhat.com,resources=rdsinventories,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=dbaas.redhat.com,resources=rdsinventories/status,verbs=get;update;patch //+kubebuilder:rbac:groups=dbaas.redhat.com,resources=rdsinventories/finalizers,verbs=update -//+kubebuilder:rbac:groups=rds.services.k8s.aws,resources=dbinstances,verbs=get;list;watch;update +//+kubebuilder:rbac:groups=rds.services.k8s.aws,resources=dbinstances,verbs=get;list;watch;update;delete //+kubebuilder:rbac:groups=rds.services.k8s.aws,resources=dbinstances/finalizers,verbs=update -//+kubebuilder:rbac:groups=rds.services.k8s.aws,resources=dbclusters,verbs=get;list;watch;update +//+kubebuilder:rbac:groups=rds.services.k8s.aws,resources=dbclusters,verbs=get;list;watch;update;delete //+kubebuilder:rbac:groups=rds.services.k8s.aws,resources=dbclusters/finalizers,verbs=update //+kubebuilder:rbac:groups=services.k8s.aws,resources=adoptedresources,verbs=get;list;watch;create;delete;update //+kubebuilder:rbac:groups="",resources=secrets;configmaps,verbs=get;list;watch;create;delete;update @@ -503,6 +505,21 @@ func (r *RDSInventoryReconciler) Reconcile(ctx context.Context, req ctrl.Request returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageGetInstancesError) return true, false } + + adoptedResourceList := &ackv1alpha1.AdoptedResourceList{} + if e := r.List(ctx, adoptedResourceList, client.InNamespace(inventory.Namespace), + client.MatchingLabels(map[string]string{adoptedDBResourceLabelKey: adoptedDBResourceLabelValue})); e != nil { + logger.Error(e, "Failed to read adopted Resources of the Inventory that are created by the operator") + returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageGetInstancesError) + return true, false + } + adoptedDBInstanceMap := make(map[string]ackv1alpha1.AdoptedResource, len(adoptedResourceList.Items)) + for _, adoptedDBInstance := range adoptedResourceList.Items { + if adoptedDBInstance.Spec.AWS != nil && adoptedDBInstance.Spec.AWS.ARN != nil { + adoptedDBInstanceMap[string(*adoptedDBInstance.Spec.AWS.ARN)] = adoptedDBInstance + } + } + modifyDBInstance := r.GetModifyDBInstanceAPI(accessKey, secretKey, region) waitForAdoptedResource := false for i := range adoptedDBInstanceList.Items { @@ -527,6 +544,23 @@ func (r *RDSInventoryReconciler) Reconcile(ctx context.Context, req ctrl.Request } awsDBInstance, awsOk := awsDBInstanceMap[string(*adoptedDBInstance.Status.ACKResourceMetadata.ARN)] if !awsOk { + if e := r.Delete(ctx, &adoptedDBInstance); e != nil { + if !errors.IsNotFound(e) { + logger.Error(e, "Failed to delete obsolete adopted DB Instance", "DB Instance", adoptedDBInstance) + returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageDeleteInstancesError) + return true, false + } + } + if instance, ok := adoptedDBInstanceMap[string(*adoptedDBInstance.Status.ACKResourceMetadata.ARN)]; ok { + if e := r.Delete(ctx, &instance); e != nil { + if !errors.IsNotFound(e) { + logger.Error(e, "Failed to delete adopting resource", "DB Instance", adoptedDBInstance) + returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageDeleteInstancesError) + return true, false + } + } + } + logger.Info("Deleted adopted DB Instance that is obsolete", "DB Cluster", adoptedDBInstance) continue } @@ -730,6 +764,21 @@ func (r *RDSInventoryReconciler) Reconcile(ctx context.Context, req ctrl.Request returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageGetClustersError) return true, false } + + adoptedResourceList := &ackv1alpha1.AdoptedResourceList{} + if e := r.List(ctx, adoptedResourceList, client.InNamespace(inventory.Namespace), + client.MatchingLabels(map[string]string{adoptedDBResourceLabelKey: adoptedDBResourceLabelValue})); e != nil { + logger.Error(e, "Failed to read adopted Resources of the Inventory that are created by the operator") + returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageGetClustersError) + return true, false + } + adoptedDBClusterMap := make(map[string]ackv1alpha1.AdoptedResource, len(adoptedResourceList.Items)) + for _, adoptedDBCluster := range adoptedResourceList.Items { + if adoptedDBCluster.Spec.AWS != nil && adoptedDBCluster.Spec.AWS.ARN != nil { + adoptedDBClusterMap[string(*adoptedDBCluster.Spec.AWS.ARN)] = adoptedDBCluster + } + } + modifyDBCluster := r.GetModifyDBClusterAPI(accessKey, secretKey, region) waitForAdoptedResource := false for i := range adoptedDBClusterList.Items { @@ -752,6 +801,23 @@ func (r *RDSInventoryReconciler) Reconcile(ctx context.Context, req ctrl.Request } awsDBCluster, awsOk := awsDBClusterMap[string(*adoptedDBCluster.Status.ACKResourceMetadata.ARN)] if !awsOk { + if e := r.Delete(ctx, &adoptedDBCluster); e != nil { + if !errors.IsNotFound(e) { + logger.Error(e, "Failed to delete obsolete adopted DB Cluster", "DB Cluster", adoptedDBCluster) + returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageDeleteClustersError) + return true, false + } + } + if cluster, ok := adoptedDBClusterMap[string(*adoptedDBCluster.Status.ACKResourceMetadata.ARN)]; ok { + if e := r.Delete(ctx, &cluster); e != nil { + if !errors.IsNotFound(e) { + logger.Error(e, "Failed to delete adopting resource", "DB Cluster", adoptedDBCluster) + returnError(e, inventoryStatusReasonBackendError, inventoryStatusMessageDeleteClustersError) + return true, false + } + } + } + logger.Info("Deleted adopted DB Cluster that is obsolete", "DB Cluster", adoptedDBCluster) continue } @@ -1199,6 +1265,9 @@ func createAdoptedResource(resourceIdentifier *string, resourceArn *string, engi "owner.kind": inventory.Kind, "owner.namespace": inventory.Namespace, }, + Labels: map[string]string{ + adoptedDBResourceLabelKey: adoptedDBResourceLabelValue, + }, }, Spec: ackv1alpha1.AdoptedResourceSpec{ Kubernetes: &ackv1alpha1.ResourceWithMetadata{ diff --git a/controllers/rdsinventory_controller_test.go b/controllers/rdsinventory_controller_test.go index 5b54c64..8cbd543 100644 --- a/controllers/rdsinventory_controller_test.go +++ b/controllers/rdsinventory_controller_test.go @@ -600,7 +600,7 @@ var _ = Describe("RDSInventoryController", func() { }, } BeforeEach(assertResourceCreation(dbInstance14)) - AfterEach(assertResourceDeletion(dbInstance14)) + AfterEach(assertResourceDeletionIfExist(dbInstance14)) BeforeEach(func() { Eventually(func() bool { if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbInstance14), dbInstance14); err != nil { @@ -636,7 +636,7 @@ var _ = Describe("RDSInventoryController", func() { }, } BeforeEach(assertResourceCreation(dbInstance15)) - AfterEach(assertResourceDeletion(dbInstance15)) + AfterEach(assertResourceDeletionIfExist(dbInstance15)) BeforeEach(func() { Eventually(func() bool { if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbInstance15), dbInstance15); err != nil { @@ -1314,7 +1314,7 @@ var _ = Describe("RDSInventoryController", func() { }, } BeforeEach(assertResourceCreation(dbCluster19)) - AfterEach(assertResourceDeletion(dbCluster19)) + AfterEach(assertResourceDeletionIfExist(dbCluster19)) BeforeEach(func() { Eventually(func() bool { if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbCluster19), dbCluster19); err != nil { @@ -1350,7 +1350,7 @@ var _ = Describe("RDSInventoryController", func() { }, } BeforeEach(assertResourceCreation(dbCluster20)) - AfterEach(assertResourceDeletion(dbCluster20)) + AfterEach(assertResourceDeletionIfExist(dbCluster20)) BeforeEach(func() { Eventually(func() bool { if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbCluster20), dbCluster20); err != nil { @@ -2611,7 +2611,7 @@ var _ = Describe("RDSInventoryController", func() { return true }, timeout).Should(BeTrue()) - By("checking if the username and password of adopted db instance is not reset when the instance not exist in AWS") + By("checking if the adopted db instance is deleted when the instance not exist in AWS") dbInstance14 := &rdsv1alpha1.DBInstance{ ObjectMeta: metav1.ObjectMeta{ Name: "db-instance-inventory-controller-14", @@ -2625,20 +2625,10 @@ var _ = Describe("RDSInventoryController", func() { }, } Consistently(func() bool { - if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbInstance14), dbInstance14); err != nil { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbInstance14), dbInstance14); err == nil || !errors.IsNotFound(err) { return false } - if dbInstance14.Spec.DBName != nil { - return false - } - if dbInstance14.Spec.MasterUsername != nil { - return false - } - if dbInstance14.Spec.MasterUserPassword != nil { - return false - } - err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbSecret14), dbSecret14) - if err == nil || !errors.IsNotFound(err) { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbSecret14), dbSecret14); err == nil || !errors.IsNotFound(err) { return false } return true @@ -2657,20 +2647,10 @@ var _ = Describe("RDSInventoryController", func() { }, } Consistently(func() bool { - if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbInstance15), dbInstance15); err != nil { - return false - } - if dbInstance15.Spec.DBName != nil { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbInstance15), dbInstance15); err == nil || !errors.IsNotFound(err) { return false } - if dbInstance15.Spec.MasterUsername != nil { - return false - } - if dbInstance15.Spec.MasterUserPassword != nil { - return false - } - err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbSecret15), dbSecret15) - if err == nil || !errors.IsNotFound(err) { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbSecret15), dbSecret15); err == nil || !errors.IsNotFound(err) { return false } return true @@ -3043,7 +3023,7 @@ var _ = Describe("RDSInventoryController", func() { return true }, timeout).Should(BeTrue()) - By("checking if the username and password of adopted db cluster is not reset when the cluster not exist in AWS") + By("checking if the adopted db cluster is deleted when the cluster not exist in AWS") dbCluster19 := &rdsv1alpha1.DBCluster{ ObjectMeta: metav1.ObjectMeta{ Name: "db-cluster-inventory-controller-19", @@ -3057,20 +3037,10 @@ var _ = Describe("RDSInventoryController", func() { }, } Consistently(func() bool { - if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbCluster19), dbCluster19); err != nil { - return false - } - if dbCluster19.Spec.DatabaseName != nil { - return false - } - if dbCluster19.Spec.MasterUsername != nil { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbCluster19), dbCluster19); err == nil || !errors.IsNotFound(err) { return false } - if dbCluster19.Spec.MasterUserPassword != nil { - return false - } - err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbcSecret19), dbcSecret19) - if err == nil || !errors.IsNotFound(err) { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbcSecret19), dbcSecret19); err == nil || !errors.IsNotFound(err) { return false } return true @@ -3089,20 +3059,10 @@ var _ = Describe("RDSInventoryController", func() { }, } Consistently(func() bool { - if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbCluster20), dbCluster20); err != nil { - return false - } - if dbCluster20.Spec.DatabaseName != nil { - return false - } - if dbCluster20.Spec.MasterUsername != nil { - return false - } - if dbCluster20.Spec.MasterUserPassword != nil { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbCluster20), dbCluster20); err == nil || !errors.IsNotFound(err) { return false } - err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbcSecret20), dbcSecret20) - if err == nil || !errors.IsNotFound(err) { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dbcSecret20), dbcSecret20); err == nil || !errors.IsNotFound(err) { return false } return true @@ -3526,6 +3486,221 @@ var _ = Describe("RDSInventoryController", func() { }, timeout).Should(BeTrue()) }) + Context("when instances and clusters are deleted from AWS", func() { + mockDeleteDBInstance1 := &rdsv1alpha1.DBInstance{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rhoda-adopted-postgres-mock-db-instance-delete-1", + Namespace: testNamespace, + Labels: map[string]string{ + "rds.dbaas.redhat.com/adopted": "true", + }, + }, + Spec: rdsv1alpha1.DBInstanceSpec{ + Engine: pointer.String("postgres"), + DBInstanceIdentifier: pointer.String("mock-db-instance-delete-1"), + DBInstanceClass: pointer.String("db.t3.micro"), + }, + } + AfterEach(assertResourceDeletionIfExist(mockDeleteDBInstance1)) + + mockDeleteDBCluster1 := &rdsv1alpha1.DBCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rhoda-adopted-postgres-mock-db-cluster-delete-1", + Namespace: testNamespace, + Labels: map[string]string{ + "rds.dbaas.redhat.com/adopted": "true", + }, + }, + Spec: rdsv1alpha1.DBClusterSpec{ + Engine: pointer.String("postgres"), + DBClusterIdentifier: pointer.String("mock-db-cluster-delete-1"), + DBClusterInstanceClass: pointer.String("db.t3.micro"), + }, + } + AfterEach(assertResourceDeletionIfExist(mockDeleteDBCluster1)) + + It("should delete adopted resource when the resource is deleted from AWS", func() { + By("checking if the resources are adopted") + Eventually(func() bool { + adoptedDBResources := &ackv1alpha1.AdoptedResourceList{} + if err := k8sClient.List(ctx, adoptedDBResources, client.InNamespace(testNamespace)); err != nil { + return false + } + + dbResourcesMap := map[string]ackv1alpha1.AdoptedResource{} + for i := range adoptedDBResources.Items { + resource := adoptedDBResources.Items[i] + dbResourcesMap[resource.Spec.AWS.NameOrID] = resource + } + + if _, ok := dbResourcesMap["mock-db-instance-1"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-instance-2"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-instance-3"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-instance-4"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-instance-7"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-instance-8"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-adopted-db-instance-15"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-instance-delete-1"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-1"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-2"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-3"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-4"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-7"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-8"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-adopted-db-cluster-20"]; !ok { + return false + } + if _, ok := dbResourcesMap["mock-db-cluster-delete-1"]; !ok { + return false + } + + for i := range adoptedDBResources.Items { + resource := adoptedDBResources.Items[i] + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&resource), &resource); err != nil { + return false + } + resource.Status.Conditions = []*ackv1alpha1.Condition{ + { + Type: ackv1alpha1.ConditionTypeAdopted, + Status: v1.ConditionTrue, + }, + } + if err := k8sClient.Status().Update(ctx, &resource); err != nil { + return false + } + } + return true + }, timeout).Should(BeTrue()) + + assertResourceCreation(mockDeleteDBInstance1)() + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(mockDeleteDBInstance1), mockDeleteDBInstance1); err != nil { + return false + } + arn := ackv1alpha1.AWSResourceName("mock-db-instance-delete-1") + ownerAccountID := ackv1alpha1.AWSAccountID("testOwnerId") + region := ackv1alpha1.AWSRegion("us-east-1") + mockDeleteDBInstance1.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{ + ARN: &arn, + OwnerAccountID: &ownerAccountID, + Region: ®ion, + } + if err := k8sClient.Status().Update(ctx, mockDeleteDBInstance1); err != nil { + return false + } + return true + }, timeout).Should(BeTrue()) + + assertResourceCreation(mockDeleteDBCluster1)() + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(mockDeleteDBCluster1), mockDeleteDBCluster1); err != nil { + return false + } + arn := ackv1alpha1.AWSResourceName("mock-db-cluster-delete-1") + ownerAccountID := ackv1alpha1.AWSAccountID("testOwnerId") + region := ackv1alpha1.AWSRegion("us-east-1") + mockDeleteDBCluster1.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{ + ARN: &arn, + OwnerAccountID: &ownerAccountID, + Region: ®ion, + } + if err := k8sClient.Status().Update(ctx, mockDeleteDBCluster1); err != nil { + return false + } + return true + }, timeout).Should(BeTrue()) + + test.SetInventoryTestDBInstanceCounter(5) + test.SetInventoryTestDBClusterCounter(5) + + inv := &rdsdbaasv1alpha1.RDSInventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: inventoryName, + Namespace: testNamespace, + }, + } + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(inv), inv); err != nil { + return false + } + condition := apimeta.FindStatusCondition(inv.Status.Conditions, "SpecSynced") + if condition == nil || condition.Status != metav1.ConditionTrue || condition.Reason != "SyncOK" { + return false + } + return true + }, timeout).Should(BeTrue()) + + Eventually(func() bool { + By("checking if the adopted resources are deleted") + adoptedDBResources := &ackv1alpha1.AdoptedResourceList{} + if err := k8sClient.List(ctx, adoptedDBResources, client.InNamespace(testNamespace)); err != nil { + return false + } + for i := range adoptedDBResources.Items { + db := adoptedDBResources.Items[i] + if db.Spec.AWS.NameOrID == "mock-db-instance-delete-1" { + return false + } + if db.Spec.AWS.NameOrID == "mock-db-cluster-delete-1" { + return false + } + } + + adoptedDBInstances := &rdsv1alpha1.DBInstanceList{} + if err := k8sClient.List(ctx, adoptedDBInstances, client.InNamespace(testNamespace)); err != nil { + return false + } + for i := range adoptedDBInstances.Items { + db := adoptedDBInstances.Items[i] + if db.Spec.DBInstanceIdentifier != nil && *db.Spec.DBInstanceIdentifier == "mock-db-instance-delete-1" { + return false + } + } + + adoptedDBClusters := &rdsv1alpha1.DBClusterList{} + if err := k8sClient.List(ctx, adoptedDBClusters, client.InNamespace(testNamespace)); err != nil { + return false + } + for i := range adoptedDBClusters.Items { + db := adoptedDBClusters.Items[i] + if db.Spec.DBClusterIdentifier != nil && *db.Spec.DBClusterIdentifier == "mock-db-cluster-delete-1" { + return false + } + } + + return true + }, timeout).Should(BeTrue()) + }) + }) + Context("when is ACK controller is scaled down", func() { It("should scale the ACK controller up", func() { deployment := &appsv1.Deployment{ diff --git a/go.mod b/go.mod index 7147c57..ad5ca34 100644 --- a/go.mod +++ b/go.mod @@ -74,11 +74,11 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect - golang.org/x/net v0.2.0 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sys v0.2.0 // indirect - golang.org/x/term v0.2.0 // indirect - golang.org/x/text v0.4.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 2a1a52f..d6ed0d7 100644 --- a/go.sum +++ b/go.sum @@ -491,8 +491,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -583,12 +583,12 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -598,8 +598,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=