#!/usr/bin/env bash set -Eeuo pipefail # shellcheck source=lib.sh source "$(dirname -- "${BASH_SOURCE[0]}")/lib.sh" usage() { echo '用法:restore.sh --confirm [env-file]' } backup="${1:-}" target_database="${2:-}" confirm_flag="${3:-}" confirm_database="${4:-}" env_file="${5:-/etc/lehuo/lehuo.env}" [[ -n "$backup" && -n "$target_database" && "$confirm_flag" == '--confirm' && "$confirm_database" == "$target_database" ]] || { usage >&2 exit 1 } [[ "$target_database" =~ ^[A-Za-z0-9_]+$ ]] || { echo '目标数据库名无效。' >&2; exit 1; } require_command docker require_command gzip require_command sha256sum require_command realpath require_env_file "$env_file" backup_dir="$(realpath -m "$(env_value "$env_file" BACKUP_DIR)")" backup_path="$(realpath -e "$backup")" [[ "$backup_path" == "$backup_dir"/* ]] || { echo '备份文件必须位于 BACKUP_DIR。' >&2; exit 1; } [[ -f "${backup_path}.sha256" ]] || { echo '缺少 SHA-256 校验文件。' >&2; exit 1; } (cd -- "$backup_dir" && sha256sum -c "$(basename -- "${backup_path}.sha256")") gzip -t "$backup_path" production_database="$(env_value "$env_file" MYSQL_DATABASE)" if [[ "$target_database" == "$production_database" && "${ALLOW_PRODUCTION_RESTORE:-}" != 'YES' ]]; then echo '拒绝覆盖生产数据库。若已完成停机、审批和二次备份,请显式设置 ALLOW_PRODUCTION_RESTORE=YES。' >&2 exit 1 fi compose "$env_file" exec -T -e RESTORE_DATABASE="$target_database" mysql sh -c \ 'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" exec mysql -u root -e "CREATE DATABASE IF NOT EXISTS \`$RESTORE_DATABASE\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci"' gzip -dc "$backup_path" | compose "$env_file" exec -T -e RESTORE_DATABASE="$target_database" mysql sh -c \ 'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" exec mysql -u root "$RESTORE_DATABASE"' printf '恢复完成:%s → %s\n' "$backup_path" "$target_database"