Skip to content

Commit f89b4b3

Browse files
committed
fix: replica-ready probe must authenticate (clear leaked NOPASSWORD)
wait_until_replica_ready connects as the sandbox user, but init_slaves exports NOPASSWORD=1 for the root steps and that leaked into the probe: 'use' then drops the password, so SELECT 1 fails with Access denied even once the user exists, and the poll burned its full ~20s budget on every replication deploy. Clear NOPASSWORD for the probe so it authenticates and returns as soon as the replica is actually ready (~1-2s).
1 parent 5520307 commit f89b4b3

4 files changed

Lines changed: 27 additions & 3 deletions

File tree

sandbox/templates/replication/init_slaves.gotxt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ cd "$SBDIR"
1212
# initialization to prevent the race where the first client command on a
1313
# just-started replica fails with "Access denied" or connection errors.
1414
# Observed especially with MySQL 8.4+ and 9.x.
15+
# NOTE: init_slaves exports NOPASSWORD=1 for the root steps; that must NOT
16+
# leak into this probe, or 'use' would drop the sandbox-user password and the
17+
# check would fail with "Access denied" even once the user exists (burning the
18+
# whole budget). Clear NOPASSWORD for the probe so it authenticates normally.
1519
wait_until_replica_ready() {
1620
local use_cmd=${1:-$SBDIR/use}
1721
local max_attempts=${2:-20}
1822
local sleep_sec=${3:-1}
1923
for i in $(seq 1 $max_attempts); do
20-
if $use_cmd -BN -e "SELECT 1;" >/dev/null 2>&1 ; then
24+
if NOPASSWORD= $use_cmd -BN -e "SELECT 1;" >/dev/null 2>&1 ; then
2125
return 0
2226
fi
2327
sleep $sleep_sec

sandbox/templates/replication/init_slaves_84.gotxt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ cd "$SBDIR"
1313
# initialization to prevent the race where the first client command on a
1414
# just-started replica fails with "Access denied" or connection errors.
1515
# Observed especially with MySQL 8.4+ and 9.x.
16+
# NOTE: init_slaves exports NOPASSWORD=1 for the root steps; that must NOT
17+
# leak into this probe, or 'use' would drop the sandbox-user password and the
18+
# check would fail with "Access denied" even once the user exists (burning the
19+
# whole budget). Clear NOPASSWORD for the probe so it authenticates normally.
1620
wait_until_replica_ready() {
1721
local use_cmd=${1:-$SBDIR/use}
1822
local max_attempts=${2:-20}
1923
local sleep_sec=${3:-1}
2024
for i in $(seq 1 $max_attempts); do
21-
if $use_cmd -BN -e "SELECT 1;" >/dev/null 2>&1 ; then
25+
if NOPASSWORD= $use_cmd -BN -e "SELECT 1;" >/dev/null 2>&1 ; then
2226
return 0
2327
fi
2428
sleep $sleep_sec

sandbox/templates/single/sb_include.gotxt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,17 @@ function wait_until_wsrep_ready
148148
# just-started replica fails with "Access denied" or connection errors.
149149
# Observed especially with MySQL 8.4+ and 9.x.
150150
# Usage: wait_until_replica_ready "$SBDIR/s1/use" 20 1
151+
# NOTE: callers (e.g. init_slaves) may export NOPASSWORD=1 for root steps; it
152+
# must not leak into this probe, or 'use' would drop the sandbox-user password
153+
# and the check would fail with "Access denied" even once the user exists.
154+
# Clear NOPASSWORD for the probe so it authenticates normally.
151155
function wait_until_replica_ready
152156
{
153157
local use_cmd=${1:-$SBDIR/use}
154158
local max_attempts=${2:-20}
155159
local sleep_sec=${3:-1}
156160
for i in $(seq 1 $max_attempts); do
157-
if $use_cmd -BN -e "SELECT 1;" >/dev/null 2>&1 ; then
161+
if NOPASSWORD= $use_cmd -BN -e "SELECT 1;" >/dev/null 2>&1 ; then
158162
return 0
159163
fi
160164
sleep $sleep_sec

sandbox/templates_flavor_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,13 @@ func TestInitSlavesTemplates_IncludeReplicaReadyWait(t *testing.T) {
245245
if !strings.Contains(result, expectedWarning) {
246246
t.Errorf("%s template must include a timeout warning message", name)
247247
}
248+
// The probe must clear NOPASSWORD so it authenticates as the sandbox
249+
// user. init_slaves exports NOPASSWORD=1 for the root steps; if it leaks
250+
// into the probe, 'use' drops the password and the check fails with
251+
// "Access denied" for the whole budget (~20s wasted on every deploy).
252+
if !strings.Contains(result, `NOPASSWORD= $use_cmd -BN -e "SELECT 1;"`) {
253+
t.Errorf("%s template must clear NOPASSWORD for the replica-ready probe", name)
254+
}
248255
}
249256
}
250257

@@ -328,4 +335,9 @@ func TestSbInclude_WaitUntilReplicaReady_BoundedWait(t *testing.T) {
328335
t.Errorf("wait_until_replica_ready max_attempts should be 20 to keep total wait ≤ %ds",
329336
maxAllowedWaitSeconds)
330337
}
338+
// The probe must clear NOPASSWORD so it authenticates as the sandbox user
339+
// (callers such as init_slaves export NOPASSWORD=1 for the root steps).
340+
if !strings.Contains(result, `NOPASSWORD= $use_cmd -BN -e "SELECT 1;"`) {
341+
t.Error("wait_until_replica_ready must clear NOPASSWORD for the probe, or it fails with Access denied and burns the whole budget")
342+
}
331343
}

0 commit comments

Comments
 (0)