Skip to content

Commit c05302b

Browse files
authored
Merge pull request #5619 from sysown/fix/groups-json-orphaned-entries
fix(tests): resolve TAP test failures in multi-group runs
2 parents 8524688 + 732a65d commit c05302b

90 files changed

Lines changed: 4824 additions & 149 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/superpowers/plans/2026-04-12-infra-dbdeployer-mysql57.md

Lines changed: 990 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Design: infra-dbdeployer-mysql57 — Replace infra-mysql57 with dbdeployer
2+
3+
**Date:** 2026-04-12
4+
**Branch:** v3.0-dbdeployer01
5+
**Status:** Draft
6+
7+
## Goal
8+
9+
Replace the 6-container `infra-mysql57` (3 MySQL + 3 Orchestrator) with a single-container infra using [dbdeployer](https://github.com/ProxySQL/dbdeployer/) to run 3 MySQL 5.7 instances inside one Docker container. Orchestrator is dropped (unused by legacy tests).
10+
11+
## Why
12+
13+
- Reduce container count from 6 to 1 per MySQL infra
14+
- Faster startup and lower resource usage in CI
15+
- Orchestrator is not used by the `legacy` test group
16+
- Paves the way for a MySQL 8.4 variant using the same pattern
17+
18+
## Scope
19+
20+
**In scope:**
21+
- Docker image: Dockerfile with dbdeployer + MySQL 5.7 tarball pre-baked
22+
- Infra directory: `test/infra/infra-dbdeployer-mysql57/` with docker-compose, init/destroy, post-scripts, ProxySQL config
23+
- Self-contained: image build artifacts live inside the infra directory under `docker/`
24+
25+
**Out of scope:**
26+
- Modifying existing test groups (swap happens later)
27+
- Fixing test failures from hostname/port changes
28+
- MySQL 8.4 variant (separate follow-up)
29+
30+
## Architecture
31+
32+
### Current: infra-mysql57
33+
34+
```
35+
6 containers:
36+
mysql1 (mysql:5.7, port 3306, server-id=111, read_only=0) -- writer
37+
mysql2 (mysql:5.7, port 3306, server-id=222, read_only=1) -- replica
38+
mysql3 (mysql:5.7, port 3306, server-id=333, read_only=1) -- replica
39+
orc1, orc2, orc3 (percona-orchestrator) -- unused by legacy tests
40+
41+
Hostnames: mysql1.infra-mysql57, mysql2.infra-mysql57, mysql3.infra-mysql57
42+
All on port 3306.
43+
```
44+
45+
### New: infra-dbdeployer-mysql57
46+
47+
```
48+
1 container:
49+
dbdeployer1 (proxysql/ci-infra:dbdeployer-mysql57)
50+
mysqld node1: port 3306, writer
51+
mysqld node2: port 3307, replica
52+
mysqld node3: port 3308, replica
53+
54+
Hostname: dbdeployer1.infra-dbdeployer-mysql57
55+
Three ports: 3306, 3307, 3308.
56+
No orchestrator.
57+
```
58+
59+
### Key change for tests
60+
61+
Tests currently see 3 hostnames on port 3306. After the swap, they see 1 hostname on 3 ports. ProxySQL config (`infra-config.sql`) is updated accordingly. Some tests that connect directly to backends using `cl.mysql_host`/`cl.mysql_port` may need future updates, but that is out of scope for this branch.
62+
63+
## Directory Structure
64+
65+
```
66+
test/infra/infra-dbdeployer-mysql57/
67+
├── docker/
68+
│ ├── Dockerfile # Ubuntu base + dbdeployer + MySQL 5.7 tarball
69+
│ ├── build.sh # Builds and tags proxysql/ci-infra:dbdeployer-mysql57
70+
│ └── entrypoint.sh # Deploys replication, creates users, keeps container alive
71+
├── .env # MYSQL_VERSION=5.7, WHG=1300, RHG=1301, BHG=1302, OHG=1303
72+
├── docker-compose.yml # Single service: dbdeployer1
73+
├── docker-compose-init.bash # Common init pattern (no orchestrator patching)
74+
├── docker-compose-destroy.bash
75+
├── bin/
76+
│ ├── docker-mysql-post.bash # Waits for 3 ports, creates users if not done by entrypoint
77+
│ └── docker-proxy-post.bash # Registers backends in ProxySQL
78+
└── conf/
79+
└── proxysql/
80+
└── infra-config.sql # 1 hostname, 3 ports in mysql_servers
81+
```
82+
83+
## Docker Image Design
84+
85+
### Dockerfile (`docker/Dockerfile`)
86+
87+
- **Base**: Ubuntu 22.04
88+
- **System deps**: libaio1, libnuma1, mysql-client (for health checks)
89+
- **dbdeployer**: Download release binary from ProxySQL/dbdeployer
90+
- **MySQL 5.7 tarball**: Download and `dbdeployer unpack` at build time, so `/root/opt/mysql/5.7.x/` is ready
91+
- **entrypoint.sh**: Copied into image, set as ENTRYPOINT
92+
93+
### Entrypoint (`docker/entrypoint.sh`)
94+
95+
Runs at container startup:
96+
97+
1. **Deploy replication** (exact MySQL minor version TBD based on available tarball, e.g. `5.7.44`):
98+
```bash
99+
dbdeployer deploy replication 5.7.44 \
100+
--nodes=3 \
101+
--gtid \
102+
--bind-address=0.0.0.0 \
103+
--base-port=3306 \
104+
--my-cnf-options="log-bin,log-slave-updates,binlog_format=ROW,max_connections=500,innodb_buffer_pool_size=128M,innodb_log_file_size=32M,innodb_flush_log_at_trx_commit=2,sync_binlog=0" \
105+
--repl-crash-safe
106+
```
107+
108+
2. **Wait for all 3 mysqld processes** to accept connections (poll with mysqladmin ping or SELECT 1).
109+
110+
3. **Create test users** on all 3 nodes (same users as current `docker-mysql-post.bash`):
111+
- `root@'%'` with `$ROOT_PASSWORD` (passed via env var)
112+
- `monitor@'%'` with password `monitor`
113+
- `testuser@'%'` with password `testuser`
114+
- `$INFRA@'%'` with password `$INFRA` (infra-specific user)
115+
- `sbtest1`-`sbtest10` with matching passwords
116+
- Databases: `sysbench`, `test`, `t1`, `jdbc_test`
117+
- Grants: same as current setup
118+
119+
4. **Collect SSL certs** into bundle (same as current script, if MySQL 5.7 generates self-signed certs).
120+
121+
5. **Stay alive**: `exec sleep infinity` (or `tail -f /dev/null`)
122+
123+
### Build Script (`docker/build.sh`)
124+
125+
```bash
126+
#!/bin/bash
127+
IMAGE_TAG="${1:-proxysql/ci-infra:dbdeployer-mysql57}"
128+
docker build -t "${IMAGE_TAG}" -f Dockerfile .
129+
```
130+
131+
## Infra Runtime
132+
133+
### `.env`
134+
135+
```
136+
MYSQL_VERSION=5.7
137+
WHG=1300
138+
RHG=1301
139+
BHG=1302
140+
OHG=1303
141+
```
142+
143+
Same hostgroup IDs as `infra-mysql57` for drop-in compatibility.
144+
145+
### `docker-compose.yml`
146+
147+
Single service, no orchestrator:
148+
149+
```yaml
150+
services:
151+
dbdeployer1:
152+
hostname: dbdeployer1.${INFRA}
153+
image: proxysql/ci-infra:dbdeployer-mysql57
154+
container_name: ${COMPOSE_PROJECT}-dbdeployer1-1
155+
environment:
156+
- ROOT_PASSWORD=${ROOT_PASSWORD}
157+
- INFRA=${INFRA}
158+
networks:
159+
backend:
160+
aliases:
161+
- dbdeployer1.${INFRA}
162+
- dbdeployer1.infra-dbdeployer-mysql57
163+
164+
networks:
165+
backend:
166+
name: "${INFRA_ID}_backend"
167+
external: true
168+
```
169+
170+
### `docker-compose-init.bash`
171+
172+
Same pattern as `infra-mysql57/docker-compose-init.bash` but:
173+
- No orchestrator config patching (step 3 skipped)
174+
- No orchestrator post-script invocation
175+
- Calls `docker-mysql-post.bash` and `docker-proxy-post.bash`
176+
177+
### `docker-compose-destroy.bash`
178+
179+
Same as existing infras — `docker compose down`, cleanup log dirs.
180+
181+
### `bin/docker-mysql-post.bash`
182+
183+
Simplified compared to `infra-mysql57`:
184+
- Connects to one container (`${COMPOSE_PROJECT}-dbdeployer1-1`)
185+
- Waits for ports 3306, 3307, 3308 to accept connections
186+
- User creation is done by the entrypoint (inside the container). This script's role is to **wait** for readiness and **collect SSL cert bundles** — not to create users. This avoids a race condition where docker-mysql-post.bash runs before the entrypoint finishes user creation.
187+
- If the entrypoint signals readiness (e.g. via a marker file or healthy exit code), this script proceeds to SSL cert collection.
188+
189+
### `bin/docker-proxy-post.bash`
190+
191+
Same logic as `infra-mysql57`, but references the updated `infra-config.sql`.
192+
193+
### `conf/proxysql/infra-config.sql`
194+
195+
Key change — single hostname, 3 ports:
196+
197+
```sql
198+
-- Writer: node1 on port 3306
199+
INSERT INTO mysql_servers (hostgroup_id,hostname,port,...) VALUES (${WHG},'dbdeployer1.${INFRA}',3306,...);
200+
INSERT INTO mysql_servers (hostgroup_id,hostname,port,...) VALUES (${RHG},'dbdeployer1.${INFRA}',3306,...);
201+
202+
-- Replicas: node2 on 3307, node3 on 3308
203+
INSERT INTO mysql_servers (hostgroup_id,hostname,port,...) VALUES (${RHG},'dbdeployer1.${INFRA}',3307,...);
204+
INSERT INTO mysql_servers (hostgroup_id,hostname,port,...) VALUES (${RHG},'dbdeployer1.${INFRA}',3308,...);
205+
```
206+
207+
The rest of the SQL (users, query rules, debug filters, etc.) stays the same but with updated hostname references.
208+
209+
## Risks and Mitigations
210+
211+
| Risk | Mitigation |
212+
|------|-----------|
213+
| dbdeployer `--bind-address=0.0.0.0` may not work as expected | Test during image build; fall back to patching my.sandbox.cnf post-deploy |
214+
| `--base-port=3306` may conflict with dbdeployer's reserved ports list | Use `dbdeployer defaults update reserved-ports ''` to clear reservations |
215+
| MySQL 5.7 tarball URL may change | Pin exact version in Dockerfile, document update process |
216+
| Tests that hardcode hostname patterns like `mysql1.*` will break | Out of scope — expected and acceptable, will fix when swapping groups |
217+
| Single container = single point of failure (all 3 mysqld share fate) | Acceptable for CI testing; not a production topology |
218+
219+
## Future Work
220+
221+
- **MySQL 8.4 variant**: Same pattern, different tarball — `infra-dbdeployer84/`
222+
- **Swap legacy group**: Update `test/tap/groups/legacy/infras.lst` and `env.sh` to point to `infra-dbdeployer-mysql57`
223+
- **Fix test failures**: Address tests that assume separate hostnames per backend

test/infra/common/env-isolated.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ export DEFAULT_MYSQL_INFRA="${INFRA_TYPE:-${DEFAULT_MYSQL_INFRA:-infra-mysql84}}
3131
export DEFAULT_PGSQL_INFRA="${INFRA_TYPE:-${DEFAULT_PGSQL_INFRA:-docker-pgsql16-single}}"
3232

3333
# MySQL/MariaDB Environment Variables
34-
export TAP_MYSQLHOST="mysql1.${DEFAULT_MYSQL_INFRA}"
35-
export TAP_MYSQLPORT=3306
34+
# MYSQL_PRIMARY_HOST/PORT can be set in the infra's .env to override defaults
35+
# (e.g. dbdeployer uses "dbdeployer1" instead of "mysql1")
36+
export TAP_MYSQLHOST="${MYSQL_PRIMARY_HOST:-mysql1}.${DEFAULT_MYSQL_INFRA}"
37+
export TAP_MYSQLPORT="${MYSQL_PRIMARY_PORT:-3306}"
3638
export TAP_MYSQLUSERNAME="root"
3739
export TAP_MYSQLPASSWORD="${ROOT_PASSWORD}"
3840

test/infra/control/env-isolated.bash

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ export TAP_ADMINPORT=6032
1818
export TAP_ADMINUSERNAME="radmin"
1919
export TAP_ADMINPASSWORD="radmin"
2020

21-
# NO HARDCODED DEFAULTS HERE
22-
# These must be provided by run-tests-isolated.bash or group env.sh
21+
# NOTE: TAP_MYSQLHOST/PORT are set later (after infra .env is sourced)
22+
# so that infra-specific overrides like MYSQL_PRIMARY_HOST take effect.
2323
if [ -n "${DEFAULT_MYSQL_INFRA}" ]; then
24-
export TAP_MYSQLHOST="mysql1.${DEFAULT_MYSQL_INFRA}"
25-
export TAP_MYSQLPORT=3306
2624
export TAP_MYSQLUSERNAME="root"
2725
export TAP_MYSQLPASSWORD="${ROOT_PASSWORD}"
2826
fi
@@ -125,9 +123,20 @@ export TEST_PY_TAP_EXCL="${TEST_PY_TAP_EXCL:-reg_test_3273_ssl_con-t}"
125123
export TEST_PY_TAPINT_INCL="${TEST_PY_TAPINT_INCL:-}"
126124
export TEST_PY_TAPINT_EXCL="${TEST_PY_TAPINT_EXCL:-}"
127125

128-
# Source infra-specific environment (exports WHG, RHG, and TAP test variables)
129-
if [ -n "${INFRA_TYPE}" ] && [ -f "${WORKSPACE}/test/infra/${INFRA_TYPE}/.env" ]; then
130-
source "${WORKSPACE}/test/infra/${INFRA_TYPE}/.env"
126+
# Source infra-specific environments (exports WHG, RHG, MYSQL_PRIMARY_HOST, etc.)
127+
# INFRA_TYPE is set by binlog/special groups; DEFAULT_MYSQL_INFRA by all MySQL groups
128+
for _infra_env in "${INFRA_TYPE}" "${DEFAULT_MYSQL_INFRA}"; do
129+
if [ -n "${_infra_env}" ] && [ -f "${WORKSPACE}/test/infra/${_infra_env}/.env" ]; then
130+
source "${WORKSPACE}/test/infra/${_infra_env}/.env"
131+
fi
132+
done
133+
unset _infra_env
134+
135+
# Set TAP_MYSQLHOST/PORT after sourcing infra .env so that MYSQL_PRIMARY_HOST/PORT
136+
# overrides take effect (e.g. dbdeployer uses "dbdeployer1" instead of "mysql1")
137+
if [ -n "${DEFAULT_MYSQL_INFRA}" ]; then
138+
export TAP_MYSQLHOST="${MYSQL_PRIMARY_HOST:-mysql1}.${DEFAULT_MYSQL_INFRA}"
139+
export TAP_MYSQLPORT="${MYSQL_PRIMARY_PORT:-3306}"
131140
fi
132141

133142
echo ">>> Isolated Environment Loaded (INFRA_ID: ${INFRA_ID})"

test/infra/control/run-tests-isolated.bash

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,6 @@ chmod 777 "${TESTS_LOGS_PATH_HOST}"
269269

270270
# Find binaries
271271
MYSQL_BINLOG_BIN=$(find "${WORKSPACE}" -path "${WORKSPACE}/ci_infra_logs" -prune -o -path "${WORKSPACE}/.git" -prune -o -name "mysqlbinlog" -type f -executable -print | head -n 1)
272-
BINLOG_READER_BIN=$(find "${WORKSPACE}" -path "${WORKSPACE}/ci_infra_logs" -prune -o -path "${WORKSPACE}/.git" -prune -o -name "test_binlog_reader-t" -type f -executable -print | head -n 1)
273272

274273
# Execution: run the container
275274
docker run \
@@ -295,7 +294,6 @@ docker run \
295294
-e COVERAGE_REPORT_DIR="${COVERAGE_REPORT_DIR}" \
296295
-e SCRIPT_DIR="${SCRIPT_DIR}" \
297296
-e MYSQL_BINLOG_BIN="${MYSQL_BINLOG_BIN}" \
298-
-e BINLOG_READER_BIN="${BINLOG_READER_BIN}" \
299297
-e TAP_USE_NOISE="${TAP_USE_NOISE:-0}" \
300298
-e TAP_PGSQL_SYNC_REPLICA_PORT="${TAP_PGSQL_SYNC_REPLICA_PORT:-}" \
301299
-e MULTI_GROUP="${MULTI_GROUP:-0}" \
@@ -394,7 +392,6 @@ docker run \
394392
395393
mkdir -p \"${WORKSPACE}/test-scripts/deps\"
396394
[ -n \"${MYSQL_BINLOG_BIN}\" ] && ln -sf \"${MYSQL_BINLOG_BIN}\" \"${WORKSPACE}/test-scripts/deps/mysqlbinlog\"
397-
[ -n \"${BINLOG_READER_BIN}\" ] && ln -sf \"${BINLOG_READER_BIN}\" \"${WORKSPACE}/test-scripts/deps/test_binlog_reader-t\"
398395
399396
# Source group environment first (sets TEST_PY_* flags etc.)
400397
if [ -n \"${TAP_GROUP}\" ]; then

test/infra/docker-pgsql16-single/conf/pgsql/pgsql1/postgresql.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
hba_file = '/etc/postgresql/pg_hba.conf'
22
listen_addresses = '*'
3+
max_connections = 120
34

45
logging_collector = 'on'
56
log_directory = '/var/log/postgresql'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
MARIADB_VERSION=10
2+
3+
PREFIX=17
4+
5+
WHG=${PREFIX}00
6+
RHG=${PREFIX}01
7+
BHG=${PREFIX}02
8+
OHG=${PREFIX}03
9+
10+
MARIADB1_PORT=${PREFIX}306
11+
MARIADB2_PORT=${PREFIX}307
12+
MARIADB3_PORT=${PREFIX}308
13+
14+
# dbdeployer uses a single container with 3 ports instead of 3 separate containers
15+
MYSQL_PRIMARY_HOST=dbdeployer1
16+
MYSQL_PRIMARY_PORT=3306
17+
18+
# Export hostgroup for TAP tests that need it
19+
export TAP_REG_TEST_3549_AUTOCOMMIT_TRACKING___MYSQL_SERVER_HOSTGROUP=${WHG}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
set -e
3+
set -o pipefail
4+
[ -f .env ] && . .env
5+
6+
CONTAINER="${COMPOSE_PROJECT}-dbdeployer1-1"
7+
8+
# NOTE: Do NOT delete/recreate cert bundles here.
9+
# The MySQL docker-mysql-post.bash (which runs first) already collected the
10+
# backend's CA cert into dbservers-cert-bundle.pem. MariaDB doesn't generate
11+
# SSL certs in the sandbox datadir, so deleting the bundle would remove the
12+
# MySQL certs without replacing them, breaking SSL tests.
13+
14+
# Verify all 3 MySQL nodes are reachable
15+
for PORT in 3306 3307 3308; do
16+
echo -n "Verifying MySQL on ${CONTAINER}:${PORT}..."
17+
MAX_WAIT=60
18+
COUNT=0
19+
while ! docker exec "${CONTAINER}" mysql -h127.0.0.1 -P${PORT} -uroot -p"${ROOT_PASSWORD}" -e "SELECT 1" >/dev/null 2>&1; do
20+
if [ $COUNT -ge $MAX_WAIT ]; then
21+
echo " TIMEOUT"
22+
exit 1
23+
fi
24+
echo -n "."
25+
sleep 2
26+
COUNT=$((COUNT + 2))
27+
done
28+
echo " OK"
29+
done
30+
31+
# Verify replication is working on nodes 2 and 3
32+
for PORT in 3307 3308; do
33+
echo -n "Checking replication on port ${PORT}..."
34+
SLAVE_STATUS=$(docker exec "${CONTAINER}" mysql -h127.0.0.1 -P${PORT} -uroot -p"${ROOT_PASSWORD}" -e "SHOW SLAVE STATUS\G" 2>/dev/null)
35+
IO_RUNNING=$(echo "${SLAVE_STATUS}" | grep "Slave_IO_Running:" | awk '{print $2}')
36+
SQL_RUNNING=$(echo "${SLAVE_STATUS}" | grep "Slave_SQL_Running:" | awk '{print $2}')
37+
if [ "${IO_RUNNING}" = "Yes" ] && [ "${SQL_RUNNING}" = "Yes" ]; then
38+
echo " OK (IO: Yes, SQL: Yes)"
39+
else
40+
echo " WARNING (IO: ${IO_RUNNING}, SQL: ${SQL_RUNNING})"
41+
fi
42+
done
43+
44+
echo "docker-mysql-post.bash complete."

0 commit comments

Comments
 (0)