Skip to content

Commit 0555f81

Browse files
authored
CLOUDP-80765: Handle Cluster pause/unpause (#89)
1 parent 778eb3b commit 0555f81

File tree

6 files changed

+75
-12
lines changed

6 files changed

+75
-12
lines changed

config/crd/bases/atlas.mongodb.com_atlasclusters.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ spec:
143143
maximum: 50
144144
minimum: 1
145145
type: integer
146+
paused:
147+
description: Flag that indicates whether the cluster should be paused.
148+
type: boolean
146149
pitEnabled:
147150
description: Flag that indicates the cluster uses continuous cloud
148151
backups.

pkg/api/v1/atlascluster_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ type AtlasClusterSpec struct {
8383
// +optional
8484
NumShards *int `json:"numShards,omitempty"`
8585

86+
// Flag that indicates whether the cluster should be paused.
87+
Paused *bool `json:"paused,omitempty"`
88+
8689
// Flag that indicates the cluster uses continuous cloud backups.
8790
// +optional
8891
PitEnabled *bool `json:"pitEnabled,omitempty"`

pkg/api/v1/atlascluster_types_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import (
1010
"go.mongodb.org/atlas/mongodbatlas"
1111
)
1212

13-
var excludedClusterFieldsOurs = map[string]bool{}
14-
var excludedClusterFieldsTheirs = map[string]bool{}
13+
var (
14+
excludedClusterFieldsOurs = map[string]bool{}
15+
excludedClusterFieldsTheirs = map[string]bool{}
16+
)
1517

1618
func init() {
1719
excludedClusterFieldsOurs["projectRef"] = true
@@ -32,9 +34,6 @@ func init() {
3234
excludedClusterFieldsTheirs["connectionStrings"] = true
3335
excludedClusterFieldsTheirs["srvAddress"] = true
3436
excludedClusterFieldsTheirs["stateName"] = true
35-
36-
// CLOUDP-80765
37-
excludedClusterFieldsTheirs["paused"] = true
3837
}
3938

4039
func TestCompatibility(t *testing.T) {

pkg/api/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/atlascluster/cluster.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,28 @@ func (r *AtlasClusterReconciler) ensureClusterState(log *zap.SugaredLogger, conn
4848

4949
switch c.StateName {
5050
case "IDLE":
51+
if done, err := clusterMatchesSpec(log, c, cluster.Spec); err != nil {
52+
return c, workflow.Terminate(workflow.Internal, err.Error())
53+
} else if done {
54+
return c, workflow.OK()
55+
}
56+
5157
spec, err := cluster.Spec.Cluster()
5258
if err != nil {
5359
return c, workflow.Terminate(workflow.Internal, err.Error())
5460
}
5561

56-
if done, err := clusterMatchesSpec(log, c, cluster.Spec); err != nil {
57-
return c, workflow.Terminate(workflow.Internal, err.Error())
58-
} else if done {
59-
return c, workflow.OK()
62+
if cluster.Spec.Paused != nil {
63+
if c.Paused == nil || *c.Paused != *cluster.Spec.Paused {
64+
// paused is different from Atlas
65+
// we need to first send a special (un)pause request before reconciling everything else
66+
spec = &mongodbatlas.Cluster{
67+
Paused: cluster.Spec.Paused,
68+
}
69+
} else {
70+
// otherwise, don't send the paused field
71+
spec.Paused = nil
72+
}
6073
}
6174

6275
c, _, err = client.Clusters.Update(ctx, project.Status.ID, cluster.Spec.Name, spec)

test/int/cluster_test.go

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ var _ = Describe("AtlasCluster", func() {
8989
)))
9090
Expect(createdCluster.Status.ObservedGeneration).To(Equal(createdCluster.Generation))
9191
Expect(createdCluster.Status.ObservedGeneration).To(Equal(lastGeneration + 1))
92-
lastGeneration++
9392
})
9493
}
9594

@@ -119,7 +118,7 @@ var _ = Describe("AtlasCluster", func() {
119118
Eventually(testutil.WaitFor(k8sClient, createdCluster, status.TrueCondition(status.ReadyType), validateClusterUpdatingFunc()),
120119
1200, interval).Should(BeTrue())
121120

122-
doCommonChecks()
121+
lastGeneration++
123122
}
124123

125124
Describe("Create/Update the cluster", func() {
@@ -142,12 +141,14 @@ var _ = Describe("AtlasCluster", func() {
142141
By("Updating the Cluster labels", func() {
143142
createdCluster.Spec.Labels = []mdbv1.LabelSpec{{Key: "int-test", Value: "true"}}
144143
performUpdate()
144+
doCommonChecks()
145145
checkAtlasState()
146146
})
147147

148148
By("Updating the Cluster backups settings", func() {
149149
createdCluster.Spec.ProviderBackupEnabled = boolptr(true)
150150
performUpdate()
151+
doCommonChecks()
151152
checkAtlasState(func(c *mongodbatlas.Cluster) {
152153
Expect(c.ProviderBackupEnabled).To(Equal(createdCluster.Spec.ProviderBackupEnabled))
153154
})
@@ -156,13 +157,52 @@ var _ = Describe("AtlasCluster", func() {
156157
By("Decreasing the Cluster disk size", func() {
157158
createdCluster.Spec.DiskSizeGB = intptr(10)
158159
performUpdate()
160+
doCommonChecks()
159161
checkAtlasState(func(c *mongodbatlas.Cluster) {
160162
Expect(*c.DiskSizeGB).To(BeEquivalentTo(*createdCluster.Spec.DiskSizeGB))
161163

162164
// check whether https://github.com/mongodb/go-client-mongodb-atlas/issues/140 is fixed
163165
Expect(c.DiskSizeGB).To(BeAssignableToTypeOf(float64ptr(0)), "DiskSizeGB is no longer a *float64, please check the spec!")
164166
})
165167
})
168+
169+
By("Pausing the cluster", func() {
170+
createdCluster.Spec.Paused = boolptr(true)
171+
performUpdate()
172+
doCommonChecks()
173+
checkAtlasState(func(c *mongodbatlas.Cluster) {
174+
Expect(c.Paused).To(Equal(createdCluster.Spec.Paused))
175+
})
176+
})
177+
178+
By("Updating the Cluster configuration while paused (should fail)", func() {
179+
createdCluster.Spec.ProviderBackupEnabled = boolptr(false)
180+
181+
Expect(k8sClient.Update(context.Background(), createdCluster)).To(Succeed())
182+
Eventually(
183+
testutil.WaitFor(k8sClient, createdCluster, status.FalseCondition(status.ClusterReadyType).WithReason(string(workflow.ClusterNotCreatedInAtlas))),
184+
60,
185+
interval,
186+
).Should(BeTrue())
187+
188+
lastGeneration++
189+
})
190+
191+
By("Unpausing the cluster", func() {
192+
createdCluster.Spec.Paused = boolptr(false)
193+
performUpdate()
194+
doCommonChecks()
195+
checkAtlasState(func(c *mongodbatlas.Cluster) {
196+
Expect(c.Paused).To(Equal(createdCluster.Spec.Paused))
197+
})
198+
})
199+
200+
By("Checking that modifications were applied after unpausing", func() {
201+
doCommonChecks()
202+
checkAtlasState(func(c *mongodbatlas.Cluster) {
203+
Expect(c.ProviderBackupEnabled).To(Equal(createdCluster.Spec.ProviderBackupEnabled))
204+
})
205+
})
166206
})
167207
})
168208
})
@@ -200,7 +240,7 @@ func validateClusterUpdatingFunc() func(a mdbv1.AtlasCustomResource) {
200240
}
201241
// When the create request has been made to Atlas - we expect the following status
202242
if !isIdle {
203-
Expect(c.Status.StateName).To(Equal("UPDATING"), fmt.Sprintf("Current conditions: %+v", c.Status.Conditions))
243+
Expect(c.Status.StateName).To(Or(Equal("UPDATING"), Equal("REPAIRING")), fmt.Sprintf("Current conditions: %+v", c.Status.Conditions))
204244
expectedConditionsMatchers := testutil.MatchConditions(
205245
status.FalseCondition(status.ClusterReadyType).WithReason(string(workflow.ClusterUpdating)).WithMessageRegexp("cluster is updating"),
206246
status.FalseCondition(status.ReadyType),

0 commit comments

Comments
 (0)