#!/bin/bash # ============================================================================= # WOOO AIOps - AWOOOI 資料庫備份腳本 # 2026-04-05 Claude Code: 首席架構師備份審計 — awoooi_prod/dev/k3s_datastore # 部署位置: /backup/scripts/backup-awoooi.sh (on 192.168.0.110) # 整合進 backup-all.sh (步驟 4/4) # ============================================================================= set -euo pipefail # 載入共用函式 source "$(dirname "$0")/common.sh" # 配置 SERVICE="awoooi" AWOOOI_HOST="192.168.0.188" AWOOOI_DB_USER="awoooi" AWOOOI_DB_PASS="awoooi_prod_2026" AWOOOI_DB_HOST="localhost" AWOOOI_DB_PORT="5432" K3S_DB_USER="postgres" LOCAL_REPO="${BACKUP_BASE}/awoooi" DUMP_DIR="/tmp/awoooi-backup-$$" # 保留策略覆寫(比其他服務更長) KEEP_DAILY=14 # 14 天每日 KEEP_WEEKLY=8 # 8 週每週 KEEP_MONTHLY=12 # 12 個月每月 main() { local start_time=$(date +%s) local failed=0 log_info "========== 開始 AWOOOI 資料庫備份 ==========" mkdir -p "${DUMP_DIR}" # Step 1: awoooi_prod dump(核心資料庫:KB/事故/AutoRepair/Drift) log_info "Dump awoooi_prod..." local timestamp=$(date "+%Y%m%d_%H%M%S") if ssh ollama@${AWOOOI_HOST} "PGPASSWORD='${AWOOOI_DB_PASS}' pg_dump \ -U ${AWOOOI_DB_USER} -h ${AWOOOI_DB_HOST} -p ${AWOOOI_DB_PORT} \ awoooi_prod" > "${DUMP_DIR}/awoooi_prod_${timestamp}.sql" 2>&1; then local size=$(du -h "${DUMP_DIR}/awoooi_prod_${timestamp}.sql" | cut -f1) log_success "awoooi_prod dump 完成 (${size})" else log_error "awoooi_prod dump 失敗" ((failed++)) fi # Step 2: awoooi_dev dump log_info "Dump awoooi_dev..." if ssh ollama@${AWOOOI_HOST} "PGPASSWORD='${AWOOOI_DB_PASS}' pg_dump \ -U ${AWOOOI_DB_USER} -h ${AWOOOI_DB_HOST} -p ${AWOOOI_DB_PORT} \ awoooi_dev 2>/dev/null" > "${DUMP_DIR}/awoooi_dev_${timestamp}.sql" 2>/dev/null; then local size=$(du -h "${DUMP_DIR}/awoooi_dev_${timestamp}.sql" | cut -f1) log_success "awoooi_dev dump 完成 (${size})" else log_warn "awoooi_dev dump 跳過(可能不存在)" fi # Step 3: k3s_datastore dump(Kine 後端) log_info "Dump k3s_datastore..." if ssh ollama@${AWOOOI_HOST} "PGPASSWORD='${AWOOOI_DB_PASS}' pg_dump \ -U ${AWOOOI_DB_USER} -h ${AWOOOI_DB_HOST} -p ${AWOOOI_DB_PORT} \ k3s_datastore 2>/dev/null" > "${DUMP_DIR}/k3s_datastore_${timestamp}.sql" 2>/dev/null; then local size=$(du -h "${DUMP_DIR}/k3s_datastore_${timestamp}.sql" | cut -f1) log_success "k3s_datastore dump 完成 (${size})" else log_warn "k3s_datastore dump 跳過" fi # 若核心 DB 失敗,中止 if [ $failed -gt 0 ]; then log_error "核心 DB awoooi_prod 備份失敗,中止" notify_clawbot "failed" "${SERVICE}" "AWOOOI 核心 DB 備份失敗" rm -rf "${DUMP_DIR}" exit 1 fi # Step 4: Restic 備份 log_info "建立 Restic 備份..." local tags=$(build_tags "${SERVICE}") if [ ! -d "${LOCAL_REPO}/data" ]; then log_info "初始化 Restic 倉庫 ${LOCAL_REPO}..." restic -r "${LOCAL_REPO}" init --password-file "${RESTIC_PASSWORD_FILE}" 2>&1 fi restic -r "${LOCAL_REPO}" backup "${DUMP_DIR}" \ --password-file "${RESTIC_PASSWORD_FILE}" \ ${tags} 2>&1 local snapshot_id=$(restic -r "${LOCAL_REPO}" snapshots --latest 1 --json \ --password-file "${RESTIC_PASSWORD_FILE}" 2>/dev/null | \ grep -oP '"short_id":"\K[^"]+' | head -1) log_success "Restic 備份完成: ${snapshot_id}" # Step 5: GFS 清理(延長保留) log_info "執行 GFS 清理 (daily=${KEEP_DAILY} weekly=${KEEP_WEEKLY} monthly=${KEEP_MONTHLY})..." restic -r "${LOCAL_REPO}" forget --prune \ --password-file "${RESTIC_PASSWORD_FILE}" \ --keep-daily ${KEEP_DAILY} \ --keep-weekly ${KEEP_WEEKLY} \ --keep-monthly ${KEEP_MONTHLY} 2>&1 log_success "GFS 清理完成" # Step 6: B2 同步(若設定) if check_b2_config; then log_info "同步到 Backblaze B2..." rclone sync "${LOCAL_REPO}" "b2:${B2_BUCKET}/awoooi" --progress 2>&1 log_success "B2 同步完成" fi rm -rf "${DUMP_DIR}" local end_time=$(date +%s) local duration=$((end_time - start_time)) log_success "========== AWOOOI 備份完成 (${duration}s) ==========" notify_clawbot "success" "${SERVICE}" "AWOOOI DB 備份完成 (awoooi_prod/dev + k3s)" "${duration}" } main "$@"