Skip to content

Commit b3ea899

Browse files
authored
CLOUDP-324655 - fix MongoDBMultiCluster not ready if clusterSpecList contains 0 members (#484)
# Summary Fixes issue in `MongoDBMultiCluster` not ready if `clusterSpecList` contains 0 members. ## Proof of Work Passing CI with new test case where we scale down to 0 members in one cluster. ## Checklist - [x] Have you linked a jira ticket and/or is the ticket in the title? - [x] Have you checked whether your jira ticket required DOCSP changes? - [x] Have you added changelog file? - use `skip-changelog` label if not needed - refer to [Changelog files and Release Notes](https://github.com/mongodb/mongodb-kubernetes/blob/master/CONTRIBUTING.md#changelog-files-and-release-notes) section in CONTRIBUTING.md for more details
1 parent dfb9424 commit b3ea899

File tree

3 files changed

+41
-27
lines changed

3 files changed

+41
-27
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
kind: fix
3+
date: 2025-10-01
4+
---
5+
6+
* **MongoDBMultiCluster**: fix resource stuck in Pending state if any `clusterSpecList` item has 0 members. After the fix, a value of 0 members is handled correctly, similarly to how it's done in the **MongoDB** resource.

controllers/operator/mongodbmultireplicaset_controller.go

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -235,23 +235,13 @@ func (r *ReconcileMongoDbMultiReplicaSet) Reconcile(ctx context.Context, request
235235
return r.updateStatus(ctx, &mrs, workflow.Failed(xerrors.Errorf("Failed to set annotation: %w", err)), log)
236236
}
237237

238-
// for purposes of comparison, we don't want to compare entries with 0 members since they will not be present
239-
// as a desired entry.
240238
desiredSpecList := mrs.GetDesiredSpecList()
241239
actualSpecList, err := mrs.GetClusterSpecItems()
242240
if err != nil {
243241
return r.updateStatus(ctx, &mrs, workflow.Failed(err), log)
244242
}
245243

246-
effectiveSpecList := filterClusterSpecItem(actualSpecList, func(item mdb.ClusterSpecItem) bool {
247-
return item.Members > 0
248-
})
249-
250-
// sort both actual and desired to match the effective and desired list version before comparing
251-
sortClusterSpecList(desiredSpecList)
252-
sortClusterSpecList(effectiveSpecList)
253-
254-
needToRequeue := !clusterSpecListsEqual(effectiveSpecList, desiredSpecList)
244+
needToRequeue := !clusterSpecListsEqual(actualSpecList, desiredSpecList)
255245
if needToRequeue {
256246
return r.updateStatus(ctx, &mrs, workflow.Pending("MongoDBMultiCluster deployment is not yet ready, requeuing reconciliation."), log)
257247
}
@@ -1276,26 +1266,39 @@ func (r *ReconcileMongoDbMultiReplicaSet) deleteManagedResources(ctx context.Con
12761266
return errs
12771267
}
12781268

1279-
// filterClusterSpecItem filters items out of a list based on provided predicate.
1280-
func filterClusterSpecItem(items mdb.ClusterSpecList, fn func(item mdb.ClusterSpecItem) bool) mdb.ClusterSpecList {
1281-
var result mdb.ClusterSpecList
1282-
for _, item := range items {
1283-
if fn(item) {
1284-
result = append(result, item)
1285-
}
1286-
}
1287-
return result
1288-
}
1289-
12901269
func sortClusterSpecList(clusterSpecList mdb.ClusterSpecList) {
12911270
sort.SliceStable(clusterSpecList, func(i, j int) bool {
12921271
return clusterSpecList[i].ClusterName < clusterSpecList[j].ClusterName
12931272
})
12941273
}
12951274

12961275
func clusterSpecListsEqual(effective, desired mdb.ClusterSpecList) bool {
1276+
// for purposes of comparison, we don't want to compare entries with 0 members
1277+
effective = filterClusterSpecItem(effective, func(item mdb.ClusterSpecItem) bool {
1278+
return item.Members > 0
1279+
})
1280+
desired = filterClusterSpecItem(desired, func(item mdb.ClusterSpecItem) bool {
1281+
return item.Members > 0
1282+
})
1283+
1284+
// sort both actual and desired to match the effective and desired list version before comparing
1285+
sortClusterSpecList(effective)
1286+
sortClusterSpecList(desired)
1287+
12971288
comparer := cmp.Comparer(func(x, y automationconfig.MemberOptions) bool {
12981289
return true
12991290
})
1291+
13001292
return cmp.Equal(effective, desired, comparer)
13011293
}
1294+
1295+
// filterClusterSpecItem filters items out of a list based on provided predicate.
1296+
func filterClusterSpecItem(items mdb.ClusterSpecList, fn func(item mdb.ClusterSpecItem) bool) mdb.ClusterSpecList {
1297+
var result mdb.ClusterSpecList
1298+
for _, item := range items {
1299+
if fn(item) {
1300+
result = append(result, item)
1301+
}
1302+
}
1303+
return result
1304+
}

docker/mongodb-kubernetes-tests/tests/multicluster/multi_cluster_replica_set_scale_down.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import kubernetes
44
import pytest
5+
from kubetester import try_load
56
from kubetester.automation_config_tester import AutomationConfigTester
67
from kubetester.certs_mongodb_multi import create_multi_cluster_mongodb_tls_certs
78
from kubetester.kubetester import fixture as yaml_fixture
@@ -59,7 +60,10 @@ def server_certs(
5960

6061
@pytest.fixture(scope="module")
6162
def mongodb_multi(mongodb_multi_unmarshalled: MongoDBMulti, server_certs: str) -> MongoDBMulti:
62-
return mongodb_multi_unmarshalled.create()
63+
if try_load(mongodb_multi_unmarshalled):
64+
return mongodb_multi_unmarshalled
65+
66+
return mongodb_multi_unmarshalled.update()
6367

6468

6569
@pytest.mark.e2e_multi_cluster_replica_set_scale_down
@@ -101,8 +105,9 @@ def test_ops_manager_has_been_updated_correctly_before_scaling():
101105
def test_scale_mongodb_multi(mongodb_multi: MongoDBMulti):
102106
mongodb_multi.load()
103107
mongodb_multi["spec"]["clusterSpecList"][0]["members"] = 1
104-
mongodb_multi["spec"]["clusterSpecList"][1]["members"] = 1
105-
mongodb_multi["spec"]["clusterSpecList"][2]["members"] = 1
108+
# Testing scaling down to zero is required to test fix for https://jira.mongodb.org/browse/CLOUDP-324655
109+
mongodb_multi["spec"]["clusterSpecList"][1]["members"] = 0
110+
mongodb_multi["spec"]["clusterSpecList"][2]["members"] = 2
106111
mongodb_multi.update()
107112

108113
mongodb_multi.assert_reaches_phase(Phase.Running, timeout=1800)
@@ -120,11 +125,11 @@ def test_statefulsets_have_been_scaled_down_correctly(
120125

121126
cluster_two_client = member_cluster_clients[1]
122127
cluster_two_sts = statefulsets[cluster_two_client.cluster_name]
123-
assert cluster_two_sts.status.ready_replicas == 1
128+
assert cluster_two_sts.status.ready_replicas is None
124129

125130
cluster_three_client = member_cluster_clients[2]
126131
cluster_three_sts = statefulsets[cluster_three_client.cluster_name]
127-
assert cluster_three_sts.status.ready_replicas == 1
132+
assert cluster_three_sts.status.ready_replicas == 2
128133

129134

130135
@pytest.mark.e2e_multi_cluster_replica_set_scale_down

0 commit comments

Comments
 (0)