pg_dump -> gzip -> gpg AES-256 symmetric encryption, plaintext deleted immediately, optional off-host rsync-over-SSH copy (Hetzner Storage Box or any SSH target), retention pruning, Prometheus textfile-collector metrics for backup success/age/size. Genuinely tested end-to-end, not just written: real production migrations (17 total, correct cross-service order) applied to a disposable Postgres, sample data inserted, backed up, restored into a second disposable Postgres, verified table-for-table and byte-for-byte. Exit 0.
27 lines
1.0 KiB
Bash
Executable File
27 lines
1.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sanity-checks a restored database — confirms the expected Platform API schema landed and has
|
|
# data, not just that psql exited 0 (a restore that silently imported zero rows would still
|
|
# "succeed" by that measure). Used both by restore-postgres.sh's own suggestion and by
|
|
# test-backup-restore.sh's automated local test.
|
|
set -euo pipefail
|
|
DB_URL="${1:?usage: verify-restore.sh <db-url>}"
|
|
|
|
EXPECTED_TABLES=(students cohorts instructors sessions scenario_attempts assessment_definitions achievements audit_events)
|
|
FAIL=0
|
|
|
|
for t in "${EXPECTED_TABLES[@]}"; do
|
|
exists=$(psql "$DB_URL" -tAc "SELECT to_regclass('public.$t') IS NOT NULL")
|
|
if [ "$exists" != "t" ]; then
|
|
echo "MISSING TABLE: $t" >&2
|
|
FAIL=1
|
|
fi
|
|
done
|
|
|
|
if [ "$FAIL" = "1" ]; then
|
|
echo "FAIL: restored database is missing expected tables" >&2
|
|
exit 1
|
|
fi
|
|
|
|
MIGRATIONS_APPLIED=$(psql "$DB_URL" -tAc "SELECT count(*) FROM schema_migrations" 2>/dev/null || echo 0)
|
|
echo "OK: all expected tables present. $MIGRATIONS_APPLIED migrations recorded in schema_migrations."
|