Skip to content

Commit 026ff16

Browse files
committed
🐛 ensure mongodb secondaries always get votes:1 and priority:1
Issue: ZENKO-5302
1 parent 5336705 commit 026ff16

1 file changed

Lines changed: 43 additions & 19 deletions

File tree

  • solution-base/images/mongodb-sharded/debian-12/rootfs/opt/bitnami/scripts

solution-base/images/mongodb-sharded/debian-12/rootfs/opt/bitnami/scripts/libmongodb.sh

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -934,21 +934,40 @@ mongodb_configure_secondary_node_voting() {
934934
local -r node="${1:?node is required}"
935935
local -r port="${2:?port is required}"
936936

937-
debug "Granting voting rights to the node"
937+
debug "Ensuring the node has full voting rights (votes: 1, priority: 1)"
938938
local reconfig_cmd="rs.reconfigForPSASet(member, cfg)"
939939
[[ "$(mongodb_get_version)" =~ ^4\.(0|2)\. ]] && reconfig_cmd="rs.reconfig(cfg)"
940-
result=$(
941-
mongodb_execute_print_output "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" "$MONGODB_INITIAL_PRIMARY_HOST" "$MONGODB_INITIAL_PRIMARY_PORT_NUMBER" <<EOF
940+
# Idempotent: skip the reconfig when the node already has full voting rights.
941+
# rs.reconfigForPSASet applies the change in two internal steps (first
942+
# votes: 1 / priority: 0, then priority: 1); if a previous run was
943+
# interrupted between the two steps the member can be left at
944+
# votes: 1 / priority: 0, so we must be able to re-run and finish the job.
945+
mongodb_execute_print_output "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" "$MONGODB_INITIAL_PRIMARY_HOST" "$MONGODB_INITIAL_PRIMARY_PORT_NUMBER" <<EOF
942946
cfg = rs.conf()
943947
member = cfg.members.findIndex(m => m.host === '$node:$port')
944-
cfg.members[member].priority = 1
945-
cfg.members[member].votes = 1
946-
$reconfig_cmd
948+
if (member === -1) {
949+
print('node-not-in-replicaset')
950+
} else if (cfg.members[member].votes === 1 && cfg.members[member].priority === 1) {
951+
print('voting-already-configured')
952+
} else {
953+
cfg.members[member].priority = 1
954+
cfg.members[member].votes = 1
955+
$reconfig_cmd
956+
}
957+
EOF
958+
959+
# Verify the node actually ended up as a full voting member. The retry_while
960+
# wrapper around this function re-runs it until this check passes, so a
961+
# partially applied reconfig converges to votes: 1 / priority: 1.
962+
result=$(
963+
mongodb_execute_print_output "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" "$MONGODB_INITIAL_PRIMARY_HOST" "$MONGODB_INITIAL_PRIMARY_PORT_NUMBER" <<EOF
964+
m = rs.conf().members.find(m => m.host === '$node:$port')
965+
print(m && m.votes === 1 && m.priority === 1 ? 'voting-ok' : 'voting-pending')
947966
EOF
948967
)
949968
debug "$result"
950969

951-
grep -q "ok: 1" <<<"$result"
970+
grep -q "voting-ok" <<<"$result"
952971
}
953972

954973
########################
@@ -1194,21 +1213,22 @@ mongodb_configure_secondary() {
11941213
error "Secondary node did not get marked as secondary"
11951214
exit 1
11961215
fi
1216+
fi
11971217

1198-
# Grant voting rights to node
1199-
# https://docs.mongodb.com/manual/tutorial/modify-psa-replica-set-safely/
1200-
if ! retry_while "mongodb_configure_secondary_node_voting $node $port" "$MONGODB_INIT_RETRY_ATTEMPTS" "$MONGODB_INIT_RETRY_DELAY"; then
1201-
error "Secondary node did not get marked as secondary"
1202-
exit 1
1203-
fi
1218+
# Always grant voting rights, whether the node was just added or was already
1219+
# a member. This guarantees the replica set converges to votes: 1 / priority: 1
1220+
# for every secondary, even if a previous run was interrupted before this step.
1221+
# https://docs.mongodb.com/manual/tutorial/modify-psa-replica-set-safely/
1222+
if ! retry_while "mongodb_configure_secondary_node_voting $node $port" "$MONGODB_INIT_RETRY_ATTEMPTS" "$MONGODB_INIT_RETRY_DELAY"; then
1223+
error "Secondary node did not get full voting rights (votes: 1, priority: 1)"
1224+
exit 1
1225+
fi
12041226

1205-
# Mark node as readable. This is necessary in cases where the PVC is lost
1206-
if is_boolean_yes "$MONGODB_SET_SECONDARY_OK"; then
1207-
mongodb_execute_print_output "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" <<EOF
1227+
# Mark node as readable. This is necessary in cases where the PVC is lost
1228+
if is_boolean_yes "$MONGODB_SET_SECONDARY_OK"; then
1229+
mongodb_execute_print_output "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" <<EOF
12081230
rs.secondaryOk()
12091231
EOF
1210-
fi
1211-
12121232
fi
12131233
}
12141234

@@ -1324,8 +1344,12 @@ mongodb_node_currently_in_cluster() {
13241344
local -r port="${2:?port is required}"
13251345
local result
13261346

1347+
# Use mongodb_execute_print_output (not mongodb_execute): mongodb_execute
1348+
# wraps the call in debug_execute, which discards stdout unless BITNAMI_DEBUG
1349+
# is enabled. We need to capture rs.status() output to inspect the members,
1350+
# otherwise this check always sees an empty string and returns false.
13271351
result=$(
1328-
mongodb_execute "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" "$MONGODB_INITIAL_PRIMARY_HOST" "$MONGODB_INITIAL_PRIMARY_PORT_NUMBER" <<EOF
1352+
mongodb_execute_print_output "$MONGODB_INITIAL_PRIMARY_ROOT_USER" "$MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD" "admin" "$MONGODB_INITIAL_PRIMARY_HOST" "$MONGODB_INITIAL_PRIMARY_PORT_NUMBER" <<EOF
13291353
rs.status().members
13301354
EOF
13311355
)

0 commit comments

Comments
 (0)