#!/usr/bin/env bash # Spielt eine Sicherung in eine Wegwerf-Datenbank ein und prüft, ob alles # angekommen ist. Ein ungetestetes Backup ist keins — siehe docs/11-betrieb.md. # # scripts/restore-test.sh [container] [quelldatenbank] # # Legt `_restore_test` an, spielt einen frischen Dump hinein, vergleicht # Zeilenzahlen, Regeln und Trigger, und räumt danach auf. set -euo pipefail CONTAINER="${1:-afis-dev-db}" QUELLE="${2:-afis}" ZIEL="${QUELLE}_restore_test" NUTZER="afis" rot() { printf '\033[31m%s\033[0m\n' "$*"; } gruen() { printf '\033[32m%s\033[0m\n' "$*"; } info() { printf ' %s\n' "$*"; } psql_in() { docker exec "$CONTAINER" psql -U "$NUTZER" -d "$1" -tA -c "$2"; } docker exec "$CONTAINER" pg_isready -U "$NUTZER" -d "$QUELLE" >/dev/null 2>&1 \ || { rot "Container $CONTAINER antwortet nicht."; exit 1; } echo "Wiederherstellung prüfen: ${QUELLE} -> ${ZIEL}" info "Dump erzeugen" docker exec "$CONTAINER" pg_dump -U "$NUTZER" -d "$QUELLE" -Fc -f /tmp/restore-test.dump info "Zieldatenbank neu anlegen" docker exec "$CONTAINER" psql -U "$NUTZER" -d postgres -q \ -c "DROP DATABASE IF EXISTS \"${ZIEL}\";" -c "CREATE DATABASE \"${ZIEL}\";" info "Einspielen" # pg_restore meldet auf einer frischen Datenbank Warnungen zu Besitzrechten. # Die sind erwartbar; entscheidend ist der Vergleich danach. docker exec "$CONTAINER" pg_restore -U "$NUTZER" -d "$ZIEL" --no-owner \ /tmp/restore-test.dump >/dev/null 2>&1 || true FEHLER=0 info "Zeilen vergleichen" for TABELLE in Case CaseEntry Document PersonnelFile AuditLog ChatMessage SearchIndex; do A=$(psql_in "$QUELLE" "SELECT count(*) FROM \"$TABELLE\";" 2>/dev/null || echo "-") B=$(psql_in "$ZIEL" "SELECT count(*) FROM \"$TABELLE\";" 2>/dev/null || echo "-") if [ "$A" = "$B" ]; then info "$TABELLE: $A" else rot " $TABELLE: Quelle $A, Wiederherstellung $B" FEHLER=1 fi done # Ohne Regeln und Trigger wäre die Wiederherstellung eine Datenbank ohne die # harten Zusicherungen: löschbare Verlaufseinträge, kein Suchindex. REGELN=$(psql_in "$ZIEL" "SELECT count(*) FROM pg_rules WHERE schemaname='public';") TRIGGER=$(psql_in "$ZIEL" "SELECT count(*) FROM pg_trigger WHERE NOT tgisinternal;") info "Regeln: ${REGELN}, Trigger: ${TRIGGER}" [ "$REGELN" -ge 5 ] || { rot " Zu wenige Regeln: die Anhängigkeit fehlt."; FEHLER=1; } [ "$TRIGGER" -ge 5 ] || { rot " Zu wenige Trigger: Suchindex oder Wächter fehlen."; FEHLER=1; } # Stichprobe auf die wichtigste Regel überhaupt. psql_in "$ZIEL" "SELECT 1 FROM pg_rules WHERE rulename='entry_no_delete';" | grep -q 1 \ || { rot " entry_no_delete fehlt: Verlaufseinträge wären löschbar."; FEHLER=1; } info "Aufräumen" docker exec "$CONTAINER" psql -U "$NUTZER" -d postgres -q -c "DROP DATABASE IF EXISTS \"${ZIEL}\";" docker exec "$CONTAINER" rm -f /tmp/restore-test.dump if [ "$FEHLER" = "0" ]; then gruen "Wiederherstellung geprüft: alles angekommen." else rot "Wiederherstellung unvollständig." exit 1 fi