feat: add flyway cli wrapper and staging restore

This commit is contained in:
irving
2025-11-07 22:38:47 -05:00
parent d7d7c64c01
commit 29ff0a2637
9 changed files with 590 additions and 1 deletions

137
recreate-staging.sh Executable file
View File

@@ -0,0 +1,137 @@
#!/usr/bin/env bash
set -euo pipefail
CONTAINER_NAME=${STAGING_MYSQL_CONTAINER:-peipei-mysql-staging}
VOLUME_NAME=${STAGING_MYSQL_VOLUME:-peipei-mysql-staging-data}
HOST_PORT=${STAGING_MYSQL_PORT:-3307}
DB_NAME=${STAGING_MYSQL_DB:-play-with}
ROOT_PASSWORD=${STAGING_MYSQL_ROOT_PASSWORD:-root}
MYSQL_IMAGE=${STAGING_MYSQL_IMAGE:-mysql:8.0.32}
usage() {
cat <<USAGE
Usage: $0 <path-to-backup.sql[.gz|.xz]>
Recreates the local staging MySQL container (${CONTAINER_NAME}) and imports the given SQL dump.
Environment overrides: STAGING_MYSQL_CONTAINER, STAGING_MYSQL_VOLUME, STAGING_MYSQL_PORT,
STAGING_MYSQL_DB, STAGING_MYSQL_ROOT_PASSWORD, STAGING_MYSQL_IMAGE.
USAGE
exit 1
}
if [[ $# -ne 1 ]]; then
usage
fi
backup_path=$1
if [[ ! -f "$backup_path" ]]; then
echo "[ERROR] Backup file not found: $backup_path" >&2
exit 1
fi
if ! command -v docker >/dev/null 2>&1; then
echo "[ERROR] docker command not found" >&2
exit 1
fi
port_in_use() {
if command -v lsof >/dev/null 2>&1; then
lsof -iTCP:"$HOST_PORT" -sTCP:LISTEN -Pn >/dev/null 2>&1 && return 0
fi
if command -v netstat >/dev/null 2>&1; then
netstat -an | grep -E "\.$HOST_PORT .*LISTEN" >/dev/null 2>&1 && return 0
fi
return 1
}
confirm_remove() {
local prompt="$1"
read -r -p "$prompt (yes/no): " reply
if [[ "$reply" != "yes" ]]; then
echo "操作已取消"
exit 1
fi
}
existing_container_id=$(docker ps -a --filter "name=^${CONTAINER_NAME}$" -q)
if [[ -n "$existing_container_id" ]]; then
echo "[WARN] Container ${CONTAINER_NAME} already exists."
confirm_remove "Remove the existing staging container and recreate it?"
docker rm -f "$CONTAINER_NAME" >/dev/null
fi
echo "[INFO] Removing existing volume (if any): ${VOLUME_NAME}"
if docker volume ls -q --filter "name=^${VOLUME_NAME}$" | grep -Fxq "$VOLUME_NAME"; then
docker volume rm "$VOLUME_NAME" >/dev/null
fi
if port_in_use; then
containers_on_port=$(docker ps --filter "publish=${HOST_PORT}" --format '{{.ID}}\t{{.Names}}')
if [[ -n "$containers_on_port" ]]; then
echo "[WARN] Host port ${HOST_PORT} is currently used by the following container(s):"
while IFS=$'\t' read -r cid cname; do
[[ -z "$cid" ]] && continue
echo " - ${cname} (${cid})"
done <<<"$containers_on_port"
confirm_remove "Stop and remove these container(s)?"
while IFS=$'\t' read -r cid cname; do
[[ -z "$cid" ]] && continue
docker stop "$cid" >/dev/null
docker rm "$cid" >/dev/null
done <<<"$containers_on_port"
else
echo "[ERROR] Host port ${HOST_PORT} is already in use. Set STAGING_MYSQL_PORT to an unused port or stop the process using it." >&2
exit 1
fi
if port_in_use; then
echo "[ERROR] Host port ${HOST_PORT} is still in use after stopping containers. Please free the port manually or change STAGING_MYSQL_PORT." >&2
exit 1
fi
fi
echo "[INFO] Starting fresh MySQL container ${CONTAINER_NAME}"
docker run -d \
--name "$CONTAINER_NAME" \
-p "${HOST_PORT}:3306" \
-e MYSQL_ROOT_PASSWORD="$ROOT_PASSWORD" \
-e MYSQL_DATABASE="$DB_NAME" \
-v "$VOLUME_NAME:/var/lib/mysql" \
"$MYSQL_IMAGE" \
--lower_case_table_names=1 \
--explicit_defaults_for_timestamp=1 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci >/dev/null
echo -n "[INFO] Waiting for MySQL to accept connections"
for attempt in {1..60}; do
if docker exec "$CONTAINER_NAME" mysqladmin ping -h127.0.0.1 -uroot -p"$ROOT_PASSWORD" --silent >/dev/null 2>&1; then
echo " - ready"
break
fi
sleep 2
echo -n "."
if [[ $attempt -eq 60 ]]; then
echo "\n[ERROR] MySQL did not become ready in time" >&2
exit 1
fi
done
case "$backup_path" in
*.gz)
reader=(gzip -dc -- "$backup_path")
;;
*.xz)
reader=(xz -dc -- "$backup_path")
;;
*.zip)
reader=(unzip -p -- "$backup_path")
;;
*)
reader=(cat -- "$backup_path")
;;
esac
echo "[INFO] Importing backup $backup_path into ${DB_NAME}"
"${reader[@]}" | docker exec -i "$CONTAINER_NAME" mysql -uroot -p"$ROOT_PASSWORD" --default-character-set=utf8mb4 "$DB_NAME"
echo "[INFO] Staging database restored. Container ${CONTAINER_NAME} is listening on port ${HOST_PORT}."