Skip to content

Commit 2e9abee

Browse files
author
Anton
authored
CLOUDP-86187: cluster update (replicationSpecs) (#188)
1 parent cc24191 commit 2e9abee

File tree

3 files changed

+88
-8
lines changed

3 files changed

+88
-8
lines changed

pkg/controller/atlascluster/cluster.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,7 @@ func MergedCluster(atlasCluster mongodbatlas.Cluster, spec mdbv1.AtlasClusterSpe
109109
return
110110
}
111111

112-
// TODO: might need to do this with other slices
113-
if err = compat.JSONSliceMerge(&result.ReplicationSpecs, atlasCluster.ReplicationSpecs); err != nil {
114-
return
115-
}
116-
117-
if err = compat.JSONSliceMerge(&result.ReplicationSpecs, spec.ReplicationSpecs); err != nil {
118-
return
119-
}
112+
mergeRegionConfigs(result.ReplicationSpecs, spec.ReplicationSpecs)
120113

121114
// According to the docs for 'providerSettings.regionName' (https://docs.atlas.mongodb.com/reference/api/clusters-create-one/):
122115
// "Don't specify this parameter when creating a multi-region cluster using the replicationSpec object or a Global
@@ -130,6 +123,26 @@ func MergedCluster(atlasCluster mongodbatlas.Cluster, spec mdbv1.AtlasClusterSpe
130123
return
131124
}
132125

126+
// mergeRegionConfigs removes replicationSpecs[i].RegionsConfigs[key] from Atlas Cluster that are absent in Operator.
127+
// Dev idea: this could have been added into some more generic method like `JSONCopy` or something wrapping it to make
128+
// sure any Atlas map get redundant keys removed. So far there's only one map in Cluster ('RegionsConfig') so we'll do this
129+
// explicitly - but may make sense to refactor this later if more maps are added (and all follow the same logic).
130+
func mergeRegionConfigs(atlasSpecs []mongodbatlas.ReplicationSpec, operatorSpecs []mdbv1.ReplicationSpec) {
131+
for i, operatorSpec := range operatorSpecs {
132+
if len(operatorSpec.RegionsConfig) == 0 {
133+
// Edge case: if the operator doesn't specify regions configs - Atlas will put the default ones. We shouldn't
134+
// remove it in this case.
135+
continue
136+
}
137+
atlasSpec := atlasSpecs[i]
138+
for key := range atlasSpec.RegionsConfig {
139+
if _, ok := operatorSpec.RegionsConfig[key]; !ok {
140+
delete(atlasSpec.RegionsConfig, key)
141+
}
142+
}
143+
}
144+
}
145+
133146
// ClustersEqual compares two Atlas Clusters
134147
func ClustersEqual(log *zap.SugaredLogger, clusterAtlas mongodbatlas.Cluster, clusterOperator mongodbatlas.Cluster) bool {
135148
d := cmp.Diff(clusterAtlas, clusterOperator, cmpopts.EquateEmpty())

pkg/controller/atlascluster/cluster_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import (
1010
mdbv1 "github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1"
1111
)
1212

13+
func init() {
14+
logger, _ := zap.NewDevelopment()
15+
zap.ReplaceGlobals(logger)
16+
}
17+
1318
func TestClusterMatchesSpec(t *testing.T) {
1419
t.Run("Clusters match (enums)", func(t *testing.T) {
1520
atlasCluster := mongodbatlas.Cluster{
@@ -82,6 +87,10 @@ func TestClusterMatchesSpec(t *testing.T) {
8287
"US_EAST": {AnalyticsNodes: int64ptr(0), ElectableNodes: int64ptr(3), Priority: int64ptr(7), ReadOnlyNodes: int64ptr(0)}}},
8388
}
8489
operatorCluster := mdbv1.DefaultAWSCluster("test-ns", "project-name")
90+
operatorCluster.Spec.ReplicationSpecs = []mdbv1.ReplicationSpec{{
91+
NumShards: int64ptr(1),
92+
ZoneName: "zone1",
93+
}}
8594

8695
merged, err := MergedCluster(*atlasCluster, operatorCluster.Spec)
8796
assert.NoError(t, err)
@@ -120,6 +129,43 @@ func TestClusterMatchesSpec(t *testing.T) {
120129
equal := ClustersEqual(zap.S(), *atlasCluster, merged)
121130
assert.False(t, equal)
122131
})
132+
133+
t.Run("Clusters don't match - Operator removed the region", func(t *testing.T) {
134+
atlasCluster, err := mdbv1.DefaultAWSCluster("test-ns", "project-name").Spec.Cluster()
135+
assert.NoError(t, err)
136+
atlasCluster.ReplicationSpecs = []mongodbatlas.ReplicationSpec{{
137+
ID: "id",
138+
NumShards: int64ptr(1),
139+
ZoneName: "zone1",
140+
RegionsConfig: map[string]mongodbatlas.RegionsConfig{
141+
"US_EAST": {AnalyticsNodes: int64ptr(0), ElectableNodes: int64ptr(3), Priority: int64ptr(7), ReadOnlyNodes: int64ptr(0)},
142+
"US_WEST": {AnalyticsNodes: int64ptr(2), ElectableNodes: int64ptr(5), Priority: int64ptr(6), ReadOnlyNodes: int64ptr(0)},
143+
}},
144+
}
145+
operatorCluster := mdbv1.DefaultAWSCluster("test-ns", "project-name")
146+
operatorCluster.Spec.ReplicationSpecs = []mdbv1.ReplicationSpec{{
147+
NumShards: int64ptr(1),
148+
ZoneName: "zone1",
149+
RegionsConfig: map[string]mdbv1.RegionsConfig{
150+
"US_EAST": {AnalyticsNodes: int64ptr(0), ElectableNodes: int64ptr(3), Priority: int64ptr(7), ReadOnlyNodes: int64ptr(0)},
151+
}},
152+
}
153+
154+
merged, err := MergedCluster(*atlasCluster, operatorCluster.Spec)
155+
assert.NoError(t, err)
156+
157+
expectedReplicationSpecs := []mongodbatlas.ReplicationSpec{{
158+
ID: "id",
159+
NumShards: int64ptr(1),
160+
ZoneName: "zone1",
161+
RegionsConfig: map[string]mongodbatlas.RegionsConfig{
162+
"US_EAST": {AnalyticsNodes: int64ptr(0), ElectableNodes: int64ptr(3), Priority: int64ptr(7), ReadOnlyNodes: int64ptr(0)}}},
163+
}
164+
assert.Equal(t, expectedReplicationSpecs, merged.ReplicationSpecs)
165+
166+
equal := ClustersEqual(zap.S(), *atlasCluster, merged)
167+
assert.False(t, equal)
168+
})
123169
}
124170
func int64ptr(i int64) *int64 {
125171
return &i

test/int/cluster_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ var _ = Describe("AtlasCluster", func() {
280280
// Apart from 'ID' all other fields are equal to the ones sent by the Operator
281281
Expect(c.ReplicationSpecs).To(Equal(expectedReplicationSpecs))
282282
}
283+
283284
By("Creating the Cluster", func() {
284285
Expect(k8sClient.Create(context.Background(), createdCluster)).To(Succeed())
285286

@@ -290,6 +291,26 @@ var _ = Describe("AtlasCluster", func() {
290291

291292
checkAtlasState(replicationSpecsCheckFunc)
292293
})
294+
295+
By("Updating the cluster (multiple operations)", func() {
296+
delete(createdCluster.Spec.ReplicationSpecs[0].RegionsConfig, "US_WEST_2")
297+
createdCluster.Spec.ReplicationSpecs[0].RegionsConfig["US_WEST_1"] = mdbv1.RegionsConfig{AnalyticsNodes: int64ptr(0), ElectableNodes: int64ptr(2), Priority: int64ptr(6), ReadOnlyNodes: int64ptr(0)}
298+
config := createdCluster.Spec.ReplicationSpecs[0].RegionsConfig["US_EAST_1"]
299+
// Note, that Atlas has strict requirements to priorities - they must start with 7 and be in descending order over the regions
300+
config.Priority = int64ptr(7)
301+
createdCluster.Spec.ReplicationSpecs[0].RegionsConfig["US_EAST_1"] = config
302+
303+
createdCluster.Spec.ProviderSettings.AutoScaling.Compute.MaxInstanceSize = "M30"
304+
305+
performUpdate(80 * time.Minute)
306+
307+
Eventually(testutil.WaitFor(k8sClient, createdCluster, status.TrueCondition(status.ReadyType), validateClusterUpdatingFunc()),
308+
1800, interval).Should(BeTrue())
309+
310+
doCommonStatusChecks()
311+
312+
checkAtlasState(replicationSpecsCheckFunc)
313+
})
293314
})
294315
})
295316

0 commit comments

Comments
 (0)