Skip to content

test(mysql): combine open PRs for full-suite validation#3185

Draft
weicao wants to merge 63 commits into
mainfrom
william/mysql-open-pr-combined
Draft

test(mysql): combine open PRs for full-suite validation#3185
weicao wants to merge 63 commits into
mainfrom
william/mysql-open-pr-combined

Conversation

@weicao

@weicao weicao commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Purpose

This draft combines current main with all 18 open MySQL addon PR heads into one immutable candidate for full-suite testing. It is a test-integration branch, not a replacement for individual review and merge histories.

Combined exact head: ec4aa4c96e440fe0aa948e8f422eeab690ef8872

Included PR Heads

PR Exact head
#3182 a5e5aa1480266316f281628ff393443a21515abb
#3156 e5752c2517dfc5e53e49c10729be154d1f807d7e
#3154 87b7d1518771e9936d31b930f46090928d4899e5
#3159 8f0ed5193d25073584fdf1eb4fb19eafab2c1e8f
#3155 64b9be0c6abe270b125de0a9055ae4f9956165dd
#3117 86c7cea083adc5031b5ed8d2c317a6c552046f8f
#3098 a4cb93ee4d1e2c881b00a9c969329c2478b13760
#3096 7c66d01e44f74fc4067a8f5ed1d7bca1318cb340
#3094 7ede4e9cba72f1a8378752b26bf62a6e1facded2
#3092 6f755a38b844692b294f98e97ac4b93e4b942ddf
#3090 630347dda2bd606c1a435ee489223d3016a1ce07
#3088 774786e5dbd1aa0b54e15393e30b379bbd613722
#3086 db05fdc8cacc253bc5d3fabeec51371a7427bbc3
#3084 e59e22166bad945de154c760c69ff583aaa01fb8
#3082 c8812387d95bf65abea4d8dd8119a0144e75ddfc
#3080 628235157da8be06b4bd48b04391bce121ede13c
#3078 e14f15570c5298d2736b7c947e3a2193924aa04b
#3076 be278d433bf475e7721121cf403117272f3b2bb3

A machine-generated ancestry table verifies all 18 current exact heads are ancestors of the combined commit (missing=0).

Conflict Resolution

Only #3078 overlapped after the other 17 original merges, in addons/mysql/scripts/orc-switchover.sh against #3117. The resolution preserves both contracts:

  • Orchestrator precheck and command errors fail closed and cannot be mistaken for topology output.
  • Orchestrator calls are bounded; a command nonzero is accepted only when the same bounded invocation proves the requested state already converged.
  • Switchover completion requires bounded topology plus MySQL read-only-state convergence.

The later #3182 compatibility fix merged cleanly and introduced versioned xtrabackup ActionSets; it did not alter this conflict resolution.

Local Gates

  • MySQL ShellSpec: 79 examples, 0 failures
  • helm lint addons/mysql: PASS
  • full MySQL chart render: PASS, 14,952 lines
  • Bash syntax for all 28 changed MySQL shell files: PASS
  • ShellCheck severity=error for all 28 changed MySQL shell files: PASS
  • git diff --check: PASS
  • conflict-marker scan: PASS
  • current 18-head ancestry: 18/18 PASS

Exact combined chart package:

  • mysql-1.2.0-alpha.0.tgz
  • SHA256 c60cf22421b0dc084cd0769ea4d2a28d69a61820964f177f7b1a78f59f8eaeb3
  • 100 archive entries

Review Focus

Evidence Boundary

Runtime full-suite evidence remains N=0 until the test owner launches this exact packaged combined commit. Local and CI gates do not establish runtime acceptance or release readiness. Testing remains HOLD until #3182 and this combined head/package receive exact-head review and both PR CIs are terminal green.

wei and others added 30 commits July 13, 2026 20:52
…shutdown

