From 76a0905b9c7b8f0783d284461979da304adb6f5a Mon Sep 17 00:00:00 2001 From: Igor Karpukhin Date: Tue, 28 Nov 2023 17:01:33 +0100 Subject: [PATCH 1/3] Disable deletion protection from Backups --- pkg/controller/atlasdeployment/backup.go | 10 ---------- test/int/backup_protected_test.go | 8 ++------ 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/pkg/controller/atlasdeployment/backup.go b/pkg/controller/atlasdeployment/backup.go index 901fad363a..4f7da1c88a 100644 --- a/pkg/controller/atlasdeployment/backup.go +++ b/pkg/controller/atlasdeployment/backup.go @@ -29,8 +29,6 @@ import ( var errArgIsNotBackupSchedule = errors.New("failed to match resource type as AtlasBackupSchedule") -const BackupProtected = "unable to reconcile AtlasBackupSchedule due to deletion protection being enabled. see https://dochub.mongodb.org/core/ako-deletion-protection for further information" - func (r *AtlasDeploymentReconciler) ensureBackupScheduleAndPolicy( service *workflow.Context, projectID string, @@ -243,14 +241,6 @@ func (r *AtlasDeploymentReconciler) updateBackupScheduleAndPolicy( r.Log.Debugf("successfully received backup configuration: %v", currentSchedule) - owner, err := customresource.IsOwner(bSchedule, r.ObjectDeletionProtection, customresource.IsResourceManagedByOperator, backupScheduleManagedByAtlas(ctx, service.Client, projectID, deployment, bPolicy)) - if err != nil { - return err - } - - if !owner { - return fmt.Errorf(BackupProtected) - } r.Log.Debugf("updating backup configuration for the atlas deployment: %v", clusterName) apiScheduleReq := bSchedule.ToAtlas(currentSchedule.ClusterID, clusterName, deployment.GetReplicationSetID(), bPolicy) diff --git a/test/int/backup_protected_test.go b/test/int/backup_protected_test.go index 95354cc291..62e5d79dd6 100644 --- a/test/int/backup_protected_test.go +++ b/test/int/backup_protected_test.go @@ -9,9 +9,7 @@ import ( "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/project" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/status" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasdeployment" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/customresource" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/util/kube" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/util/testutil" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/util/toptr" @@ -174,14 +172,12 @@ var _ = Describe("AtlasBackupSchedule Deletion Protected", }).WithTimeout(2 * time.Minute).WithPolling(20 * time.Second).Should(Succeed()) }) - By("Deployment should NOT be Ready", func() { + By("Deployment should be Ready", func() { Eventually(func(g Gomega) bool { return testutil.CheckCondition( k8sClient, testDeployment, - status.FalseCondition(status.DeploymentReadyType). - WithReason(string(workflow.Internal)). - WithMessageRegexp(atlasdeployment.BackupProtected), + status.TrueCondition(status.DeploymentReadyType), validateDeploymentUpdatingFunc(g)) }).WithTimeout(30 * time.Minute).WithPolling(PollingInterval).Should(BeTrue()) }) From bfb764ae1452c1dd86d84ce44724690df564d31c Mon Sep 17 00:00:00 2001 From: Igor Karpukhin Date: Tue, 28 Nov 2023 17:17:49 +0100 Subject: [PATCH 2/3] Removed unused code --- pkg/controller/atlasdeployment/backup.go | 42 --- pkg/controller/atlasdeployment/backup_test.go | 339 ------------------ 2 files changed, 381 deletions(-) delete mode 100644 pkg/controller/atlasdeployment/backup_test.go diff --git a/pkg/controller/atlasdeployment/backup.go b/pkg/controller/atlasdeployment/backup.go index 4f7da1c88a..5cbc7fb5ba 100644 --- a/pkg/controller/atlasdeployment/backup.go +++ b/pkg/controller/atlasdeployment/backup.go @@ -4,9 +4,7 @@ import ( "context" "errors" "fmt" - "net/http" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/validate" "github.com/google/go-cmp/cmp" @@ -27,8 +25,6 @@ import ( mdbv1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" ) -var errArgIsNotBackupSchedule = errors.New("failed to match resource type as AtlasBackupSchedule") - func (r *AtlasDeploymentReconciler) ensureBackupScheduleAndPolicy( service *workflow.Context, projectID string, @@ -68,44 +64,6 @@ func (r *AtlasDeploymentReconciler) ensureBackupScheduleAndPolicy( return r.updateBackupScheduleAndPolicy(service.Context, service, projectID, deployment, bSchedule, bPolicy) } -func backupScheduleManagedByAtlas(ctx context.Context, atlasClient mongodbatlas.Client, projectID string, deployment *mdbv1.AtlasDeployment, policy *mdbv1.AtlasBackupPolicy) customresource.AtlasChecker { - return func(resource mdbv1.AtlasCustomResource) (bool, error) { - clusterName := deployment.GetDeploymentName() - - backupSchedule, ok := resource.(*mdbv1.AtlasBackupSchedule) - if !ok { - return false, errArgIsNotBackupSchedule - } - - atlasBS, _, err := atlasClient.CloudProviderSnapshotBackupPolicies.Get(ctx, projectID, clusterName) - if err != nil { - var apiError *mongodbatlas.ErrorResponse - if errors.As(err, &apiError) && (apiError.ErrorCode == atlas.ResourceNotFound || apiError.HTTPCode == http.StatusNotFound) { - return false, nil - } - - return false, err - } - - operatorBS := backupSchedule.ToAtlas(atlasBS.ClusterID, clusterName, deployment.GetReplicationSetID(), policy) - if err != nil { - return false, err - } - if len(operatorBS.Policies) != len(atlasBS.Policies) { - return false, nil - } - if len(atlasBS.Policies) != 0 && len(operatorBS.Policies) != 0 { - operatorBS.Policies[0].ID = atlasBS.Policies[0].ID - } - - isSame, err := backupSchedulesAreEqual(atlasBS, operatorBS) - if err != nil { - return true, nil - } - return !isSame, nil - } -} - func (r *AtlasDeploymentReconciler) ensureBackupSchedule( service *workflow.Context, deployment *mdbv1.AtlasDeployment, diff --git a/pkg/controller/atlasdeployment/backup_test.go b/pkg/controller/atlasdeployment/backup_test.go deleted file mode 100644 index 2e05b7cc71..0000000000 --- a/pkg/controller/atlasdeployment/backup_test.go +++ /dev/null @@ -1,339 +0,0 @@ -package atlasdeployment - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "go.mongodb.org/atlas/mongodbatlas" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - atlas_mock "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/mocks/atlas" - mdbv1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/status" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/util/toptr" -) - -const ( - projectID = "testProjectID" - clusterName = "testClusterName" - clusterID = "testClusterID" -) - -func Test_backupScheduleManagedByAtlas(t *testing.T) { - deploment := &mdbv1.AtlasDeployment{ - Spec: mdbv1.AtlasDeploymentSpec{ - DeploymentSpec: &mdbv1.AdvancedDeploymentSpec{ - Name: clusterName, - }, - }, - } - - t.Run("should return err when wrong resource passed", func(t *testing.T) { - validator := backupScheduleManagedByAtlas(context.TODO(), mongodbatlas.Client{}, projectID, deploment, &mdbv1.AtlasBackupPolicy{}) - result, err := validator(&mdbv1.AtlasDeployment{}) - assert.EqualError(t, err, errArgIsNotBackupSchedule.Error()) - assert.False(t, result) - }) - - t.Run("should return false if backupschedule is not in atlas", func(t *testing.T) { - validator := backupScheduleManagedByAtlas(context.TODO(), mongodbatlas.Client{ - CloudProviderSnapshotBackupPolicies: &atlas_mock.CloudProviderSnapshotBackupPoliciesClientMock{ - GetFunc: func(projectID string, clusterName string) (*mongodbatlas.CloudProviderSnapshotBackupPolicy, *mongodbatlas.Response, error) { - return nil, &mongodbatlas.Response{}, &mongodbatlas.ErrorResponse{ErrorCode: atlas.ResourceNotFound} - }, - }, - }, projectID, deploment, &mdbv1.AtlasBackupPolicy{}) - result, err := validator(&mdbv1.AtlasBackupSchedule{}) - assert.NoError(t, err) - assert.False(t, result) - }) - - t.Run("should return true if resources are not equal", func(t *testing.T) { - validator := backupScheduleManagedByAtlas(context.TODO(), mongodbatlas.Client{ - CloudProviderSnapshotBackupPolicies: &atlas_mock.CloudProviderSnapshotBackupPoliciesClientMock{ - GetFunc: func(projectID string, clusterName string) (*mongodbatlas.CloudProviderSnapshotBackupPolicy, *mongodbatlas.Response, error) { - return &mongodbatlas.CloudProviderSnapshotBackupPolicy{ - ClusterID: clusterID, - ClusterName: clusterName, - ReferenceHourOfDay: new(int64), - ReferenceMinuteOfHour: new(int64), - RestoreWindowDays: new(int64), - UpdateSnapshots: new(bool), - NextSnapshot: "", - Policies: []mongodbatlas.Policy{ - { - ID: "policy-id", - PolicyItems: []mongodbatlas.PolicyItem{ - { - ID: "policy-item-id", - FrequencyInterval: 10, - FrequencyType: "hours", - RetentionUnit: "days", - RetentionValue: 10, - }, - }, - }, - }, - AutoExportEnabled: toptr.MakePtr(false), - Export: &mongodbatlas.Export{}, - UseOrgAndGroupNamesInExportPrefix: toptr.MakePtr(false), - Links: []*mongodbatlas.Link{}, - CopySettings: []mongodbatlas.CopySetting{ - { - CloudProvider: toptr.MakePtr[string]("AWS"), - RegionName: toptr.MakePtr[string]("us-east-1"), - ReplicationSpecID: toptr.MakePtr[string]("test-id"), - ShouldCopyOplogs: new(bool), - Frequencies: []string{}, - }, - }, - DeleteCopiedBackups: []mongodbatlas.DeleteCopiedBackup{}, - }, - &mongodbatlas.Response{}, nil - }, - }, - }, projectID, deploment, &mdbv1.AtlasBackupPolicy{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: mdbv1.AtlasBackupPolicySpec{}, - Status: status.BackupPolicyStatus{}, - }) - result, err := validator(&mdbv1.AtlasBackupSchedule{}) - assert.NoError(t, err) - assert.True(t, result) - }) - - t.Run("should return false if resources are equal", func(t *testing.T) { - validator := backupScheduleManagedByAtlas(context.TODO(), mongodbatlas.Client{ - CloudProviderSnapshotBackupPolicies: &atlas_mock.CloudProviderSnapshotBackupPoliciesClientMock{ - GetFunc: func(projectID string, clusterName string) (*mongodbatlas.CloudProviderSnapshotBackupPolicy, *mongodbatlas.Response, error) { - return &mongodbatlas.CloudProviderSnapshotBackupPolicy{ - ClusterID: clusterID, - ClusterName: clusterName, - ReferenceHourOfDay: toptr.MakePtr[int64](10), - ReferenceMinuteOfHour: toptr.MakePtr[int64](10), - RestoreWindowDays: toptr.MakePtr[int64](10), - UpdateSnapshots: toptr.MakePtr[bool](false), - NextSnapshot: "", - Policies: []mongodbatlas.Policy{ - { - ID: "policy-id", - PolicyItems: []mongodbatlas.PolicyItem{ - { - ID: "policy-item-id", - FrequencyInterval: 10, - FrequencyType: "hours", - RetentionUnit: "days", - RetentionValue: 10, - }, - }, - }, - }, - AutoExportEnabled: toptr.MakePtr(false), - Export: &mongodbatlas.Export{}, - UseOrgAndGroupNamesInExportPrefix: toptr.MakePtr(false), - Links: []*mongodbatlas.Link{}, - CopySettings: []mongodbatlas.CopySetting{ - { - CloudProvider: toptr.MakePtr[string]("AWS"), - RegionName: toptr.MakePtr[string]("us-east-1"), - ReplicationSpecID: toptr.MakePtr[string]("test-id"), - ShouldCopyOplogs: toptr.MakePtr(false), - Frequencies: []string{}, - }, - }, - DeleteCopiedBackups: []mongodbatlas.DeleteCopiedBackup{}, - }, - &mongodbatlas.Response{}, nil - }, - }, - }, projectID, deploment, &mdbv1.AtlasBackupPolicy{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: mdbv1.AtlasBackupPolicySpec{ - Items: []mdbv1.AtlasBackupPolicyItem{ - { - FrequencyType: "hours", - FrequencyInterval: 10, - RetentionUnit: "days", - RetentionValue: 10, - }, - }, - }, - }) - result, err := validator(&mdbv1.AtlasBackupSchedule{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: mdbv1.AtlasBackupScheduleSpec{ - AutoExportEnabled: false, - Export: &mdbv1.AtlasBackupExportSpec{}, - PolicyRef: common.ResourceRefNamespaced{}, - ReferenceHourOfDay: 10, - ReferenceMinuteOfHour: 10, - RestoreWindowDays: 10, - UpdateSnapshots: false, - UseOrgAndGroupNamesInExportPrefix: false, - CopySettings: []mdbv1.CopySetting{ - { - CloudProvider: toptr.MakePtr[string]("AWS"), - RegionName: toptr.MakePtr[string]("us-east-1"), - ShouldCopyOplogs: toptr.MakePtr(false), - Frequencies: []string{}, - }, - }, - }, - Status: status.BackupScheduleStatus{}, - }) - assert.NoError(t, err) - assert.False(t, result) - }) -} - -func Test_backupSchedulesAreEqual(t *testing.T) { - examplePolicy := mongodbatlas.CloudProviderSnapshotBackupPolicy{ - ClusterID: "testID", - ClusterName: "testName", - ReferenceHourOfDay: toptr.MakePtr[int64](12), - ReferenceMinuteOfHour: toptr.MakePtr[int64](59), - RestoreWindowDays: toptr.MakePtr[int64](4), - UpdateSnapshots: toptr.MakePtr[bool](false), - NextSnapshot: "test123", - Policies: []mongodbatlas.Policy{ - { - ID: "testID", - PolicyItems: []mongodbatlas.PolicyItem{ - { - ID: "testID1", - FrequencyInterval: 10, - FrequencyType: "testFreq1", - RetentionUnit: "testRet1", - RetentionValue: 21, - }, - { - ID: "testID2", - FrequencyInterval: 20, - FrequencyType: "testFreq2", - RetentionUnit: "testRet2", - RetentionValue: 450, - }, - }, - }, - }, - AutoExportEnabled: toptr.MakePtr[bool](true), - Export: &mongodbatlas.Export{ - ExportBucketID: "testID", - FrequencyType: "testFreq", - }, - UseOrgAndGroupNamesInExportPrefix: toptr.MakePtr[bool](false), - Links: []*mongodbatlas.Link{ - { - Rel: "abc", - Href: "xyz", - }, - }, - CopySettings: []mongodbatlas.CopySetting{ - { - CloudProvider: toptr.MakePtr[string]("testString"), - RegionName: toptr.MakePtr[string]("testString"), - ReplicationSpecID: toptr.MakePtr[string]("testString"), - ShouldCopyOplogs: toptr.MakePtr[bool](true), - Frequencies: []string{"testString"}, - }, - }, - DeleteCopiedBackups: []mongodbatlas.DeleteCopiedBackup{ - { - CloudProvider: toptr.MakePtr[string]("testString"), - RegionName: toptr.MakePtr[string]("testString"), - ReplicationSpecID: toptr.MakePtr[string]("testString"), - }, - }, - } - - t.Run("should return true when backups are both empty", func(t *testing.T) { - res, err := backupSchedulesAreEqual(&mongodbatlas.CloudProviderSnapshotBackupPolicy{}, &mongodbatlas.CloudProviderSnapshotBackupPolicy{}) - assert.NoError(t, err) - assert.True(t, res) - }) - t.Run("should return true when backups are identical", func(t *testing.T) { - res, err := backupSchedulesAreEqual(&examplePolicy, &examplePolicy) - assert.NoError(t, err) - assert.True(t, res) - }) - t.Run("should return true when backups are identical after normalization", func(t *testing.T) { - firstPolicy := &mongodbatlas.CloudProviderSnapshotBackupPolicy{ - ClusterID: clusterID, - Links: []*mongodbatlas.Link{ - { - Href: "policy1", - Rel: "policy1", - }, - }, - NextSnapshot: "policy1 NextSnapshot", - Policies: []mongodbatlas.Policy{ - { - ID: "policy ID", - PolicyItems: []mongodbatlas.PolicyItem{ - { - ID: "policy1 item 1 id", - FrequencyInterval: 1, - FrequencyType: "testFreq1", - RetentionUnit: "testRet1", - RetentionValue: 1, - }, - { - ID: "policy 1 item 2 id", - FrequencyInterval: 2, - FrequencyType: "testFreq2", - RetentionUnit: "testRet2", - RetentionValue: 2, - }, - }, - }, - }, - } - secondPolicy := &mongodbatlas.CloudProviderSnapshotBackupPolicy{ - ClusterID: clusterID, - Links: []*mongodbatlas.Link{ - { - Href: "policy2", - Rel: "policy2", - }, - }, - NextSnapshot: "policy2 NextSnapshot", - Policies: []mongodbatlas.Policy{ - { - ID: "policy ID", - PolicyItems: []mongodbatlas.PolicyItem{ - { - ID: "policy2 item 1 id", - FrequencyInterval: 1, - FrequencyType: "testFreq1", - RetentionUnit: "testRet1", - RetentionValue: 1, - }, - { - ID: "policy 2 item 2 id", - FrequencyInterval: 2, - FrequencyType: "testFreq2", - RetentionUnit: "testRet2", - RetentionValue: 2, - }, - }, - }, - }, - } - res, err := backupSchedulesAreEqual(firstPolicy, secondPolicy) - assert.NoError(t, err) - assert.True(t, res) - }) - t.Run("should return false when backups differ", func(t *testing.T) { - changedPolicy := examplePolicy - changedPolicy.ClusterName = "different name" - res, err := backupSchedulesAreEqual(&examplePolicy, &changedPolicy) - assert.NoError(t, err) - assert.False(t, res) - }) -} From 2efebaa179345e0b8a06c2d836c01ea80675545d Mon Sep 17 00:00:00 2001 From: Igor Karpukhin Date: Tue, 28 Nov 2023 22:46:51 +0100 Subject: [PATCH 3/3] Fixed backup schedule --- test/int/backup_protected_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/int/backup_protected_test.go b/test/int/backup_protected_test.go index 62e5d79dd6..5ec2a39b12 100644 --- a/test/int/backup_protected_test.go +++ b/test/int/backup_protected_test.go @@ -86,7 +86,7 @@ var _ = Describe("AtlasBackupSchedule Deletion Protected", }) }) - It("Should not process BackupSchedule with deletion protection ON", func() { + It("Should process BackupSchedule with deletion protection ON", func() { var bsPolicy *mdbv1.AtlasBackupPolicy var bsSchedule *mdbv1.AtlasBackupSchedule By("Creating AtlasBackupPolicy resource", func() { @@ -105,7 +105,7 @@ var _ = Describe("AtlasBackupSchedule Deletion Protected", Items: []mdbv1.AtlasBackupPolicyItem{ { FrequencyType: "daily", - FrequencyInterval: 5, + FrequencyInterval: 1, RetentionUnit: "days", RetentionValue: 20, }, @@ -131,9 +131,9 @@ var _ = Describe("AtlasBackupSchedule Deletion Protected", Name: bsPolicy.Name, Namespace: bsPolicy.Namespace, }, - ReferenceHourOfDay: 10, - ReferenceMinuteOfHour: 10, - RestoreWindowDays: 10, + ReferenceHourOfDay: 12, + ReferenceMinuteOfHour: 20, + RestoreWindowDays: 2, UpdateSnapshots: false, UseOrgAndGroupNamesInExportPrefix: false, CopySettings: []mdbv1.CopySetting{},