智慧水务管理系统 - 精河县供水工程综合管理平台

restore-db.sh 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #!/bin/bash
  2. # ============================================================
  3. # 数据库恢复脚本
  4. #
  5. # 用法:
  6. # ./restore-db.sh --file /path/to/backup.sql.gz
  7. # ./restore-db.sh --latest # 恢复最近一次备份
  8. # ./restore-db.sh --date 2026-06-15 # 恢复指定日期的备份
  9. # ./restore-db.sh --list # 列出所有可用备份
  10. # ============================================================
  11. set -euo pipefail
  12. # ==================== 配置 ====================
  13. DB_HOST="${DB_HOST:-localhost}"
  14. DB_PORT="${DB_PORT:-5432}"
  15. DB_NAME="${POSTGRES_DB:-water_management}"
  16. DB_USER="${POSTGRES_USER:-water}"
  17. DB_PASSWORD="${POSTGRES_PASSWORD:-}"
  18. PGPASSWORD="${DB_PASSWORD}"
  19. export PGPASSWORD
  20. BACKUP_BASE="${BACKUP_DIR:-/opt/water-management/backups}"
  21. BACKUP_DAILY="${BACKUP_BASE}/daily"
  22. BACKUP_WEEKLY="${BACKUP_BASE}/weekly"
  23. BACKUP_MONTHLY="${BACKUP_BASE}/monthly"
  24. # ==================== 参数 ====================
  25. BACKUP_FILE=""
  26. MODE="file" # file | latest | date | list
  27. TARGET_DATE=""
  28. while [[ $# -gt 0 ]]; do
  29. case $1 in
  30. --file) BACKUP_FILE="$2"; MODE="file"; shift 2 ;;
  31. --latest) MODE="latest"; shift ;;
  32. --date) TARGET_DATE="$2"; MODE="date"; shift 2 ;;
  33. --list) MODE="list"; shift ;;
  34. -h|--help)
  35. echo "用法: $0 [选项]"
  36. echo ""
  37. echo "选项:"
  38. echo " --file PATH 指定备份文件路径"
  39. echo " --latest 恢复最近一次备份"
  40. echo " --date YYYY-MM-DD 恢复指定日期的备份"
  41. echo " --list 列出所有可用备份"
  42. echo ""
  43. echo "示例:"
  44. echo " $0 --file /opt/water-management/backups/daily/wm_water_management_20260615_020000.sql.gz"
  45. echo " $0 --latest"
  46. echo " $0 --date 2026-06-15"
  47. exit 0
  48. ;;
  49. *)
  50. echo "❌ 未知参数: $1"
  51. exit 1
  52. ;;
  53. esac
  54. done
  55. # ==================== 函数 ====================
  56. log() {
  57. echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
  58. }
  59. # 列出所有可用备份
  60. list_backups() {
  61. echo "========================================="
  62. echo " 可用备份列表"
  63. echo "========================================="
  64. echo ""
  65. echo "📅 每日备份:"
  66. if [ -d "$BACKUP_DAILY" ]; then
  67. ls -lht "$BACKUP_DAILY"/*.sql.gz 2>/dev/null | head -10 || echo " (无)"
  68. fi
  69. echo ""
  70. echo "📅 每周备份:"
  71. if [ -d "$BACKUP_WEEKLY" ]; then
  72. ls -lht "$BACKUP_WEEKLY"/*.sql.gz 2>/dev/null | head -10 || echo " (无)"
  73. fi
  74. echo ""
  75. echo "📅 每月备份:"
  76. if [ -d "$BACKUP_MONTHLY" ]; then
  77. ls -lht "$BACKUP_MONTHLY"/*.sql.gz 2>/dev/null | head -10 || echo " (无)"
  78. fi
  79. echo ""
  80. }
  81. # 查找最近的备份
  82. find_latest_backup() {
  83. local latest=""
  84. latest=$(ls -1t "$BACKUP_DAILY"/*.sql.gz 2>/dev/null | head -1 || echo "")
  85. if [ -z "$latest" ]; then
  86. latest=$(ls -1t "$BACKUP_WEEKLY"/*.sql.gz 2>/dev/null | head -1 || echo "")
  87. fi
  88. if [ -z "$latest" ]; then
  89. latest=$(ls -1t "$BACKUP_MONTHLY"/*.sql.gz 2>/dev/null | head -1 || echo "")
  90. fi
  91. echo "$latest"
  92. }
  93. # 查找指定日期的备份
  94. find_backup_by_date() {
  95. local date_str="$1"
  96. local date_compact
  97. date_compact=$(echo "$date_str" | tr -d '-')
  98. local found=""
  99. found=$(ls -1 "$BACKUP_DAILY"/*${date_compact}*.sql.gz 2>/dev/null | head -1 || echo "")
  100. echo "$found"
  101. }
  102. # 解密备份文件(如果需要)
  103. decrypt_if_needed() {
  104. local file="$1"
  105. if [[ "$file" == *.enc ]]; then
  106. log "🔐 检测到加密文件,正在解密..."
  107. local decrypted="${file%.enc}"
  108. openssl enc -d -aes-256-cbc -pbkdf2 \
  109. -in "$file" \
  110. -out "$decrypted" \
  111. -pass "pass:${ENCRYPT_PASSPHRASE:-}"
  112. echo "$decrypted"
  113. else
  114. echo "$file"
  115. fi
  116. }
  117. # 恢复数据库
  118. restore_database() {
  119. local backup_file="$1"
  120. if [ ! -f "$backup_file" ]; then
  121. log "❌ 备份文件不存在: $backup_file"
  122. exit 1
  123. fi
  124. local file_size
  125. file_size=$(du -sh "$backup_file" | cut -f1)
  126. log "========================================="
  127. log " 数据库恢复"
  128. log "========================================="
  129. log "备份文件: $backup_file"
  130. log "文件大小: $file_size"
  131. log "目标数据库: $DB_NAME"
  132. log "目标主机: $DB_HOST:$DB_PORT"
  133. log ""
  134. # 确认操作
  135. read -p "⚠️ 此操作将覆盖当前数据库,是否继续?(yes/no): " confirm
  136. if [ "$confirm" != "yes" ]; then
  137. log "❌ 操作已取消"
  138. exit 0
  139. fi
  140. log "🔄 开始恢复..."
  141. # 解密(如果需要)
  142. local actual_file
  143. actual_file=$(decrypt_if_needed "$backup_file")
  144. # 恢复数据库
  145. if [[ "$actual_file" == *.gz ]]; then
  146. gunzip -c "$actual_file" | psql \
  147. -h "$DB_HOST" \
  148. -p "$DB_PORT" \
  149. -U "$DB_USER" \
  150. -d "$DB_NAME" \
  151. --single-transaction \
  152. -v ON_ERROR_STOP=1 \
  153. 2>&1 | tail -20
  154. else
  155. psql \
  156. -h "$DB_HOST" \
  157. -p "$DB_PORT" \
  158. -U "$DB_USER" \
  159. -d "$DB_NAME" \
  160. --single-transaction \
  161. -v ON_ERROR_STOP=1 \
  162. -f "$actual_file" \
  163. 2>&1 | tail -20
  164. fi
  165. if [ ${PIPESTATUS[0]} -eq 0 ]; then
  166. log "✅ 数据库恢复成功"
  167. else
  168. log "❌ 数据库恢复可能存在问题,请检查日志"
  169. exit 1
  170. fi
  171. # 清理解密的临时文件
  172. if [ "$actual_file" != "$backup_file" ] && [ -f "$actual_file" ]; then
  173. rm -f "$actual_file"
  174. fi
  175. }
  176. # ==================== 主逻辑 ====================
  177. case "$MODE" in
  178. list)
  179. list_backups
  180. ;;
  181. latest)
  182. BACKUP_FILE=$(find_latest_backup)
  183. if [ -z "$BACKUP_FILE" ]; then
  184. log "❌ 未找到任何备份文件"
  185. exit 1
  186. fi
  187. restore_database "$BACKUP_FILE"
  188. ;;
  189. date)
  190. if [ -z "$TARGET_DATE" ]; then
  191. log "❌ 必须指定日期: --date YYYY-MM-DD"
  192. exit 1
  193. fi
  194. BACKUP_FILE=$(find_backup_by_date "$TARGET_DATE")
  195. if [ -z "$BACKUP_FILE" ]; then
  196. log "❌ 未找到 ${TARGET_DATE} 的备份文件"
  197. list_backups
  198. exit 1
  199. fi
  200. restore_database "$BACKUP_FILE"
  201. ;;
  202. file)
  203. if [ -z "$BACKUP_FILE" ]; then
  204. log "❌ 必须指定备份文件: --file /path/to/backup.sql.gz"
  205. exit 1
  206. fi
  207. restore_database "$BACKUP_FILE"
  208. ;;
  209. *)
  210. echo "❌ 未知模式: $MODE"
  211. exit 1
  212. ;;
  213. esac