diff --git a/config/crd/bases/atlas.mongodb.com_atlasprojects.yaml b/config/crd/bases/atlas.mongodb.com_atlasprojects.yaml index a19eabdc90..3b45a98f27 100644 --- a/config/crd/bases/atlas.mongodb.com_atlasprojects.yaml +++ b/config/crd/bases/atlas.mongodb.com_atlasprojects.yaml @@ -124,8 +124,7 @@ spec: this field is updated by the Atlas Operator only after specification changes items: - description: TODO solve circular dependency (move ProjectIPAccessList - to subpackage?) Copy of mdbv1.ProjectIPAccessList + description: ProjectIPAccessList is a copy of mdbv1.ProjectIPAccessList properties: awsSecurityGroup: description: Unique identifier of AWS security group in this diff --git a/pkg/controller/atlascluster/atlascluster_controller.go b/pkg/controller/atlascluster/atlascluster_controller.go index 695f6bf8c2..5936eceda6 100644 --- a/pkg/controller/atlascluster/atlascluster_controller.go +++ b/pkg/controller/atlascluster/atlascluster_controller.go @@ -29,15 +29,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/source" - "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/watch" - "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/workflow" - "github.com/mongodb/mongodb-atlas-kubernetes/pkg/util/kube" - mdbv1 "github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1/status" "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/atlas" "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/customresource" "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/statushandler" + "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/watch" + "github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/workflow" + "github.com/mongodb/mongodb-atlas-kubernetes/pkg/util/kube" ) // AtlasClusterReconciler reconciles an AtlasCluster object diff --git a/pkg/controller/atlascluster/cluster.go b/pkg/controller/atlascluster/cluster.go index be4ee6fb4c..dec1487ca1 100644 --- a/pkg/controller/atlascluster/cluster.go +++ b/pkg/controller/atlascluster/cluster.go @@ -74,7 +74,7 @@ func (r *AtlasClusterReconciler) ensureClusterState(log *zap.SugaredLogger, conn c, _, err = client.Clusters.Update(ctx, project.Status.ID, cluster.Spec.Name, spec) if err != nil { - return c, workflow.Terminate(workflow.ClusterNotCreatedInAtlas, err.Error()) + return c, workflow.Terminate(workflow.ClusterNotUpdatedInAtlas, err.Error()) } return c, workflow.InProgress(workflow.ClusterUpdating, "cluster is updating") diff --git a/pkg/controller/workflow/reason.go b/pkg/controller/workflow/reason.go index 096a01398b..5097175be8 100644 --- a/pkg/controller/workflow/reason.go +++ b/pkg/controller/workflow/reason.go @@ -20,6 +20,7 @@ const ( // Atlas Cluster reasons const ( ClusterNotCreatedInAtlas ConditionReason = "ClusterNotCreatedInAtlas" + ClusterNotUpdatedInAtlas ConditionReason = "ClusterNotUpdatedInAtlas" ClusterCreating ConditionReason = "ClusterCreating" ClusterUpdating ConditionReason = "ClusterUpdating" ) diff --git a/pkg/util/testutil/conditions.go b/pkg/util/testutil/conditions.go index 55f44b64bd..17d820d355 100644 --- a/pkg/util/testutil/conditions.go +++ b/pkg/util/testutil/conditions.go @@ -41,7 +41,6 @@ func (m *conditionMatcher) Match(actual interface{}) (success bool, err error) { if m.ExpectedCondition.Type != "" && c.Type != m.ExpectedCondition.Type { return false, nil } - // Add regexp when necessary if m.ExpectedCondition.Message != "" { gomega.Expect(c.Message).To(gomega.MatchRegexp(m.ExpectedCondition.Message)) } diff --git a/test/int/cluster_test.go b/test/int/cluster_test.go index 44e228c5de..a81cd9c2b4 100644 --- a/test/int/cluster_test.go +++ b/test/int/cluster_test.go @@ -122,6 +122,43 @@ var _ = Describe("AtlasCluster", func() { } Describe("Create/Update the cluster", func() { + It("Should fail, then be fixed", func() { + expectedCluster := testAtlasCluster(namespace.Name, "test-cluster", createdProject.Name) + expectedCluster.Spec.Name = "" + + By(fmt.Sprintf("Creating the Cluster %s with invalid parameters", kube.ObjectKeyFromObject(expectedCluster)), func() { + createdCluster.ObjectMeta = expectedCluster.ObjectMeta + Expect(k8sClient.Create(context.Background(), expectedCluster)).ToNot(HaveOccurred()) + + Eventually( + testutil.WaitFor( + k8sClient, + createdCluster, + status. + FalseCondition(status.ClusterReadyType). + WithReason(string(workflow.Internal)). // Internal due to reconciliation failing on the initial GET request + WithMessageRegexp("name is invalid because must be set"), + ), + 60, + interval, + ).Should(BeTrue()) + + lastGeneration++ + }) + + By("Fixing the cluster", func() { + createdCluster.Spec.Name = "fixed-cluster" + + Expect(k8sClient.Update(context.Background(), createdCluster)).To(Succeed()) + + Eventually(testutil.WaitFor(k8sClient, createdCluster, status.TrueCondition(status.ReadyType), validateClusterCreatingFunc()), + 1200, interval).Should(BeTrue()) + + doCommonChecks() + checkAtlasState() + }) + }) + It("Should Succeed", func() { expectedCluster := testAtlasCluster(namespace.Name, "test-cluster", createdProject.Name) @@ -180,7 +217,14 @@ var _ = Describe("AtlasCluster", func() { Expect(k8sClient.Update(context.Background(), createdCluster)).To(Succeed()) Eventually( - testutil.WaitFor(k8sClient, createdCluster, status.FalseCondition(status.ClusterReadyType).WithReason(string(workflow.ClusterNotCreatedInAtlas))), + testutil.WaitFor( + k8sClient, + createdCluster, + status. + FalseCondition(status.ClusterReadyType). + WithReason(string(workflow.ClusterNotUpdatedInAtlas)). + WithMessageRegexp("CANNOT_UPDATE_PAUSED_CLUSTER"), + ), 60, interval, ).Should(BeTrue()) @@ -203,6 +247,65 @@ var _ = Describe("AtlasCluster", func() { Expect(c.ProviderBackupEnabled).To(Equal(createdCluster.Spec.ProviderBackupEnabled)) }) }) + + By("Setting AutoScaling.Compute.Enabled to false (should fail)", func() { + createdCluster.Spec.ProviderSettings.AutoScaling = &mdbv1.AutoScalingSpec{ + Compute: &mdbv1.ComputeSpec{ + Enabled: boolptr(false), + }, + } + + Expect(k8sClient.Update(context.Background(), createdCluster)).To(Succeed()) + Eventually( + testutil.WaitFor( + k8sClient, + createdCluster, + status. + FalseCondition(status.ClusterReadyType). + WithReason(string(workflow.ClusterNotUpdatedInAtlas)). + WithMessageRegexp("INVALID_ATTRIBUTE"), + ), + 60, + interval, + ).Should(BeTrue()) + + lastGeneration++ + + By("Fixing the Cluster", func() { + createdCluster.Spec.ProviderSettings.AutoScaling = nil + performUpdate() + doCommonChecks() + checkAtlasState() + }) + }) + + By("Setting incorrect instance size (should fail)", func() { + oldSizeName := createdCluster.Spec.ProviderSettings.InstanceSizeName + createdCluster.Spec.ProviderSettings.InstanceSizeName = "M42" + + Expect(k8sClient.Update(context.Background(), createdCluster)).To(Succeed()) + Eventually( + testutil.WaitFor( + k8sClient, + createdCluster, + status. + FalseCondition(status.ClusterReadyType). + WithReason(string(workflow.ClusterNotUpdatedInAtlas)). + WithMessageRegexp("INVALID_ENUM_VALUE"), + ), + 60, + interval, + ).Should(BeTrue()) + + lastGeneration++ + + By("Fixing the Cluster", func() { + createdCluster.Spec.ProviderSettings.InstanceSizeName = oldSizeName + performUpdate() + doCommonChecks() + checkAtlasState() + }) + }) }) }) })