Files
teamvis-selfhost/deploy/selfhost/restore.sh
T

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."