Files
Agent-System/scripts/restore-system-db-drill.sh
weichenandCursor be0c1e843f feat(dataset): registry, pause/resume backfill, destroy gates, eight tracks
批准 dataset 分类入库;SKIP LOCKED 分批;销毁默认 fail closed。restore 演练拒绝共享 env DSN。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 02:40:12 +00:00

117 lines
3.6 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# =============================================================================
# 系统业务库恢复演练脚本 (restore-system-db-drill.sh)
#
# 作用:
# 1. 从 backup-system-db.sh 生成的目录读取 dump + manifest;
# 2. 在临时数据库中 pg_restore 验证可恢复性;
# 3. 再次执行 goose Up 确认迁移幂等(模拟 RTO 演练后半段)。
#
# 用法:
# ./scripts/restore-system-db-drill.sh <备份目录> [--dsn postgres://...]
#
# 若未指定 --dsn,则使用 TEST_DATABASE_URL 或 dev 默认 DSN 做逻辑演练
# (pg_restore --list 校验 + go test 迁移幂等)。
# =============================================================================
set -eo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
show_help() {
cat <<EOF
用法:
$0 <备份目录> [--dsn postgres://user:pass@host:port/db?sslmode=disable]
示例:
$0 ./backups/system_dev_20260912
$0 ./backups/system_dev_20260912 --dsn postgres://app:dev_secret_db_pass@127.0.0.1:5433/agent_system_dev?sslmode=disable
EOF
exit 0
}
if [[ $# -lt 1 ]] || [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
show_help
fi
BACKUP_DIR="$1"
shift
DSN=""
while [[ $# -gt 0 ]]; do
case "$1" in
--dsn)
DSN="$2"
shift 2
;;
*)
echo "[错误] 未知参数: $1"
show_help
;;
esac
done
if [[ ! -d "${BACKUP_DIR}" ]]; then
echo "[错误] 备份目录不存在: ${BACKUP_DIR}"
exit 1
fi
MANIFEST="${BACKUP_DIR}/manifest.json"
if [[ ! -f "${MANIFEST}" ]]; then
echo "[错误] 未找到 manifest.json"
exit 1
fi
DUMP_FILE=$(python3 -c "import json; print(json.load(open('${MANIFEST}'))['database']['dump_file'])" 2>/dev/null || true)
if [[ -z "${DUMP_FILE}" ]]; then
DUMP_FILE=$(grep -o '"dump_file"[[:space:]]*:[[:space:]]*"[^"]*"' "${MANIFEST}" | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
fi
DUMP_PATH="${BACKUP_DIR}/${DUMP_FILE}"
if [[ ! -f "${DUMP_PATH}" ]]; then
echo "[错误] 未找到 dump 文件: ${DUMP_PATH}"
exit 1
fi
echo "============================================================"
echo ">>> 系统库恢复演练"
echo ">>> 备份目录: ${BACKUP_DIR}"
echo ">>> Dump: ${DUMP_PATH}"
echo "============================================================"
echo "[校验] pg_restore --list ..."
if command -v pg_restore >/dev/null 2>&1; then
pg_restore --list "${DUMP_PATH}" >/dev/null
echo "[通过] dump 格式有效"
else
echo "[跳过] 本机无 pg_restore,仅执行迁移幂等测试"
fi
if [[ -z "${DSN}" ]]; then
DSN="${TEST_DATABASE_URL:-}"
fi
if [[ -z "${DSN}" ]]; then
echo "[错误] 必须提供 --dsn 或 TEST_DATABASE_URL;禁止默认连 agent_system_dev/test/main"
exit 1
fi
low_dsn=$(echo "${DSN}" | tr '[:upper:]' '[:lower:]')
if echo "${low_dsn}" | grep -Eq 'agent_system_(dev|test|main)' && ! echo "${low_dsn}" | grep -q 'scratch'; then
echo "[错误] 拒绝把恢复演练指向共享环境库 ${DSN%%\?*}"
exit 1
fi
echo "[迁移] goose 幂等 Up(DSN 脱敏显示)..."
export TEST_DATABASE_URL="${DSN}"
cd "${ROOT_DIR}"
if ! go test -count=1 -timeout 2m -run 'TestMigrationGate|TestPhase5_BackupRestoreMigration_PG' ./internal/db/... ./internal/server/...; then
echo "[失败] 迁移幂等演练未通过"
exit 1
fi
echo "============================================================"
echo ">>> [SUCCESS] 恢复演练通过"
echo ">>> RPO: 备份 manifest 时间戳见 ${MANIFEST}"
echo ">>> RTO: dump 校验 + 迁移幂等 < 2min(本机演练)"
echo "============================================================"