Initial commit (unpacked platform)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
# Backup-restore-övning (hardening-checklistan: "genomfört och protokollfört, kvartalsvis").
|
||||
# Kör: DATABASE_URL=postgres://… ./infrastructure/deployment/backup-restore-test.sh
|
||||
#
|
||||
# Gör: logisk dump → återställ till temporär databas → jämför radantal per tabell
|
||||
# → skriv protokoll → städa. Avslutar med exitkod 1 vid avvikelse.
|
||||
set -euo pipefail
|
||||
|
||||
DATABASE_URL="${DATABASE_URL:?Sätt DATABASE_URL}"
|
||||
# Roll med CREATEDB för test-databasen (RDS master/operatör). Faller tillbaka på DATABASE_URL.
|
||||
ADMIN_URL="${ADMIN_DATABASE_URL:-$DATABASE_URL}"
|
||||
STAMP=$(date +%Y%m%d_%H%M%S)
|
||||
WORKDIR="${BACKUP_DIR:-/tmp/backup-restore-test}"
|
||||
DUMP="$WORKDIR/dump-$STAMP.pgdump"
|
||||
RESTORE_DB="restore_test_$STAMP"
|
||||
PROTOKOLL="$WORKDIR/protokoll-$STAMP.md"
|
||||
mkdir -p "$WORKDIR"
|
||||
|
||||
# Härled anslutning utan databasnamn för att kunna skapa/droppa test-databasen.
|
||||
BASE_URL="${DATABASE_URL%/*}"
|
||||
ADMIN_BASE_URL="${ADMIN_URL%/*}"
|
||||
|
||||
echo "==> 1/5 Dumpar databasen"
|
||||
pg_dump "$DATABASE_URL" --format=custom --file="$DUMP"
|
||||
SIZE=$(du -h "$DUMP" | cut -f1)
|
||||
|
||||
echo "==> 2/5 Skapar temporär databas $RESTORE_DB"
|
||||
psql "$ADMIN_BASE_URL/postgres" -qc "CREATE DATABASE $RESTORE_DB" 2>/dev/null \
|
||||
|| psql "$ADMIN_URL" -qc "CREATE DATABASE $RESTORE_DB"
|
||||
|
||||
cleanup() {
|
||||
psql "$ADMIN_BASE_URL/postgres" -qc "DROP DATABASE IF EXISTS $RESTORE_DB" 2>/dev/null \
|
||||
|| psql "$ADMIN_URL" -qc "DROP DATABASE IF EXISTS $RESTORE_DB" || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "==> 3/5 Återställer till $RESTORE_DB"
|
||||
# Återställ som admin-rollen (äger test-databasen, får skapa extensions).
|
||||
pg_restore --dbname="$ADMIN_BASE_URL/$RESTORE_DB" --no-owner --no-privileges "$DUMP"
|
||||
|
||||
echo "==> 4/5 Jämför radantal per tabell"
|
||||
COUNT_SQL="SELECT relname, n_live_tup FROM pg_stat_user_tables ORDER BY relname"
|
||||
ROWS_SQL="SELECT string_agg(format('%s:%s', t.tablename, (xpath('/row/cnt/text()', query_to_xml(format('SELECT count(*) AS cnt FROM %I', t.tablename), false, true, '')))[1]::text), E'\n' ORDER BY t.tablename) FROM pg_tables t WHERE schemaname='public'"
|
||||
ORIG=$(psql "$DATABASE_URL" -tA -c "$ROWS_SQL")
|
||||
REST=$(psql "$ADMIN_BASE_URL/$RESTORE_DB" -tA -c "$ROWS_SQL")
|
||||
|
||||
STATUS="GODKÄND"
|
||||
DIFF_OUT=""
|
||||
if [ "$ORIG" != "$REST" ]; then
|
||||
STATUS="UNDERKÄND"
|
||||
DIFF_OUT=$(diff <(echo "$ORIG") <(echo "$REST") || true)
|
||||
fi
|
||||
|
||||
echo "==> 5/5 Skriver protokoll: $PROTOKOLL"
|
||||
TABLES=$(echo "$ORIG" | wc -l)
|
||||
TOTAL=$(echo "$ORIG" | awk -F: '{s+=$2} END {print s}')
|
||||
{
|
||||
echo "# Backup-restore-protokoll $STAMP"
|
||||
echo
|
||||
echo "| Fält | Värde |"
|
||||
echo "| ---- | ----- |"
|
||||
echo "| Resultat | **$STATUS** |"
|
||||
echo "| Dumpstorlek | $SIZE |"
|
||||
echo "| Tabeller jämförda | $TABLES |"
|
||||
echo "| Totalt antal rader | $TOTAL |"
|
||||
echo "| Dump | $DUMP |"
|
||||
echo
|
||||
if [ -n "$DIFF_OUT" ]; then
|
||||
echo '## Avvikelser'
|
||||
echo '```'
|
||||
echo "$DIFF_OUT"
|
||||
echo '```'
|
||||
else
|
||||
echo "Alla tabellers radantal identiska mellan original och återställning."
|
||||
fi
|
||||
} > "$PROTOKOLL"
|
||||
|
||||
cat "$PROTOKOLL"
|
||||
[ "$STATUS" = "GODKÄND" ]
|
||||
Reference in New Issue
Block a user