#!/usr/bin/env bash # 按需启停测试库,禁止一次全开。 set -euo pipefail cd "$(dirname "$0")" ALIASES_HELP='mysql|a mariadb|b postgres|c mssql|d oracle|e redis|f zookeeper|g elasticsearch|h influxdb|i' ALL_PROFILES=(mysql mariadb postgres mssql oracle redis zookeeper elasticsearch influxdb) # 国内加速(DaoCloud 镜像站)。可用 DOCKER_MIRROR 覆盖,例如 docker.1ms.run DOCKER_MIRROR="${DOCKER_MIRROR:-docker.m.daocloud.io}" DOCKER_MIRROR_FALLBACK="${DOCKER_MIRROR_FALLBACK:-docker.1ms.run}" resolve() { case "$1" in a|mysql) echo mysql ;; b|mariadb|maria) echo mariadb ;; c|postgres|pg|postgresql) echo postgres ;; d|mssql|sqlserver|sqlsrv) echo mssql ;; e|oracle) echo oracle ;; f|redis) echo redis ;; g|zk|zookeeper) echo zookeeper ;; h|es|elastic|elasticsearch) echo elasticsearch ;; i|influx|influxdb) echo influxdb ;; *) echo ""; return 1 ;; esac } compose_all_profiles() { local args=() local p for p in "${ALL_PROFILES[@]}"; do args+=(--profile "$p") done echo "${args[@]}" } # 国内源路径 → 本地短名。拉完摘掉带源前缀的 tag,层仍在。 # zookeeper:3.9 ← docker.m.daocloud.io/library/zookeeper:3.9 # mssql/server:2022-latest ← mcr.m.daocloud.io/mssql/server:2022-latest mirror_src() { case "$1" in mssql/server:*|mssql/*) echo "mcr.m.daocloud.io/$1" ;; *) echo "${DOCKER_MIRROR}/library/$1" ;; esac } mirror_src_fallback() { case "$1" in mssql/server:*|mssql/*) echo "mcr.microsoft.com/$1" ;; *) echo "${DOCKER_MIRROR_FALLBACK}/library/$1" ;; esac } pull_mirrored() { local official="$1" if docker image inspect "$official" >/dev/null 2>&1; then echo "[OK] 已有本地镜像 $official" return 0 fi local src for src in "$(mirror_src "$official")" "$(mirror_src_fallback "$official")"; do echo "[INFO] 从 $src 拉取 …" if docker pull "$src"; then docker tag "$src" "$official" if [[ "$src" != "$official" ]]; then docker rmi "$src" >/dev/null 2>&1 || true fi echo "[OK] $official" return 0 fi echo "[WARN] $src 失败,尝试下一个" done echo "[ERR] 无法拉取 $official" return 1 } running_profiles() { docker compose ps --services --status running 2>/dev/null || true } cmd_up() { local svc svc=$(resolve "${1:-}") || { echo "用法: $0 up <${ALIASES_HELP}>"; exit 1; } local cur cur=$(running_profiles) if [[ -n "$cur" ]]; then local other other=$(echo "$cur" | grep -v "^${svc}$" || true) if [[ -n "$other" ]]; then echo "[WARN] 已有其它测试库在跑,先停以免抢资源: $other" # shellcheck disable=SC2086 docker compose $(compose_all_profiles) stop $other || true fi fi echo "[INFO] 启动 $svc …" docker compose --profile "$svc" up -d "$svc" echo "[OK] $svc 已请求启动。连接参数见 README.md" docker compose --profile "$svc" ps } cmd_down() { if [[ -z "${1:-}" ]]; then echo "[INFO] 停止全部 opsxdb-tests 服务" # shellcheck disable=SC2046 docker compose $(compose_all_profiles) down return fi local svc svc=$(resolve "$1") || { echo "未知库: $1"; exit 1; } docker compose --profile "$svc" stop "$svc" echo "[OK] 已停止 $svc(数据卷保留;要清数据用: $0 reset $svc)" } cmd_reset() { local svc svc=$(resolve "${1:-}") || { echo "用法: $0 reset <服务>"; exit 1; } docker compose --profile "$svc" stop "$svc" || true docker compose --profile "$svc" rm -f "$svc" || true case "$svc" in mysql) docker volume rm -f opsxdb-tests_opsxdb_mysql_data 2>/dev/null || true ;; mariadb) docker volume rm -f opsxdb-tests_opsxdb_mariadb_data 2>/dev/null || true ;; postgres) docker volume rm -f opsxdb-tests_opsxdb_pg_data 2>/dev/null || true ;; mssql) docker volume rm -f opsxdb-tests_opsxdb_mssql_data 2>/dev/null || true ;; oracle) docker volume rm -f opsxdb-tests_opsxdb_oracle_data 2>/dev/null || true ;; redis) ;; zookeeper) docker volume rm -f opsxdb-tests_opsxdb_zk_data opsxdb-tests_opsxdb_zk_datalog 2>/dev/null || true ;; elasticsearch) docker volume rm -f opsxdb-tests_opsxdb_es_data 2>/dev/null || true ;; influxdb) docker volume rm -f opsxdb-tests_opsxdb_influx_data 2>/dev/null || true ;; esac echo "[OK] $svc 已重置(下次 up 会重新初始化)" } cmd_status() { echo "=== 运行中的测试库 ===" docker compose ps 2>/dev/null || docker ps --filter name=opsxdb- --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' } cmd_logs() { local svc svc=$(resolve "${1:-}") || { echo "用法: $0 logs <服务>"; exit 1; } docker compose --profile "$svc" logs -f --tail=100 "$svc" } cmd_pull() { local target="${1:-new}" case "$target" in new|ghi|extra) echo "[INFO] 拉取 ZooKeeper / Elasticsearch / InfluxDB(国内加速,本地短 tag)" pull_mirrored zookeeper:3.9 pull_mirrored elasticsearch:8.15.3 pull_mirrored influxdb:2.7 ;; d|mssql|sqlserver) pull_mirrored mssql/server:2022-latest ;; g|zk|zookeeper) pull_mirrored zookeeper:3.9 ;; h|es|elastic|elasticsearch) pull_mirrored elasticsearch:8.15.3 ;; i|influx|influxdb) pull_mirrored influxdb:2.7 ;; *) local svc svc=$(resolve "$target") || { echo "用法: $0 pull [new|zookeeper|elasticsearch|influxdb]"; exit 1; } case "$svc" in mssql) pull_mirrored mssql/server:2022-latest ;; zookeeper) pull_mirrored zookeeper:3.9 ;; elasticsearch) pull_mirrored elasticsearch:8.15.3 ;; influxdb) pull_mirrored influxdb:2.7 ;; *) echo "请直接 docker compose pull,或: $0 pull new"; exit 1 ;; esac ;; esac echo docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}' | grep -E 'REPOSITORY|zookeeper|elasticsearch|influxdb' || true } usage() { cat < ./dbctl.sh down [服务] # 省略则停全部 ./dbctl.sh reset <服务> # 删容器+数据卷 ./dbctl.sh pull [new] # 国内加速拉取 ZK / ES / InfluxDB ./dbctl.sh status ./dbctl.sh logs <服务> a–i: a=MySQL b=MariaDB c=PostgreSQL d=SQL Server e=Oracle f=Redis g=ZooKeeper h=Elasticsearch i=InfluxDB USAGE } case "${1:-}" in up) shift; cmd_up "$@" ;; down|stop) shift; cmd_down "$@" ;; reset) shift; cmd_reset "$@" ;; pull) shift; cmd_pull "$@" ;; status|ps) cmd_status ;; logs) shift; cmd_logs "$@" ;; help|-h|--help|"") usage ;; *) echo "未知命令: $1"; usage; exit 1 ;; esac