#!/usr/bin/env bash # # ПРОД food-market: проверка восстановления бэкапа. Берёт последний daily-дамп # (или путь из аргумента), ВОССТАНАВЛИВАЕТ во ВРЕМЕННУЮ БД в том же контейнере # postgres, сверяет число строк ключевых таблиц с боевой БД, затем удаляет # временную БД. Боевую БД НЕ трогает (только читает count'ы). # # Выход 0 — восстановление успешно и counts совпали; !=0 — проблема (для мониторинга). set -uo pipefail CONTAINER="${FM_PG_CONTAINER:-food-market-prod-postgres}" DB="${FM_PG_DB:-food_market}" DB_USER="${FM_PG_USER:-food_market}" BASE_DIR="${FM_BACKUP_DIR:-/opt/food-market-data/backups}" TMP_DB="food_market_restore_test" DUMP="${1:-}" log() { echo "[$(date -Is)] [restore-verify] $*"; } fail() { log "FAIL: $*"; cleanup; exit 1; } cleanup() { docker exec "$CONTAINER" psql -U "$DB_USER" -d "$DB" -c "DROP DATABASE IF EXISTS $TMP_DB;" >/dev/null 2>&1 || true; } [ -n "$DUMP" ] || DUMP="$(ls -t "$BASE_DIR"/daily/db-*.dump "$BASE_DIR"/hourly/db-*.dump 2>/dev/null | head -1)" [ -n "$DUMP" ] && [ -f "$DUMP" ] || fail "дамп не найден (ни в аргументе, ни в $BASE_DIR)" log "дамп: $DUMP ($(du -h "$DUMP" | cut -f1))" trap cleanup EXIT cleanup log "создаю временную БД $TMP_DB" docker exec "$CONTAINER" psql -U "$DB_USER" -d "$DB" -c "CREATE DATABASE $TMP_DB;" >/dev/null 2>&1 || fail "CREATE DATABASE" log "pg_restore → $TMP_DB" if ! docker exec -i "$CONTAINER" pg_restore -U "$DB_USER" -d "$TMP_DB" --no-owner --no-privileges < "$DUMP" >/tmp/fm-restore.log 2>&1; then # pg_restore может вернуть !=0 на безобидных warning'ах (owner/extension); проверяем, # что таблицы реально появились — это решающий критерий. log "pg_restore завершился с предупреждениями (проверяю таблицы):" tail -5 /tmp/fm-restore.log 2>/dev/null | sed 's/^/ /' || true fi # Сверка числа строк ключевых таблиц: боевая vs восстановленная. TABLES="users roles organizations products supplies retail_sales money_transactions stocks" mismatch=0 for t in $TABLES; do live=$(docker exec "$CONTAINER" psql -U "$DB_USER" -d "$DB" -A -t -c "SELECT count(*) FROM $t;" 2>/dev/null | tr -d '[:space:]') rest=$(docker exec "$CONTAINER" psql -U "$DB_USER" -d "$TMP_DB" -A -t -c "SELECT count(*) FROM $t;" 2>/dev/null | tr -d '[:space:]') live="${live:-ERR}"; rest="${rest:-ERR}" if [ "$live" = "$rest" ] && [ "$live" != "ERR" ]; then log " $t: $live = $rest ✓" else log " $t: боевая=$live восстановлено=$rest ✗"; mismatch=1 fi done [ "$mismatch" = 0 ] || fail "число строк не совпало (см. выше)" log "✓ Восстановление проверено: все ключевые таблицы совпали." # cleanup выполнит trap EXIT. exit 0