food-market/deploy/prod-restore-verify.sh
nns b49abfdbd7
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
feat(prod): запуск admin.food-market.kz — бэкапы (hourly/daily/офсайт), restore-verify, мониторинг, deploy-prod
- prod-backup.sh (tier hourly 48ч / daily 30д + uploads), prod-backup-offsite-pull.sh (DR на dev-vm)
- prod-restore-verify.sh: restore во временную БД + сверка числа строк, дроп
- prod-monitor.sh: api/web/public/БД/диск/5xx → Telegram владельцу (+ --test)
- deploy-prod.sh: guard'ы (prod-postgres, .env chmod600, не dev-пароль, quick-login off,
  SEED_DEMO_DATA=false, issuer), бэкап ДО миграций, только --yes, НЕ в ночных
- systemd таймеры (backup-hourly/daily, monitor, offsite-pull); docs/prod-runbook.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:31:55 +05:00

57 lines
3.1 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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