proxysql-entry.sh backgrounded proxysql with `exec proxysql ... &` then `wait`,
with no signal trap. On pod termination the wrapper (the container init process)
received SIGTERM but never forwarded it to proxysql, so proxysql kept running
until the termination grace period elapsed and was then SIGKILLed. This slows
down / flaps scale-in, rolling-update, and delete tests. The mysql container
already traps and forwards; proxysql should too (same class as #3090).

- Install a `term_handler` trap on SIGTERM/SIGINT as the first thing in the main
  path (pid initialized to 0) so a signal during startup — config rendering,
  spawn, or the configure helper — is handled instead of the default kill.
- The handler forwards TERM to the proxysql pid, reaps it exactly once, and
  exits, so the main path never runs a second `wait` (which would exit 127
  "not a child" under set -e).
- Drop the misleading `exec ... &` (exec cannot replace the shell for a
  backgrounded job) and the false "PID 1" comment; run proxysql as a child so
  the wrapper stays alive to forward signals.
- Quote the FRONTEND_TLS_ENABLED test so an unset value is not a set -e syntax
  error.
- Make the config helper / template / output paths overridable (in-image
  defaults unchanged) so the signal contract can be exercised end-to-end.

Tests (scripts-ut-spec/proxysql_entry_spec.sh):
- end-to-end: a real proxysql-stub child receives SIGTERM and the wrapper exits 0
  (deterministic: waits until the child signals readiness before sending TERM);
- double-wait guard: term_handler exits rather than falling through to a second
  wait (fails against a return-instead-of-exit handler);
- trap installed before the proxysql spawn line;
- term_handler forwards `kill -TERM <pid>` and is a no-op when no pid captured.
…ent-only admin creds

mysql-myloader.sh connected with ${MYSQL_ADMIN_USER}/${MYSQL_ADMIN_PASSWORD},
but those are component-container env (credentialVarRef in _helpers.tpl) and are
not injected into the DataProtection restore job. The backup side
(mysql-mydumper.sh) already uses ${DP_DB_USER}/${DP_DB_PASSWORD}, and the same
myloader line already relies on the DP-injected ${DP_DB_HOST}/${DP_DB_PORT}, so
the user/password should come from the same DP connection env. With the admin
vars empty in the restore job, myloader fails authentication and the
mydumper/myloader logical restore fails.

Align the restore credentials with the backup side and add a shellspec that
asserts myloader is invoked with DP_DB_USER/DP_DB_PASSWORD and never references
MYSQL_ADMIN_*.
accountProvision can be retried by the controller/kbagent; CREATE USER
without IF NOT EXISTS fails with ERROR 1396 on re-execution and the
provision never converges. Align kbdataprotection/kbprobe/kbmonitoring/
proxysql with the orc variant's CREATE USER IF NOT EXISTS.

Fixes #3097

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ls closed

Target KB_LEAVE_MEMBER_POD_NAME (05b memberLeave contract) instead of
the execution pod's name, falling back only when unset. Verify
Orchestrator reachability before interpreting an empty instance query
as "forgotten" - an Orchestrator outage previously made scale-in
report success without deregistering the member.

Fixes #3095

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'default .Values.image.pullPolicy "IfNotPresent"' puts the fallback
second, so it always yielded IfNotPresent and the values key was
silently ignored at 20+ container sites; the exporter helper hardcoded
it outright. Normalize every site to
'default "IfNotPresent" .Values.image.pullPolicy'.

Fixes #3093

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Group Replication is majority-based; the MGR cmpds inherited the
semisync roles block with participatesInQuorum=false, giving KubeBlocks
no signal to preserve majority during parallel updates. Extract the
roles block from mysql.spec.common into per-topology helpers: semisync
keeps the previous declaration verbatim, MGR declares quorum
participation.

Fixes #3091

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The orc runtime wrapper backgrounds mysql-entrypoint.sh and TERMs $! on
pod stop. Without exec that signal killed the intermediate bash while
mysqld ran on orphaned until the grace-period SIGKILL, forcing InnoDB
crash recovery on every ordinary pod stop.

Fixes #3089

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fix-safe

Replica discovery relied on KB_ITS_*_HOSTNAME env that never existed in
DataProtection job pods on KB 1.x, so the >=80% disk cleanup (default
PURGE_BINLOG=on) silently never purged anything. Discover replicas from
the target primary via SHOW REPLICAS / SHOW SLAVE HOSTS instead.

Also make the master purge prefix-safe: PURGE BINARY LOGS TO is prefix
deletion, so scan stops at the first file that must be kept (not yet
synced+uploaded, or one of the newest 5) and a single PURGE TO that
file is issued - the old per-file loop could delete an unarchived
binlog sitting before a qualifying one and tear the archived sequence.
Membership tests are now exact-match instead of substring grep.

Fixes #3087

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The disk-pressure binlog purge only triggers at >=80% usage, which cannot
be safely reached on a large shared host volume in tests (would need a
~177GB fill). Make the threshold overridable via PURGE_BINLOG_DISK_THRESHOLD
(default 80, production behaviour unchanged) so a test can set it below the
current usage and exercise the real purge path without filling the disk.

Refs #3087

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
get_synced_binlogs matched replica status against a reconstructed
${DP_TARGET_POD_NAME}-bin, which fails when the target env drifts from
the actual binlog-writing pod (e.g. after a switchover) - returning
'No synced binlog files found' even when replicas are synced. Match
against LOG_PREFIX (derived from the real log_bin_basename) instead.
Add DEBUG lines printing DP_TARGET_POD_NAME/LOG_PREFIX/replica hosts and
per-replica resolved current_file, so the cleanup-decision path is
observable in the archive-binlog log.

Refs #3087

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stderr

get_replica_hosts assumed replicas register report_host, but the semisync
cmpd start command omits --report-host (only the MGR cmpd and
mysql-entrypoint.sh set it). With report_host empty, SHOW REPLICAS leaves the
Host column blank and `awk '{print $2}'` slides onto the Port, returning
"3306" as the replica host (observed: 'Processing replica host: 3306',
'Can't connect to MySQL server on 3306:3306'). Discover connected replicas
from the primary's own Binlog Dump threads instead
(information_schema.PROCESSLIST), which carry the replica ip:port regardless
of report_host; strip the ephemeral :port. Fall back to SHOW REPLICAS / SHOW
SLAVE HOSTS with TAB-split awk so an empty Host stays empty instead of
becoming the Port.

Also move the two DEBUG lines in get_synced_binlogs to stderr: that
function's stdout is captured by `synced_binlogs=$(get_synced_binlogs)`, so
echoing on stdout both hid the lines from the pod log and corrupted the
return value (making the empty result look non-empty and bypassing the
fail-closed 'No synced binlog files found' guard).

Split the `local synced_binlogs=$(...)` declaration from its assignment so
the `$? -ne 0` check reflects get_synced_binlogs' exit code rather than the
always-zero exit of `local`, keeping the fail-closed guard closed.

Refs #3087

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two data-safety defects found in a deep review of the PITR binlog cleanup.

1. The fail-closed guard `synced_binlogs=$(get_synced_binlogs); if [ $? -ne 0
   ]` is unreachable under the actionset-wide `set -e`: a separated
   `var=$(fn)` assignment where fn returns 1 aborts the whole script before
   the check, so a replica-parse failure crash-loops the archiver instead of
   logging and skipping the purge. (Splitting the earlier `local var=$(...)`
   to fix `$?` masking removed the mask that `set -e` was relying on.) Use
   `if ! synced_binlogs=$(get_synced_binlogs) || [ -z ... ]` so the failure
   is caught without tripping set -e.

2. `min_synced_file` was a leaked global, never reset. On a 2nd+ cleanup call
   in the long-lived archiver, if replica discovery returns empty the loop is
   skipped and the stale previous value passes the guard, purging binlogs on
   an unverified synced position (potential data loss). Declare it `local`
   with an empty reset at function entry.

Both verified: bash confirms the separated assignment aborts under set -e
while `if !` does not; helm render + bash -n pass.
…variables

Port the apecloud-addons paramsdef-84 structure (shared 8.0 cue + a
#MysqlParameter unification patch) and extend the rejection from
default_authentication_plugin alone to all MySQL 8.4.0-removed system
variables; filter them out of the static/dynamic/immutable lists too.
Narrow paramsdef-80's componentDef regex to 8.0 only. Also correct the
8.0 cue entry for expire_logs_days to MySQL's real range 0-99 (default
0) instead of binlog_expire_logs_seconds' default.

Fixes #3085

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The _|_ (CUE bottom) used to reject MySQL 8.4-removed variables cannot
be marshaled into an OpenAPI schema by KB 1.2.0-alpha.2, so mysql-8.4-pd
never became Available and 8.4 clusters could not provision at all - a
regression worse than the original shared-schema problem. Drop the
bottom override so the PD reuses the (range-corrected) 8.0 CUE and
becomes Available. The 8.4-removed variables remain filtered out of the
static/dynamic/immutable classification lists, and a user reconfigure of
them is rejected at runtime by update-parameter.sh fail-close on the
SET GLOBAL unknown-variable error. Strict PD schema-level rejection
(closing the open CUE struct) is deferred as a separate enhancement.

Refs #3085

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The appended #MysqlParameter{} block (added to declare authentication_policy
and, earlier, to bottom removed vars) re-declares the definition, which
closes the otherwise-open (...) shared struct. A closed #MysqlParameter is
then applied strictly to every ini section via [SectionName=_], so the
[client] section's rendered port="3306" (string) conflicts with the
schema's port?: int, failing 8.4 ComponentParameter rendering and blocking
8.4 provisioning. 8.0-pd never hit this because it has no such block. Reuse
the shared 8.0 cue verbatim: the open struct already accepts
authentication_policy, and removed-variable rejection stays at the runtime
fail-close layer plus classification-list filtering.

Refs #3085

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mic to action)

