Skip to content

Commit 01d5960

Browse files
authored
CLOUDP-226369: Fix instance size updates when autoscale ON (#1351)
Signed-off-by: jose.vazquez <[email protected]>
1 parent a6a0754 commit 01d5960

File tree

12 files changed

+261
-49
lines changed

12 files changed

+261
-49
lines changed

.github/workflows/lint.yaml

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Check for every push
2-
32
name: Lint
43

54
on:
@@ -21,20 +20,10 @@ jobs:
2120
uses: actions/setup-go@v4
2221
with:
2322
go-version-file: "${{ github.workspace }}/go.mod"
23+
cache: false
2424

25-
- name: golangci-lint
26-
uses: golangci/[email protected]
27-
with:
28-
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
29-
version: v1.53.3
30-
31-
# Optional: working directory, useful for monorepos
32-
# working-directory:
33-
34-
args: --timeout 10m
35-
# Optional: show only new issues if it's a pull request. The default value is `false`.
36-
# only-new-issues: true
37-
25+
- name: lint
26+
run: make lint
3827

3928
- name: Run ShellCheck
4029
uses: bewuethr/shellcheck-action@v2

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ OPERATOR_NAMESPACE = mongodb-atlas-system
7979
ATLAS_DOMAIN = https://cloud-qa.mongodb.com/
8080
ATLAS_KEY_SECRET_NAME = mongodb-atlas-operator-api-key
8181

82+
# golangci-lint
83+
GOLANGCI_LINT_VERSION := v1.54.2
84+
8285
.DEFAULT_GOAL := help
8386
.PHONY: help
8487
help: ## Show this help screen
@@ -155,9 +158,13 @@ $(TIMESTAMPS_DIR)/manifests: $(GO_SOURCES)
155158
manifests: CRD_OPTIONS ?= "crd:crdVersions=v1"
156159
manifests: fmt controller-gen $(TIMESTAMPS_DIR)/manifests ## Generate manifests e.g. CRD, RBAC etc.
157160

161+
golangci-lint:
162+
@which $@ >/dev/null 2>&1 || \
163+
go install "github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)"
164+
158165
.PHONY: lint
159-
lint:
160-
golangci-lint run
166+
lint: golangci-lint
167+
golangci-lint run --timeout 10m
161168

162169
$(TIMESTAMPS_DIR)/fmt: $(GO_SOURCES)
163170
@echo "goimports -local github.com/mongodb/mongodb-atlas-kubernetes -l -w \$$(GO_SOURCES)"

major-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1

pkg/controller/atlasdeployment/advanced_deployment.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func advancedDeploymentIdle(ctx *workflow.Context, project *mdbv1.AtlasProject,
8383
return atlasDeploymentAsAtlas, workflow.Terminate(workflow.Internal, err.Error())
8484
}
8585

86-
if areEqual, _ := AdvancedDeploymentsEqual(ctx.Log, specDeployment, atlasDeployment); areEqual {
86+
if areEqual, _ := AdvancedDeploymentsEqual(ctx.Log, &specDeployment, &atlasDeployment); areEqual {
8787
return atlasDeploymentAsAtlas, workflow.OK()
8888
}
8989

@@ -192,18 +192,27 @@ func convertDiskSizeField(result *mdbv1.AdvancedDeploymentSpec, atlas *mongodbat
192192
}
193193

194194
// AdvancedDeploymentsEqual compares two Atlas Advanced Deployments
195-
func AdvancedDeploymentsEqual(log *zap.SugaredLogger, deploymentOperator mdbv1.AdvancedDeploymentSpec, deploymentAtlas mdbv1.AdvancedDeploymentSpec) (areEqual bool, diff string) {
196-
deploymentAtlas = cleanupFieldsToCompare(deploymentAtlas, deploymentOperator)
197-
198-
d := cmp.Diff(deploymentAtlas, deploymentOperator, cmpopts.EquateEmpty(), cmpopts.SortSlices(mdbv1.LessAD))
195+
func AdvancedDeploymentsEqual(log *zap.SugaredLogger, deploymentOperator *mdbv1.AdvancedDeploymentSpec, deploymentAtlas *mdbv1.AdvancedDeploymentSpec) (areEqual bool, diff string) {
196+
expected := deploymentOperator.DeepCopy()
197+
actualCleaned := cleanupFieldsToCompare(deploymentAtlas.DeepCopy(), expected)
198+
199+
// Ignore differences on auto-scaled region configs
200+
for _, rs := range expected.ReplicationSpecs {
201+
for _, rc := range rs.RegionConfigs {
202+
if isComputeAutoScalingEnabled(rc.AutoScaling) {
203+
ignoreInstanceSize(rc)
204+
}
205+
}
206+
}
207+
d := cmp.Diff(actualCleaned, expected, cmpopts.EquateEmpty(), cmpopts.SortSlices(mdbv1.LessAD))
199208
if d != "" {
200209
log.Debugf("Deployments are different: %s", d)
201210
}
202211

203212
return d == "", d
204213
}
205214

206-
func cleanupFieldsToCompare(atlas, operator mdbv1.AdvancedDeploymentSpec) mdbv1.AdvancedDeploymentSpec {
215+
func cleanupFieldsToCompare(atlas, operator *mdbv1.AdvancedDeploymentSpec) *mdbv1.AdvancedDeploymentSpec {
207216
if atlas.ReplicationSpecs == nil {
208217
return atlas
209218
}
@@ -231,6 +240,10 @@ func cleanupFieldsToCompare(atlas, operator mdbv1.AdvancedDeploymentSpec) mdbv1.
231240
regionConfig.ReadOnlySpecs = operator.ReplicationSpecs[specIdx].RegionConfigs[configIdx].ReadOnlySpecs
232241
}
233242
}
243+
244+
if isComputeAutoScalingEnabled(regionConfig.AutoScaling) {
245+
ignoreInstanceSize(regionConfig)
246+
}
234247
}
235248
}
236249

pkg/controller/atlasdeployment/advanced_deployment_test.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,78 @@ func TestAdvancedDeploymentsEqual(t *testing.T) {
5050
regionConfig := defaultAtlas.ReplicationSpecs[0].RegionConfigs[0]
5151
fillInSpecs(regionConfig, "M10", "AWS")
5252

53-
t.Run("Test ", func(t *testing.T) {
53+
t.Run("Test equal advanced deployments", func(t *testing.T) {
5454
advancedCluster := mdbv1.DefaultAwsAdvancedDeployment("default", "my-project")
5555

5656
merged, atlas, err := MergedAdvancedDeployment(*defaultAtlas, *advancedCluster.Spec.AdvancedDeploymentSpec)
5757
assert.NoError(t, err)
58+
beforeSpec := merged.DeepCopy()
59+
beforeAtlas := atlas.DeepCopy()
5860

5961
logger, _ := zap.NewProduction()
60-
areEqual, _ := AdvancedDeploymentsEqual(logger.Sugar(), merged, atlas)
62+
areEqual, _ := AdvancedDeploymentsEqual(logger.Sugar(), &merged, &atlas)
6163
assert.True(t, areEqual, "Deployments should be equal")
64+
assert.Equal(t, beforeSpec, &merged, "Comparison should not change original spec values")
65+
assert.Equal(t, beforeAtlas, &atlas, "Comparison should not change original atlas values")
66+
})
67+
68+
t.Run("Advanced deployments are equal when autoscaling is ON and only differ on instance sizes", func(t *testing.T) {
69+
advancedCluster := mdbv1.DefaultAwsAdvancedDeployment("default", "my-project")
70+
// set auto scaling ON
71+
advancedCluster.Spec.AdvancedDeploymentSpec.ReplicationSpecs[0].RegionConfigs[0].AutoScaling = &mdbv1.AdvancedAutoScalingSpec{
72+
DiskGB: &mdbv1.DiskGB{
73+
Enabled: toptr.MakePtr(false),
74+
},
75+
Compute: &mdbv1.ComputeSpec{
76+
Enabled: toptr.MakePtr(true),
77+
ScaleDownEnabled: toptr.MakePtr(true),
78+
MinInstanceSize: "M10",
79+
MaxInstanceSize: "M30",
80+
},
81+
}
82+
83+
merged, atlas, err := MergedAdvancedDeployment(*defaultAtlas, *advancedCluster.Spec.AdvancedDeploymentSpec)
84+
// copy autoscaling to atlas
85+
k8sRegion := advancedCluster.Spec.AdvancedDeploymentSpec.ReplicationSpecs[0].RegionConfigs[0]
86+
atlas.ReplicationSpecs[0].RegionConfigs[0].AutoScaling = &mdbv1.AdvancedAutoScalingSpec{
87+
DiskGB: &mdbv1.DiskGB{
88+
Enabled: k8sRegion.AutoScaling.DiskGB.Enabled,
89+
},
90+
Compute: &mdbv1.ComputeSpec{
91+
Enabled: k8sRegion.AutoScaling.Compute.Enabled,
92+
ScaleDownEnabled: k8sRegion.AutoScaling.Compute.ScaleDownEnabled,
93+
MinInstanceSize: k8sRegion.AutoScaling.Compute.MinInstanceSize,
94+
MaxInstanceSize: k8sRegion.AutoScaling.Compute.MaxInstanceSize,
95+
},
96+
}
97+
// inject difference
98+
atlas.ReplicationSpecs[0].RegionConfigs[0].ElectableSpecs.InstanceSize = "something-else"
99+
assert.NoError(t, err)
100+
beforeSpec := merged.DeepCopy()
101+
beforeAtlas := atlas.DeepCopy()
102+
103+
logger, _ := zap.NewProduction()
104+
areEqual, _ := AdvancedDeploymentsEqual(logger.Sugar(), &merged, &atlas)
105+
assert.True(t, areEqual, "Deployments should be equal")
106+
assert.Equal(t, beforeSpec, &merged, "Comparison should not change original spec values")
107+
assert.Equal(t, beforeAtlas, &atlas, "Comparison should not change original atlas values")
108+
})
109+
110+
t.Run("Advanced deployments are different when autoscaling is OFF and only differ on instance sizes", func(t *testing.T) {
111+
advancedCluster := mdbv1.DefaultAwsAdvancedDeployment("default", "my-project")
112+
113+
merged, atlas, err := MergedAdvancedDeployment(*defaultAtlas, *advancedCluster.Spec.AdvancedDeploymentSpec)
114+
// inject difference
115+
atlas.ReplicationSpecs[0].RegionConfigs[0].ElectableSpecs.InstanceSize = "something-else"
116+
assert.NoError(t, err)
117+
beforeSpec := merged.DeepCopy()
118+
beforeAtlas := atlas.DeepCopy()
119+
120+
logger, _ := zap.NewProduction()
121+
areEqual, _ := AdvancedDeploymentsEqual(logger.Sugar(), &merged, &atlas)
122+
assert.False(t, areEqual, "Deployments should be different")
123+
assert.Equal(t, beforeSpec, &merged, "Comparison should not change original spec values")
124+
assert.Equal(t, beforeAtlas, &atlas, "Comparison should not change original atlas values")
62125
})
63126
}
64127

pkg/controller/atlasdeployment/deployment.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ func convertLegacyReplicationSpecs(legacy *mdbv1.DeploymentSpec) ([]*mdbv1.Advan
5858
fillDefaultReplicationSpec(legacy)
5959
}
6060

61-
for _, legacyResplicationSpec := range legacy.ReplicationSpecs {
62-
resplicationSpec := &mdbv1.AdvancedReplicationSpec{
63-
NumShards: *convertLegacyInt64(legacyResplicationSpec.NumShards),
64-
ZoneName: legacyResplicationSpec.ZoneName,
61+
for _, legacyReplicationSpec := range legacy.ReplicationSpecs {
62+
replicationSpec := &mdbv1.AdvancedReplicationSpec{
63+
NumShards: *convertLegacyInt64(legacyReplicationSpec.NumShards),
64+
ZoneName: legacyReplicationSpec.ZoneName,
6565
RegionConfigs: []*mdbv1.AdvancedRegionConfig{},
6666
}
6767

68-
for legacyRegion, legacyRegionConfig := range legacyResplicationSpec.RegionsConfig {
68+
for legacyRegion, legacyRegionConfig := range legacyReplicationSpec.RegionsConfig {
6969
regionConfig := mdbv1.AdvancedRegionConfig{
7070
AnalyticsSpecs: &mdbv1.Specs{
7171
DiskIOPS: legacy.ProviderSettings.DiskIOPS,
@@ -92,10 +92,10 @@ func convertLegacyReplicationSpecs(legacy *mdbv1.DeploymentSpec) ([]*mdbv1.Advan
9292
RegionName: legacyRegion,
9393
}
9494

95-
resplicationSpec.RegionConfigs = append(resplicationSpec.RegionConfigs, &regionConfig)
95+
replicationSpec.RegionConfigs = append(replicationSpec.RegionConfigs, &regionConfig)
9696
}
9797

98-
result = append(result, resplicationSpec)
98+
result = append(result, replicationSpec)
9999
}
100100

101101
return result, nil

pkg/controller/atlasdeployment/region_configuration.go

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,20 @@ func syncRegionConfiguration(deploymentSpec *mdbv1.AdvancedDeploymentSpec, atlas
3939
// When compute auto-scaling is enabled, unset instance size to avoid override production workload
4040
if isComputeAutoScalingEnabled(regionSpec.AutoScaling) {
4141
if !regionsHasChanged {
42-
regionSpec.ElectableSpecs.InstanceSize = ""
43-
regionSpec.ReadOnlySpecs.InstanceSize = ""
44-
regionSpec.AnalyticsSpecs.InstanceSize = ""
42+
for _, arc := range atlasCluster.ReplicationSpecs[0].RegionConfigs {
43+
if arc.RegionName == regionSpec.RegionName {
44+
if regionSpec.ElectableSpecs != nil && arc.ElectableSpecs != nil {
45+
regionSpec.ElectableSpecs.InstanceSize = arc.ElectableSpecs.InstanceSize
46+
}
47+
if regionSpec.ReadOnlySpecs != nil && arc.ReadOnlySpecs != nil {
48+
regionSpec.ReadOnlySpecs.InstanceSize = arc.ReadOnlySpecs.InstanceSize
49+
}
50+
if regionSpec.AnalyticsSpecs != nil && arc.AnalyticsSpecs != nil {
51+
regionSpec.AnalyticsSpecs.InstanceSize = arc.AnalyticsSpecs.InstanceSize
52+
}
53+
break
54+
}
55+
}
4556
}
4657
} else {
4758
if regionSpec.AutoScaling != nil {
@@ -86,28 +97,55 @@ func regionsConfigHasChanged(deploymentRegions []*mdbv1.AdvancedRegionConfig, at
8697

8798
mapDeploymentRegions := map[string]*mdbv1.AdvancedRegionConfig{}
8899
for _, region := range deploymentRegions {
100+
// do not compare instance sizes when autoscaling is ON
101+
if isComputeAutoScalingEnabled(region.AutoScaling) {
102+
region = ignoreInstanceSize(region.DeepCopy())
103+
}
89104
mapDeploymentRegions[region.RegionName] = region
90105
}
91106

92107
for _, region := range atlasRegions {
93-
if _, ok := mapDeploymentRegions[region.RegionName]; !ok {
108+
k8sRegion, ok := mapDeploymentRegions[region.RegionName]
109+
if !ok {
94110
return true
95111
}
96112

97113
var atlasAsOperatorRegion mdbv1.AdvancedRegionConfig
98-
err := compat.JSONCopy(&atlasAsOperatorRegion, region)
114+
var atlasRegion = &atlasAsOperatorRegion
115+
err := compat.JSONCopy(atlasRegion, region)
99116
if err != nil {
100117
return true
101118
}
102119

103-
if cmp.Diff(mapDeploymentRegions[region.RegionName], &atlasAsOperatorRegion) != "" {
120+
// do not compare instance sizes when autoscaling is ON
121+
if isComputeAutoScalingEnabled(k8sRegion.AutoScaling) {
122+
atlasRegion = ignoreInstanceSize(atlasRegion.DeepCopy())
123+
}
124+
125+
if diff := cmp.Diff(k8sRegion, atlasRegion); diff != "" {
104126
return true
105127
}
106128
}
107129

108130
return false
109131
}
110132

133+
func ignoreInstanceSize(rc *mdbv1.AdvancedRegionConfig) *mdbv1.AdvancedRegionConfig {
134+
if rc == nil {
135+
return rc
136+
}
137+
if rc.ElectableSpecs != nil {
138+
rc.ElectableSpecs.InstanceSize = ""
139+
}
140+
if rc.ReadOnlySpecs != nil {
141+
rc.ReadOnlySpecs.InstanceSize = ""
142+
}
143+
if rc.AnalyticsSpecs != nil {
144+
rc.AnalyticsSpecs.InstanceSize = ""
145+
}
146+
return rc
147+
}
148+
111149
func normalizeSpecs(regions []*mdbv1.AdvancedRegionConfig) {
112150
for _, region := range regions {
113151
if region == nil {

0 commit comments

Comments
 (0)