69 lines
3.5 KiB
Bash
Executable File
69 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Wiederherstellung einer selbst gehosteten TeamVis-Instanz (Variante „eigene
|
|
# DB“) aus den Sicherungen von backup.sh — in eine LEERE Datenbank: neuer
|
|
# Host, neues Volume, Totalverlust.
|
|
#
|
|
# Im Instanz-Verzeichnis aufrufen (docker-compose.yml + .env aus dem
|
|
# Passwort-Safe; ohne die originalen Secrets passen Keys und Passwörter nicht):
|
|
# bash restore.sh /pfad/db-JJJJ-MM-TT-HHMM.dump /pfad/storage-JJJJ-MM-TT-HHMM.tar.gz
|
|
#
|
|
# Bricht ab, wenn die Datenbank schon TeamVis-Daten enthält oder
|
|
# volumes/storage nicht leer ist. Über einen Bestand zurückspielen heißt also
|
|
# bewusst: `docker compose down`, Volume `<projekt>_db-data` löschen,
|
|
# volumes/storage beiseiteschieben — erst dann dieses Skript.
|
|
set -euo pipefail
|
|
|
|
die() { echo "✗ $*" >&2; exit 1; }
|
|
[ $# -eq 2 ] || die "Aufruf: restore.sh <db-….dump> <storage-….tar.gz>"
|
|
DUMP="$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
|
TAR="$(cd "$(dirname "$2")" && pwd)/$(basename "$2")"
|
|
[ -f "$DUMP" ] && [ -f "$TAR" ] || die "Dump oder Storage-Archiv fehlt."
|
|
[ -f docker-compose.yml ] && [ -f .env ] || die "Kein Instanz-Verzeichnis (docker-compose.yml + .env)."
|
|
if [ -d volumes/storage ] && [ -n "$(ls -A volumes/storage)" ]; then
|
|
die "volumes/storage ist nicht leer."
|
|
fi
|
|
|
|
# psql/pg_restore im db-Container, als supabase_admin mit dem Passwort aus
|
|
# dessen Umgebung — das Passwort taucht so in keiner Kommandozeile auf.
|
|
dbsh() { docker compose exec -T db sh -c "$1"; }
|
|
ADMIN='PGPASSWORD="$POSTGRES_PASSWORD" psql -h localhost -U supabase_admin -d "$POSTGRES_DB" -v ON_ERROR_STOP=1'
|
|
|
|
echo "→ Datenbank starten …"
|
|
docker compose up -d db
|
|
until dbsh 'pg_isready -U postgres -d "$POSTGRES_DB"' >/dev/null 2>&1; do sleep 2; done
|
|
# Das Image meldet sich bereit, bevor supabase_admin sein Passwort hat.
|
|
until dbsh "$ADMIN -tAc 'select 1'" >/dev/null 2>&1; do sleep 2; done
|
|
|
|
if [ "$(dbsh "$ADMIN -tAc \"select to_regclass('public.employees') is not null\"")" = "t" ]; then
|
|
die "Die Datenbank enthält schon TeamVis-Daten — nur in eine leere einspielen."
|
|
fi
|
|
|
|
echo "→ Rollen (Passwörter, bypassrls) …"
|
|
# Cluster-Eigenschaften, nicht im Dump. Wie install.sh: das Image setzt nur
|
|
# supabase_admin, die übrigen Dienste melden sich mit POSTGRES_PASSWORD an.
|
|
dbsh "$ADMIN -v pw=\"\$POSTGRES_PASSWORD\"" <<'SQL'
|
|
alter role authenticator with login password :'pw';
|
|
alter role supabase_storage_admin with login password :'pw';
|
|
alter role supabase_auth_admin with login password :'pw';
|
|
alter role service_role bypassrls;
|
|
SQL
|
|
|
|
echo "→ Dump einspielen …"
|
|
# Das Schema storage legt das Image selbst an (mit abhängigen Funktionen) —
|
|
# dessen DROP/CREATE aus dem Dump überspringen, alles darin wird ersetzt.
|
|
docker compose cp "$DUMP" db:/tmp/restore.dump >/dev/null
|
|
dbsh 'pg_restore -l /tmp/restore.dump | grep -v " SCHEMA - storage " > /tmp/restore.list'
|
|
dbsh 'PGPASSWORD="$POSTGRES_PASSWORD" pg_restore -h localhost -U supabase_admin -d "$POSTGRES_DB" --clean --if-exists --exit-on-error -L /tmp/restore.list /tmp/restore.dump'
|
|
dbsh 'rm -f /tmp/restore.dump /tmp/restore.list'
|
|
|
|
echo "→ Storage-Dateien …"
|
|
mkdir -p volumes
|
|
# Mit den erweiterten Attributen (Content-Type je Datei), siehe backup.sh.
|
|
tar --xattrs --xattrs-include='user.*' -xzf "$TAR" -C volumes
|
|
|
|
echo "→ Alle Dienste starten …"
|
|
docker compose up -d
|
|
|
|
echo "✔ Wiederhergestellt: $(dbsh "$ADMIN -tAc \"select count(*) || ' Karten, ' || (select count(*) from storage.objects) || ' Dateien' from public.employees\"")"
|
|
echo " Prüfen: Storage gesund (docker compose ps), Karte und Fotos im Browser, Admin-Login."
|