Filtering the removed variables out of all classification lists left them
unclassified, so KB routed them to the config-file (static) path where they
landed in my.cnf and crash-looped 8.4. Keep the 8.0 classification instead:
the six DYNAMIC removed variables route to update-parameter.sh, which now
rejects them by name (fail-close before write). The two STATIC removed
variables take the file path with no action to intercept them - a documented
schema-only gap pending a KB forbidden-parameter mechanism.

Refs #3085

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… apecloud-addons)

The template renders it and the effect scope lists it as dynamic, but
the cue schema had no entry, leaving reconfigure of this parameter
unvalidated. Port the enterprise-repo constraint verbatim.

Fixes #3083

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
general_log=ON logged every statement to the data PVC with no rotation:
throughput cost and unbounded disk growth. Port the enterprise-repo fix;
the parameter stays dynamic for on-demand debugging. Also resolves the
inconsistency with the 5.7 cue default *"OFF".

Fixes #3081

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Previously only ERROR 1045 failed the reconfigure exec action; every
other error (unknown variable, invalid value, connection failure) was
silently ignored and the Ops reported success while the running value
never changed. Now tolerate exactly the two legitimate cannot-apply-
online cases with explicit logs (1238 read-only -> effective after
restart via rendered my.cnf; 1193 on loose_-prefixed params -> plugin
not loaded), and exit non-zero on everything else. loose_ prefix strip
is now anchored to the prefix instead of a global substitution.

