#!/usr/bin/env bash # lib.sh —— 共用函数库,被所有备份脚本 source # ---------- 日志 ---------- log_info() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*"; } log_warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $*" >&2; } log_error() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" >&2; } log_ok() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [OK] $*"; } # ---------- 默认值 ---------- : "${BACKUP_DIR:=/backup}" : "${MYSQL_HOST:=127.0.0.1}" : "${MYSQL_PORT:=3306}" : "${PG_HOST:=127.0.0.1}" : "${PG_PORT:=5432}" : "${BACKUP_AWS_REGION:=ap-southeast-1}" : "${AWS_PROFILE:=backup}" # ---------- 通知(Webhook,可选) ---------- notify() { local level="$1" local msg="$2" log_info "[NOTIFY] ${level}: ${msg}" if [ -n "${NOTIFY_WEBHOOK_URL:-}" ]; then curl -fsS -X POST "${NOTIFY_WEBHOOK_URL}" \ -H 'Content-Type: application/json' \ -d "{\"level\":\"${level}\",\"msg\":$(printf '%s' "${msg}" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}" \ --max-time 10 || true fi } # ---------- age 加密 ---------- # 用法: age_encrypt age_encrypt() { local src="$1" local dst="$2" local pubkey_file="${AGE_PUBLIC_KEY_FILE:-/etc/age-public.txt}" if [ ! -f "${pubkey_file}" ]; then log_error "age 公钥文件不存在: ${pubkey_file}" return 1 fi age --encrypt --recipient "$(cat "${pubkey_file}")" -o "${dst}" "${src}" } # ---------- S3 上传 ---------- # 用法: s3_upload s3_upload() { local src="$1" local suffix="$2" local dst="s3://${BACKUP_S3_BUCKET}/${BACKUP_S3_PREFIX}/${suffix}" log_info "上传 $(basename "${src}") → ${dst}" AWS_PROFILE="${AWS_PROFILE}" aws s3 cp \ --no-progress \ --storage-class STANDARD_IA \ "${src}" "${dst}" log_ok "上传完成: ${dst}" } # ---------- 加密并上传 ---------- # 用法: encrypt_and_upload encrypt_and_upload() { local src="$1" local suffix="$2" local enc_file="${BACKUP_DIR}/encrypt/$(basename "${src}").age" mkdir -p "${BACKUP_DIR}/encrypt" log_info "age 加密: ${src}" age_encrypt "${src}" "${enc_file}" s3_upload "${enc_file}" "${suffix}.age" # 删除本地加密临时文件(原始文件由调用方管理) rm -f "${enc_file}" } # ---------- MySQL 连接测试 ---------- mysql_ping() { mysql \ --host="${MYSQL_HOST}" \ --port="${MYSQL_PORT}" \ --user="${MYSQL_USER:-root}" \ --password="${MYSQL_PASSWORD}" \ --connect-timeout=5 \ -e "SELECT 1" > /dev/null 2>&1 } # ---------- PostgreSQL 连接测试 ---------- pg_ping() { PGPASSWORD="${PG_PASSWORD:-}" pg_isready \ --host="${PG_HOST}" \ --port="${PG_PORT}" \ --username="${PG_USER:-postgres}" \ --quiet 2>&1 } # ---------- 计时工具 ---------- timer_start() { date +%s; } timer_elapsed() { local start="$1" local end end=$(date +%s) echo $(( end - start )) } format_duration() { local secs="$1" local h=$(( secs / 3600 )) local m=$(( (secs % 3600) / 60 )) local s=$(( secs % 60 )) printf '%dh %dm %ds' "${h}" "${m}" "${s}" }