Fixes #3079

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
10 cases: numeric/suffix/quoting/dash-normalization apply paths with
query capture, tolerated 1238 and loose_+1193 paths, and hard-failure
paths (bare 1193, 1231, 1045, 2003).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A reconfigure of a variable removed in MySQL 8.4 (expire_logs_days,
master_info_repository, etc.) previously fell through to the config file
path and landed in my.cnf, crash-looping 8.4 on restart. Reject such a
request by name before SET GLOBAL when the server is >= 8.4, with a clear
reason surfaced in the action output. The SET GLOBAL unknown-variable
error remains a backstop; 8.0 keeps the legacy variables valid. Adds
ShellSpec coverage for 8.4-reject / 8.4-accept-non-removed / 8.0-legacy.

Refs #3085

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…achable

Stop merging orchestrator-client stderr into command substitutions:
error text was parsed as a master name / instance list, making the two
skip-guards exit 0 and a failed switchover report success. Check the
client exit code explicitly and exit non-zero on query failure; count
instances from non-empty lines only; include the real exit code in the
failure message.

Fixes #3077

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two log lines printed the root password verbatim, and the mysql_users
INSERT carrying the password was executed with -vvv which echoes the
statement to stdout. Log user/host/port only and drop -vvv from the
password-bearing statement.

Fixes #3075

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wei added 24 commits July 13, 2026 21:04
# Conflicts:
#	addons/mysql/scripts/orc-switchover.sh
@weicao weicao added the nopick Not auto cherry-pick when PR merged label Jul 13, 2026
@codecov-commenter

codecov-commenter commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 773 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.00%. Comparing base (b55707f) to head (ec4aa4c).

Files with missing lines Patch % Lines
...s-ut-spec/xtrabackup_action_image_contract_spec.sh 0.00% 221 Missing ⚠️
...ddons/mysql/scripts-ut-spec/orc_switchover_spec.sh 0.00% 137 Missing ⚠️
...ons/mysql/scripts-ut-spec/update_parameter_spec.sh 0.00% 113 Missing ⚠️
...ddons/mysql/scripts-ut-spec/orc_role_probe_spec.sh 0.00% 64 Missing ⚠️
...ddons/mysql/scripts-ut-spec/proxysql_entry_spec.sh 0.00% 55 Missing ⚠️
...ons/mysql/scripts-ut-spec/orc_api_contract_spec.sh 0.00% 44 Missing ⚠️
...ns/mysql/scripts-ut-spec/restore_preflight_spec.sh 0.00% 31 Missing ⚠️
...ddons/mysql/scripts-ut-spec/mysql_myloader_spec.sh 0.00% 30 Missing ⚠️
...ons/mysql/scripts-ut-spec/orc_preterminate_spec.sh 0.00% 29 Missing ⚠️
.../mysql/scripts-ut-spec/syncer_api_contract_spec.sh 0.00% 25 Missing ⚠️
... and 1 more
Additional details and impacted files
@@          Coverage Diff           @@
##            main   #3185    +/-   ##
======================================
  Coverage   0.00%   0.00%            
======================================
  Files        147     157    +10     
  Lines      23282   24055   +773     
======================================
- Misses     23282   24055   +773     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

nopick Not auto cherry-pick when PR merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants