Prepare Immich restore smoke test
This commit is contained in:
@@ -55,13 +55,13 @@ Kontext bewusst gesichert, bevor weitere Live-Aenderungen passieren:
|
||||
| offen | Disk- und Share-TBDs eintragen | Modelle, Groessen, Seriennummern, Filesysteme und Cache-Settings sind dokumentiert |
|
||||
| erledigt (Skript + Host-Test) | Gitea-Repo-Mirror-Mechanik definieren | `ops/borg-ui/scripts/gitea-bundle-mirror.sh` erzeugt verifizierte Bundles unter `/mnt/user/backups/git-bundles/gitea`; Host-Erstlauf 2026-05-26: 4 Bundles, Checksums OK, `homelab-infra.bundle` klonbar und `git fsck` sauber; Schedule bleibt offen |
|
||||
| offen | Komodo-Bootstrap-Pfad beschreiben | Kaltstart ohne laufendes Komodo ist dokumentiert |
|
||||
| offen | Immich-Restore-Test planen | Testumfang, Datenpfade und Smoke-Test-Kriterium stehen fest |
|
||||
| erledigt | Immich-Restore-Test planen | Testumfang, Datenpfade und Smoke-Test-Kriterium sind in `docs/IMMICH_RESTORE_TEST.md`, `ops/restore-tests/immich-plan.md` und `ops/restore-tests/immich-runbook.md` festgehalten; erster Host-Lauf bleibt offen |
|
||||
|
||||
## Sprint 3 - Restore und Monitoring
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| offen | Immich-Restore-Test implementieren | Restore-Report landet unter `/mnt/user/backups/restore-reports/` |
|
||||
| in Arbeit (vorbereitet) | Immich-Restore-Test implementieren | `ops/restore-tests/immich-restore-test.sh`, `immich-compose.test.yml` und Dispatcher-Eintrag vorbereitet; lokaler `--what-if` erfolgreich; Abschluss erst nach echtem Host-Lauf mit Report unter `/mnt/user/backups/restore-reports/` |
|
||||
| offen | Borg-Stale-Alert bauen | Alarm feuert, wenn Borg-Archiv zu alt ist |
|
||||
| offen | TLS-Cert-Expiry-Alert bauen | Alarm feuert bei Restlaufzeit unter Schwellwert |
|
||||
| offen | Container-Down-Alert bauen | Unerwartet fehlende Container werden sichtbar |
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Immich Restore Test
|
||||
|
||||
Status: **vorbereitet, noch nicht live ausgefuehrt** (2026-05-26)
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Finding **F-11**
|
||||
|
||||
## Zweck
|
||||
|
||||
Schliesst die Audit-Luecke aus F-11: Immich ist der groesste Datentopf (Familien-Fotos), und bisher gibt es im Gegensatz zu Vaultwarden, Gitea und Paperless **keinen** verifizierten Mini-Restore-Test. Dieses Dokument verlinkt die Repo-Artefakte und beschreibt den Ablauf aus Operator-Sicht.
|
||||
|
||||
## Repo-Artefakte
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `ops/restore-tests/immich-compose.test.yml` | isoliertes Test-Compose: pgvecto-rs Postgres + Redis + Immich-Server, ML weggelassen, `127.0.0.1:12283` |
|
||||
| `ops/restore-tests/immich-restore-test.sh` | Host-Bash-Skript fuer den Lauf, mit `--what-if` und `--keep-data` Flags |
|
||||
| `ops/restore-tests/immich-restore-test.ps1` | Plan-Scaffold fuer Windows-Operator-Sicht (kein Live-Run) |
|
||||
| `ops/restore-tests/immich-plan.md` | Fachlicher Plan: Quellen, Schutzregeln, Smoke-Test-Kriterien, bekannte Risiken |
|
||||
| `ops/restore-tests/immich-runbook.md` | Konkreter Operator-Ablauf, Fehlerfaelle, Schedule-Vorschlag |
|
||||
|
||||
## Was der Test abdeckt
|
||||
|
||||
- Extraktion von `local/borg-dumps/latest/immich.dump` aus dem aktuellsten Borg-Archiv
|
||||
- Import in eine isolierte `tensorchord/pgvecto-rs:pg14-v0.2.0` Postgres-Instanz mit demselben Digest wie Produktion
|
||||
- Start eines isolierten Immich-Server-Containers mit demselben Digest wie Produktion, **ohne** ML-Container und **ohne** Traefik
|
||||
- Smoke-Test: Login-Seite erreichbar, `assets`- und `users`-Tabelle lesbar
|
||||
- Markdown-Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md`
|
||||
- Bereinigung von Test-Container und Restore-Lab-Daten nach Erfolg
|
||||
|
||||
## Was der Test bewusst NICHT abdeckt
|
||||
|
||||
- Wiederherstellung produktiver Foto-Dateien (`/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`). Diese Pfade werden vom Test nicht angefasst und nicht in den Test-Container gemountet.
|
||||
- Machine-Learning-Container. Spart Image-Pull-Zeit und RAM; ML-Features sind im Smoke-Test irrelevant.
|
||||
- Echte Login-Flow per API. Smoke-Test prueft nur, dass Login-Seite ausgeliefert wird.
|
||||
- Asset-Rendering / Thumbnail-Generierung. Ohne Foto-Files erwartet.
|
||||
- Produktive Domain `immich.kaleschke.info`. Test laeuft ausschliesslich auf `127.0.0.1:12283`.
|
||||
|
||||
## Restore-Stufe
|
||||
|
||||
Der Test deckt **Stufe 4 (kritische Anwendungen)** aus `docs/DISASTER_RECOVERY.md` Phase 4 fuer Immich ab, allerdings nur DB-Ebene und UI-Smoke. Voll-Restore inklusive Foto-Dateien aus Borg ist eigener Folgeschritt; das Skript bereitet die Restore-Lab-Struktur dafuer vor.
|
||||
|
||||
## Vor dem ersten echten Lauf
|
||||
|
||||
| Pruefung | Verantwortlich | Wo |
|
||||
|---|---|---|
|
||||
| Dump-Groesse von `immich.dump` bestimmen | Operator | `ls -lh /mnt/user/backups/borg/dumps/latest/immich.dump` |
|
||||
| Freier Platz unter `/mnt/user/backups/restore-lab/` | Operator | `df -h /mnt/user/backups` |
|
||||
| Borg-UI-Container laeuft | Operator | `docker ps | grep borg-ui` |
|
||||
| Trockenlauf mit `--what-if` | Operator | `bash ops/restore-tests/immich-restore-test.sh --what-if` |
|
||||
| Erster echter Lauf mit `--keep-data` zur Zeitmessung | Operator | `bash ops/restore-tests/immich-restore-test.sh --keep-data` |
|
||||
|
||||
## Nach dem ersten erfolgreichen Lauf
|
||||
|
||||
1. Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md` ueberpruefen.
|
||||
2. `docs/RESTORE_MATRIX.md` um den Mini-Restore-Beleg ergaenzen (Datum + Reportpfad), analog zu Paperless 2026-05-07.
|
||||
3. `ops/restore-tests/schedule.md` von "Immich spaeter" auf konkreten Quartals-Cron umstellen.
|
||||
4. `docs/AUDIT_2026-05-25_TODO.md` F-11 von "offen" auf "erledigt" stellen.
|
||||
5. `docs/MIGRATION_LOG.md` mit Mini-Lauf-Befund ergaenzen, ohne Secret-Werte.
|
||||
|
||||
## Schutzregeln
|
||||
|
||||
- Skript greift ausschliesslich auf den Restore-Lab-Pfad und den Borg-Extract-Cache zu.
|
||||
- Produktive Pfade unter `/mnt/user/photos/*` und `/mnt/user/appdata/immich_postgres/` werden nicht angefasst.
|
||||
- Produktive Container `immich_server`, `immich_postgres`, `immich_redis`, `immich_machine_learning` werden nicht gestoppt, nicht beruehrt.
|
||||
- Borg-Passphrase wird aus `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` gelesen und nicht in Reports, Logs oder Doku geschrieben.
|
||||
- Test-Container publishen nur auf `127.0.0.1:12283`, nicht auf LAN- oder Tailscale-Interface.
|
||||
- Keine Traefik-Labels, keine Public-URL fuer Testcontainer.
|
||||
|
||||
## Risiken (aus `ops/restore-tests/immich-plan.md`)
|
||||
|
||||
- Dump-Groesse und `pg_restore`-Dauer sind aktuell nicht gemessen.
|
||||
- pgvecto-rs Extension-Mismatch bei Image-Drift moeglich; Compose pinnt denselben Digest wie Produktion.
|
||||
- Immich-Server-Migrations koennen Startup nach Restore verzoegern; Skript pollt 120 s.
|
||||
- Bei Schema-Drift (z. B. nach Major-Update) brechen einzelne DB-Queries; das Skript faengt das tolerant ab und schreibt `n/a` in den Report.
|
||||
|
||||
## Naechste Operator-Schritte
|
||||
|
||||
1. Skript mit `--what-if` ausfuehren und den Plan-Output gegenpruefen.
|
||||
2. Dump-Groesse und freien Platz pruefen.
|
||||
3. Ersten echten Lauf mit `--keep-data` ausfuehren, Dauer messen.
|
||||
4. Bei Erfolg: Restore-Matrix, Schedule, Audit-TODO und Migration-Log nachziehen.
|
||||
5. Bei Fehler: Restore-Lab nicht selbst manuell bereinigen, sondern den Trap-Cleanup laufen lassen und ggf. Logs sichern, bevor erneut gestartet wird.
|
||||
@@ -17,6 +17,13 @@ Dieses Dokument ist nur noch ein historischer Verlauf. Der aktuelle operative Ab
|
||||
|
||||
## Historische Meilensteine
|
||||
|
||||
### 2026-05-26 - Immich Restore-Smoke-Test vorbereitet (F-11)
|
||||
|
||||
- `docs/IMMICH_RESTORE_TEST.md` und `ops/restore-tests/immich-plan.md`/`immich-runbook.md` beschreiben den geplanten Immich-Mini-Restore: `immich.dump` aus Borg, isolierter pgvecto-rs-Test-Postgres, Test-Redis, Immich-Server ohne ML, lokaler Port `127.0.0.1:12283`, keine produktiven Foto-Mounts.
|
||||
- `ops/restore-tests/immich-restore-test.sh`, `immich-restore-test.ps1` und `immich-compose.test.yml` wurden vorbereitet; der Dispatcher kennt `immich --what-if`.
|
||||
- Lokal verifiziert: Bash-Syntax, `run-restore-checks.sh immich --what-if`, PowerShell-Dispatcher `-Mode immich -WhatIf`, Docker-Compose-Render und Policy-Check. Kein echter Host-Restore, kein Borg-Extract, kein Produktiv-Container-Eingriff.
|
||||
- F-11 bleibt fachlich offen bis zum ersten Host-Lauf mit Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md`.
|
||||
|
||||
### 2026-05-26 - Audit F-16 und F-20 abgeschlossen (Doku-only)
|
||||
|
||||
- F-16: `infra/redis`-Etikett auf die Realitaet abgeglichen. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 13 und `docs/DISASTER_RECOVERY.md` Bootstrap-Stufe 2 beschreiben Redis jetzt als "primaer Paperless-Redis (App-Cache); historisch als shared angelegt, faktisch nur von Paperless genutzt". Immich, Nextcloud, Mealie eigene Redis-Instanzen; Authelia bewusst ohne Redis. Keine Compose-Aenderung.
|
||||
|
||||
@@ -46,7 +46,7 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`.
|
||||
|---|---|---|---|---|---|---|
|
||||
| Paperless-ngx | Borg + Dumps | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/paperless/export`, `/mnt/user/documents/scans_inbox` | `postgresql17-paperless.dump` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS`, `borg_repo_passphrase.txt` fuer Restore-Tests | PostgreSQL 17, Redis, Traefik | Web-UI startet, Dokumente vorhanden; Mini-Restore nach `/mnt/user/backups/restore-lab/paperless` am 2026-05-07 erfolgreich validiert |
|
||||
| Mealie | Borg + Dump | `/mnt/user/appdata/mealie/data`, optional `/mnt/user/appdata/mealie/postgres` bei lokalem Share-Weiterbetrieb | `mealie.dump` | `mealie_postgres_password.txt` | `mealie-postgres`, Traefik | UI startet, Rezepte vorhanden |
|
||||
| Immich | Borg + Dump | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | `immich.dump` | `IMMICH_DB_PASSWORD`, `immich_postgres_password.txt` | `immich_postgres`, `immich_redis`, Traefik | UI startet, Medienbibliothek sichtbar |
|
||||
| Immich | Borg + Dump | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | `immich.dump` | `IMMICH_DB_PASSWORD`, `immich_postgres_password.txt` | `immich_postgres`, `immich_redis`, Traefik | UI startet, Medienbibliothek sichtbar; Restore-Smoke-Test-Artefakte vorbereitet (`docs/IMMICH_RESTORE_TEST.md`), erster Host-Report noch offen |
|
||||
| Mail-Archiver | Borg + Shared Dump | `/mnt/user/appdata/mailarchiver/data-protection-keys` | `postgresql17-mailarchiver.dump` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | PostgreSQL 17, Traefik, Authelia | Authelia-Weiterleitung greift; nach Login startet die Web-UI und das Archiv laesst sich oeffnen |
|
||||
| Nextcloud | Borg + Dump | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | `nextcloud.dump` | `nextcloud_admin_user.txt`, `nextcloud_admin_password.txt`, `nextcloud_postgres_password.txt` | `nextcloud-postgres`, `nextcloud-redis`, Traefik | Web-UI startet, Login funktioniert, Dateien sichtbar |
|
||||
| Glance | Git / Borg-Repo | Repo-Konfiguration unter `ops/glance/config/glance.yml`; keine kritische Datenpersistenz | keine | `GLANCE_IMMICH_API_KEY`, `GLANCE_ADGUARD_USERNAME`, `GLANCE_ADGUARD_PASSWORD`, `GLANCE_SPEEDTEST_API_KEY` | Traefik, Authelia, optional interne API-Ziele | Dashboard startet, Widgets laden, Docker-Status laeuft nur ueber `glance-docker-socket-proxy` |
|
||||
|
||||
@@ -32,6 +32,11 @@ Ziel:
|
||||
- `paperless-restore-test.sh`: hosttauglicher Paperless-Restore-Job
|
||||
- `paperless-plan.md`: konkreter Paperless-Testplan
|
||||
- `paperless-compose.test.yml`: isolierte Testinstanz fuer Paperless inkl. Test-Postgres und Test-Redis
|
||||
- `immich-restore-test.ps1`: Immich-Mini-Restore-Ablauf als Plan-/Windows-Scaffold
|
||||
- `immich-restore-test.sh`: hosttauglicher Immich-Restore-Job, erster echter Lauf noch offen
|
||||
- `immich-plan.md`: konkreter Immich-Testplan
|
||||
- `immich-runbook.md`: Operator-Runbook fuer den ersten Immich-Lauf
|
||||
- `immich-compose.test.yml`: isolierte Testinstanz fuer Immich inkl. pgvecto-rs Test-Postgres und Test-Redis
|
||||
- `check-restore-freshness.ps1`: woechentlicher Frische-Check fuer Dumps und Reports
|
||||
- `run-restore-checks.ps1`: einfacher Dispatcher fuer Restore-Jobs
|
||||
- `check-restore-freshness.sh`: hosttauglicher Frische-Check
|
||||
@@ -76,9 +81,10 @@ Aktuell ist das erste validierte Muster vorhanden.
|
||||
- echter Vaultwarden-Restore am 2026-05-07 erfolgreich verifiziert
|
||||
- echter Gitea-Restore am 2026-05-07 erfolgreich verifiziert
|
||||
- echter Paperless-Restore am 2026-05-07 erfolgreich verifiziert
|
||||
- Immich-Restore-Test am 2026-05-26 vorbereitet; erster echter Lauf mit Report steht noch aus
|
||||
- Bash-Dispatcher und Bash-Restore-Jobs am 2026-05-07 erfolgreich hostseitig verifiziert
|
||||
- Restore-Lab und Report-Pfade auf dem Host angelegt
|
||||
- V1-Ablauf weiter ohne `ntfy`, mit Bereinigung nach Erfolg
|
||||
- naechster grosser Kandidat ist ein weiterer datenbankgestuetzter Dienst oder die Automatisierung
|
||||
- naechster grosser Kandidat ist der erste echte Immich-Lauf mit Zeitmessung; erst danach in die Rotation aufnehmen
|
||||
|
||||
Vor dem ersten echten Testlauf muessen Zielpfade, Quellpfade und Bereinigungsschritte bewusst freigegeben werden.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
services:
|
||||
restoretest-immich-postgres:
|
||||
# gleiches Image wie Produktion, damit pgvecto-rs / pgvector-Extensions
|
||||
# beim Restore aus immich.dump verfuegbar sind
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
|
||||
container_name: restoretest-immich-postgres
|
||||
restart: "no"
|
||||
environment:
|
||||
TZ: Europe/Berlin
|
||||
POSTGRES_USER: immich
|
||||
POSTGRES_DB: immich
|
||||
POSTGRES_PASSWORD: restoretest-immich-db
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
volumes:
|
||||
- /mnt/user/backups/restore-lab/immich/postgres:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U immich -d immich"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
restoretest-immich-redis:
|
||||
image: redis:7.4-alpine
|
||||
container_name: restoretest-immich-redis
|
||||
restart: "no"
|
||||
command:
|
||||
- redis-server
|
||||
- --save
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
restoretest-immich-server:
|
||||
# gleiches Image wie Produktion; ML-Container bleibt bewusst weg,
|
||||
# weil der Smoke-Test nur Login-Page, DB-Restore und Asset-Count prueft.
|
||||
image: ghcr.io/immich-app/immich-server:release@sha256:c15bff75068effb03f4355997d03dc7e0fc58720c2b54ad6f7f10d1bc57efaa5
|
||||
container_name: restoretest-immich-server
|
||||
restart: "no"
|
||||
depends_on:
|
||||
restoretest-immich-postgres:
|
||||
condition: service_healthy
|
||||
restoretest-immich-redis:
|
||||
condition: service_started
|
||||
environment:
|
||||
DB_HOSTNAME: restoretest-immich-postgres
|
||||
DB_USERNAME: immich
|
||||
DB_PASSWORD: restoretest-immich-db
|
||||
DB_DATABASE_NAME: immich
|
||||
REDIS_HOSTNAME: restoretest-immich-redis
|
||||
# ML bewusst deaktiviert: Endpoint zeigt auf eine lokale, nicht
|
||||
# erreichbare URL. Immich-Server startet, ML-Features bleiben aus.
|
||||
IMMICH_MACHINE_LEARNING_URL: http://restoretest-immich-ml-disabled:9999
|
||||
TZ: Europe/Berlin
|
||||
ports:
|
||||
# nur 127.0.0.1 - keine Public-Route, keine Traefik-Labels
|
||||
- "127.0.0.1:12283:2283"
|
||||
volumes:
|
||||
# Test-Upload-Verzeichnis ist leer und liegt im Restore-Lab.
|
||||
# Produktive Assets unter /mnt/user/photos/immich werden NICHT eingebunden,
|
||||
# damit der Smoke-Test keine produktiven Daten anfasst.
|
||||
- /mnt/user/backups/restore-lab/immich/upload:/usr/src/app/upload
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
@@ -0,0 +1,89 @@
|
||||
# Immich Restore Test Plan
|
||||
|
||||
## Ziel
|
||||
|
||||
Nachweisen, dass `immich.dump` aus dem produktiven Borg-Archiv in einer isolierten Testumgebung wieder einspielbar ist und Immich-Server damit anlaufen, einloggen und Asset-Metadaten anzeigen kann.
|
||||
|
||||
Bewusst **nicht** Teil dieses Tests:
|
||||
|
||||
- Wiederherstellung produktiver Foto-Dateien aus `/mnt/user/photos/immich` und `/mnt/user/photos/family_archive`. Der Smoke-Test bleibt DB-/UI-zentriert.
|
||||
- Machine-Learning-Container. Spart Image-Pull-Zeit und Resource-Last; ML-Features sind im Smoke-Test nicht erforderlich.
|
||||
- Echte Browser-Login-Sequenz. Smoke-Test prueft nur, dass die Login-Seite ausgeliefert wird und die DB-Tabellen `assets` und `users` lesbar sind.
|
||||
|
||||
## Quelle
|
||||
|
||||
- Backup-Quelle: produktives Borg-Archiv (`hetzner_borg_appdata_critical` oder lokales Mirror)
|
||||
- fachlich relevanter Dump im Archiv:
|
||||
- `local/borg-dumps/latest/immich.dump`
|
||||
- Erzeuger: `ops/borg-ui/scripts/pre-backup-dumps.sh`, Funktion `dump_pg_db immich_postgres ... immich immich` mit `pg_dump -Fc`
|
||||
- produktive Foto-Pfade werden im Smoke-Test bewusst **nicht** angefasst
|
||||
|
||||
## Test-Ziel
|
||||
|
||||
- Restore-Lab: `/mnt/user/backups/restore-lab/immich`
|
||||
- Testdatenpfade:
|
||||
- `/mnt/user/backups/restore-lab/immich/postgres` (Test-Postgres-Datadir)
|
||||
- `/mnt/user/backups/restore-lab/immich/upload` (leeres Upload-Volume, Immich-Server braucht den Pfad nur als Mountpoint)
|
||||
- `/mnt/user/backups/restore-lab/immich/dumps/latest/immich.dump` (extrahierter Dump)
|
||||
- Testcontainer:
|
||||
- `restoretest-immich-server`
|
||||
- `restoretest-immich-postgres` (`tensorchord/pgvecto-rs:pg14-v0.2.0` - identisch zur Produktion, weil der Dump pgvecto-rs Extension referenziert)
|
||||
- `restoretest-immich-redis` (`redis:7.4-alpine`, rebuildbar)
|
||||
- Testport Web: `127.0.0.1:12283:2283`
|
||||
- Report-Ziel: `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md`
|
||||
|
||||
## Schutzregeln
|
||||
|
||||
- produktive Pfade `/mnt/user/photos/immich` und `/mnt/user/photos/family_archive` werden **nicht** in den Test-Container gemountet
|
||||
- produktive Domain `immich.kaleschke.info` wird **nicht** uebernommen
|
||||
- keine Traefik-Labels fuer die Testinstanz
|
||||
- keine produktive `immich_postgres`-/`immich_redis`-Instanz fuer den Test verwenden
|
||||
- ML-Container bleibt weg
|
||||
- Testcontainer publishen nur auf `127.0.0.1`, nicht auf LAN- oder Tailscale-Interface
|
||||
- Borg-Passphrase wird aus `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` gelesen und niemals in Logs, Reports oder Doku geschrieben
|
||||
|
||||
## Geplanter Ablauf
|
||||
|
||||
1. Restore-Ziel unter `/mnt/user/backups/restore-lab/immich` vorbereiten (postgres, upload, dumps/latest)
|
||||
2. `local/borg-dumps/latest/immich.dump` aus dem aktuellsten Borg-Archiv extrahieren
|
||||
3. Test-Postgres (`pgvecto-rs`) und Test-Redis mit `ops/restore-tests/immich-compose.test.yml` starten
|
||||
4. `immich.dump` in Test-Postgres importieren (`pg_restore -Fc --clean --if-exists --no-owner --no-privileges`)
|
||||
5. Testinstanz `restoretest-immich-server` starten
|
||||
6. lokalen Smoke-Test gegen `http://127.0.0.1:12283` ausfuehren und Asset/User-Count aus DB lesen
|
||||
7. Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md` schreiben
|
||||
8. Testcontainer stoppen und Restore-Lab bereinigen
|
||||
|
||||
## Smoke-Test
|
||||
|
||||
Minimal erfolgreich:
|
||||
|
||||
- Test-Postgres startet `healthy`
|
||||
- `pg_restore -Fc` laeuft ohne Fehler durch
|
||||
- Immich-Server liefert HTTP `200`, `302` oder `303` auf `/`
|
||||
- Response enthaelt mindestens einen der Marker `Immich`, `Login`, `Signin`
|
||||
- `select count(*) from assets;` und `select count(*) from users;` sind lesbar
|
||||
|
||||
Optional spaeter:
|
||||
|
||||
- Echte Login-Form via API ansprechen
|
||||
- pgvecto-rs Extension explizit per `\dx` pruefen
|
||||
- Test mit gemountetem **read-only** Foto-Sample-Pfad und Thumbnail-Rendering
|
||||
- Test inkl. ML-Container, sobald genug Test-Ressourcen verfuegbar
|
||||
|
||||
## Bekannte Komplikationen
|
||||
|
||||
| Risiko | Beschreibung | Mitigation |
|
||||
|---|---|---|
|
||||
| Dump-Groesse unbekannt | `pg_dump -Fc` der Immich-DB kann je nach Asset-/Face-Tabellen mehrere GB sein | Erster Lauf bewusst mit `--what-if`, anschliessend Operator-Test mit Zeitmessung |
|
||||
| `pg_restore`-Dauer unbekannt | Index-/Constraint-Aufbau und pgvecto-rs-Index-Build koennen lange dauern | Test-Postgres mit Health-Polling startet; Lauf nicht abbrechen ohne `pg_restore`-Exit |
|
||||
| pgvecto-rs Extension-Mismatch | Wenn das pgvecto-rs-Image im Test nicht exakt dieselbe Version wie Produktion ist, kann `CREATE EXTENSION vectors` im Restore fehlschlagen | Compose pinnt denselben Digest wie `apps/immich/docker-compose.yml` |
|
||||
| Immich-Server-Migrations beim Start | Immich fuehrt beim ersten Start DB-Migrations aus; das kann nach Restore noch laufen, bevor Web-UI antwortet | Smoke-Test pollt HTTP bis zu 120 s, bevor er als Fehler markiert |
|
||||
| Asset-Files fehlen | Der Test mountet kein Foto-Volume; Immich zeigt "missing" auf Asset-Detail-Seiten | Smoke-Test prueft nur Login-Page und DB-Counts, nicht Asset-Rendering |
|
||||
| ML-Endpoint unreachable | Immich-Server kann ML-Endpoint nicht erreichen | `IMMICH_MACHINE_LEARNING_URL` zeigt bewusst auf einen nicht erreichbaren Hostnamen; Login bleibt funktional, ML-Features bleiben deaktiviert |
|
||||
|
||||
## Noch offen vor dem ersten echten Lauf
|
||||
|
||||
- Dump-Groesse `immich.dump` auf dem Host bestimmen (`ls -lh /mnt/user/backups/borg/dumps/latest/immich.dump`)
|
||||
- Erwartete Restore-Dauer durch ersten Lauf mit `--keep-data` messen
|
||||
- Pruefen, ob die Immich-Tabellen `assets`/`users` im aktuellen Schema noch existieren (Schema-Drift bei Major-Update wuerde die Asset-Count-Query brechen, das Skript faengt das tolerant ab)
|
||||
- Schedule-Eintrag in `ops/restore-tests/schedule.md`: aktuell ist Immich nur als "spaeter, eigener Sprint" gefuehrt. Erst nach erstem erfolgreichen Lauf in Schedule aufnehmen, z. B. quartalsweise.
|
||||
@@ -0,0 +1,44 @@
|
||||
param(
|
||||
[string]$BackupSource = "/mnt/user/backups/borg",
|
||||
[string]$DumpSource = "/mnt/user/backups/borg/dumps/latest/immich.dump",
|
||||
[string]$RestoreRoot = "/mnt/user/backups/restore-lab/immich",
|
||||
[string]$ReportRoot = "/mnt/user/backups/restore-reports",
|
||||
[string]$BorgPassphraseFile = "/mnt/user/appdata/secrets/borg_repo_passphrase.txt",
|
||||
[switch]$WhatIf
|
||||
)
|
||||
|
||||
$Mode = if ($WhatIf) { "WhatIf" } else { "PlanOnly" }
|
||||
|
||||
Write-Output "Immich restore test scaffold"
|
||||
Write-Output "BackupSource: $BackupSource"
|
||||
Write-Output "DumpSource: $DumpSource"
|
||||
Write-Output "RestoreRoot: $RestoreRoot"
|
||||
Write-Output "ReportRoot: $ReportRoot"
|
||||
Write-Output "BorgPassphraseFile: $BorgPassphraseFile"
|
||||
Write-Output "Expected Borg source paths inside archive:"
|
||||
Write-Output " - local/borg-dumps/latest/immich.dump"
|
||||
Write-Output ""
|
||||
Write-Output "Planned isolation:"
|
||||
Write-Output " - Test Postgres: tensorchord/pgvecto-rs:pg14-v0.2.0 (same as production)"
|
||||
Write-Output " - Test Redis: redis:7.4-alpine (rebuildable, no restore needed)"
|
||||
Write-Output " - Test Server: ghcr.io/immich-app/immich-server:release (pinned digest like production)"
|
||||
Write-Output " - ML container: deliberately omitted"
|
||||
Write-Output " - Test endpoint: 127.0.0.1:12283 (no Traefik, no public domain)"
|
||||
Write-Output " - Productive photo paths under /mnt/user/photos/* will NOT be mounted"
|
||||
Write-Output "Mode: $Mode"
|
||||
Write-Output ""
|
||||
Write-Output "Planned steps:"
|
||||
Write-Output "1. Prepare restore-lab target under /mnt/user/backups/restore-lab/immich"
|
||||
Write-Output "2. Extract immich.dump from current Borg archive into test path"
|
||||
Write-Output ' Template: borg extract "$BORG_REPO" "::ARCHIVE_NAME" local/borg-dumps/latest/immich.dump'
|
||||
Write-Output ' Passphrase source: $(cat /mnt/user/appdata/secrets/borg_repo_passphrase.txt)'
|
||||
Write-Output "3. Start isolated test Postgres (pgvecto-rs) and test Redis"
|
||||
Write-Output "4. Import immich.dump into test Postgres with pg_restore -Fc --clean --if-exists --no-owner --no-privileges"
|
||||
Write-Output "5. Start restoretest-immich-server against isolated DB/Redis (ML omitted)"
|
||||
Write-Output "6. Run smoke checks against http://127.0.0.1:12283 and DB asset count"
|
||||
Write-Output "7. Write markdown report under /mnt/user/backups/restore-reports"
|
||||
Write-Output "8. Stop test containers and clean restore data after success"
|
||||
Write-Output ""
|
||||
Write-Output "This script is intentionally a scaffold only."
|
||||
Write-Output "No restore, no dump import, no container start, no file write is executed yet."
|
||||
Write-Output "Actual run happens on the Unraid host via ops/restore-tests/immich-restore-test.sh"
|
||||
Executable
+172
@@ -0,0 +1,172 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Immich Restore Smoke Test
|
||||
#
|
||||
# Nicht-destruktiver Restore-Smoke-Test fuer Immich.
|
||||
# - liest immich.dump aus dem produktiven Borg-Archiv
|
||||
# - importiert in eine isolierte Test-Postgres-Instanz mit gleichem Image
|
||||
# wie Produktion (tensorchord/pgvecto-rs)
|
||||
# - startet einen isolierten Immich-Server-Container ohne Traefik und
|
||||
# ohne ML-Container
|
||||
# - prueft Login-Page und Asset-Anzahl aus DB
|
||||
# - bereinigt anschliessend
|
||||
#
|
||||
# Produktiver Immich-Stack wird NICHT angefasst.
|
||||
# Produktive Foto-Pfade unter /mnt/user/photos/* werden NICHT gemountet.
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
. "$SCRIPT_DIR/common.sh"
|
||||
|
||||
WHATIF=0
|
||||
KEEP_DATA=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--what-if) WHATIF=1 ;;
|
||||
--keep-data) KEEP_DATA=1 ;;
|
||||
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
RESTORE_ROOT="/mnt/user/backups/restore-lab/immich"
|
||||
REPORT_ROOT="/mnt/user/backups/restore-reports"
|
||||
EXTRACT_DIR="$BORG_RESTORE_HOST_ROOT/immich-extract"
|
||||
COMPOSE_FILE="$SCRIPT_DIR/immich-compose.test.yml"
|
||||
REPORT_FILE="$REPORT_ROOT/immich-$(date +%F).md"
|
||||
|
||||
if [ "$WHATIF" -eq 1 ]; then
|
||||
cat <<EOF
|
||||
Immich restore test
|
||||
Mode: WhatIf
|
||||
RestoreRoot: $RESTORE_ROOT
|
||||
ReportRoot: $REPORT_ROOT
|
||||
Expected Borg source paths:
|
||||
- local/borg-dumps/latest/immich.dump
|
||||
Planned isolation:
|
||||
- Test-Postgres: tensorchord/pgvecto-rs:pg14-v0.2.0
|
||||
- Test-Redis: redis:7.4-alpine (rebuildbar, kein Restore)
|
||||
- Test-Server: ghcr.io/immich-app/immich-server:release (Image-Pin wie Produktion)
|
||||
- ML-Container bewusst weggelassen
|
||||
- Test-Upload: leer, unter $RESTORE_ROOT/upload
|
||||
- Productive photo paths NOT mounted: /mnt/user/photos/immich, /mnt/user/photos/family_archive
|
||||
- Test endpoint: 127.0.0.1:12283 (no Traefik, no public domain)
|
||||
Smoke-Test:
|
||||
- Test-Postgres healthy
|
||||
- pg_restore -Fc -> immich.dump
|
||||
- HTTP 200/302/3xx von 127.0.0.1:12283
|
||||
- Asset-Count aus DB
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
require_cmd docker
|
||||
require_cmd curl
|
||||
require_path "$BORG_PASSPHRASE_FILE_DEFAULT"
|
||||
require_path "$COMPOSE_FILE"
|
||||
|
||||
cleanup() {
|
||||
cleanup_compose "$COMPOSE_FILE"
|
||||
if [ "$KEEP_DATA" -ne 1 ]; then
|
||||
rm -rf "$RESTORE_ROOT"
|
||||
fi
|
||||
rm -rf "$EXTRACT_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
rm -rf "$EXTRACT_DIR" "$RESTORE_ROOT"
|
||||
mkdir -p "$RESTORE_ROOT/postgres" "$RESTORE_ROOT/upload" "$RESTORE_ROOT/dumps/latest"
|
||||
|
||||
archive="$(latest_archive_name)"
|
||||
repo="$(borg_repo_url)"
|
||||
|
||||
borg_extract "/restore/immich-extract" \
|
||||
"local/borg-dumps/latest/immich.dump"
|
||||
|
||||
mv "$EXTRACT_DIR/local/borg-dumps/latest/immich.dump" "$RESTORE_ROOT/dumps/latest/immich.dump"
|
||||
|
||||
# Stufe 1: Test-Postgres und Test-Redis starten
|
||||
docker compose -f "$COMPOSE_FILE" up -d \
|
||||
restoretest-immich-postgres restoretest-immich-redis >/dev/null
|
||||
|
||||
# Warten auf Postgres ready
|
||||
until docker exec restoretest-immich-postgres pg_isready -U immich -d immich >/dev/null 2>&1; do
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Stufe 2: Dump in Test-Postgres importieren
|
||||
# Hinweis: pg_restore mit --clean --if-exists, damit die Operation idempotent ist.
|
||||
# --no-owner / --no-privileges, weil im Test-Postgres kein produktiver User existiert.
|
||||
docker exec -i restoretest-immich-postgres \
|
||||
pg_restore -U immich -d immich --clean --if-exists --no-owner --no-privileges \
|
||||
< "$RESTORE_ROOT/dumps/latest/immich.dump"
|
||||
|
||||
# Stufe 3: Immich-Server starten (ohne ML)
|
||||
docker compose -f "$COMPOSE_FILE" up -d restoretest-immich-server >/dev/null
|
||||
|
||||
# Immich-Server braucht beim ersten Start einige Sekunden fuer DB-Migrations-Checks.
|
||||
# Wir geben ihm bis zu 120s und pollen den HTTP-Endpunkt.
|
||||
http_status=""
|
||||
for _ in $(seq 1 60); do
|
||||
http_status="$(curl -s -o /tmp/immich-body.html -w '%{http_code}' -L http://127.0.0.1:12283 || true)"
|
||||
if [ "$http_status" = "200" ] || [ "$http_status" = "302" ] || [ "$http_status" = "303" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Body-Check: Immich-UI hat typische Marker. Wir matchen tolerant.
|
||||
body_check="ok"
|
||||
if ! grep -qiE "immich|login|signin" /tmp/immich-body.html 2>/dev/null; then
|
||||
body_check="missing-marker"
|
||||
fi
|
||||
|
||||
# Asset-Count aus DB. Wenn die Spalte nicht existiert (Schema-Drift),
|
||||
# wird das im Report sichtbar gemacht statt das Skript zu killen.
|
||||
asset_count="$(docker exec restoretest-immich-postgres \
|
||||
psql -U immich -d immich -tAc "select count(*) from assets;" 2>/dev/null \
|
||||
| tr -d '[:space:]' || true)"
|
||||
if [ -z "$asset_count" ]; then
|
||||
asset_count="n/a"
|
||||
fi
|
||||
|
||||
# User-Count als zusaetzlicher DB-Sanity-Check
|
||||
user_count="$(docker exec restoretest-immich-postgres \
|
||||
psql -U immich -d immich -tAc "select count(*) from users;" 2>/dev/null \
|
||||
| tr -d '[:space:]' || true)"
|
||||
if [ -z "$user_count" ]; then
|
||||
user_count="n/a"
|
||||
fi
|
||||
|
||||
write_report "$REPORT_FILE" <<EOF
|
||||
# Immich Restore Test Report - $(date +%F)
|
||||
|
||||
- Service: \`immich\`
|
||||
- Source repo: \`$repo\`
|
||||
- Archive: \`$archive\`
|
||||
- Restore root: \`$RESTORE_ROOT\`
|
||||
- Test containers:
|
||||
- \`restoretest-immich-server\`
|
||||
- \`restoretest-immich-postgres\` (tensorchord/pgvecto-rs:pg14-v0.2.0)
|
||||
- \`restoretest-immich-redis\`
|
||||
- Test endpoint: \`http://127.0.0.1:12283\`
|
||||
- ML container: deliberately omitted
|
||||
- Result: \`SUCCESS\`
|
||||
|
||||
## Checks
|
||||
|
||||
- Borg extract of \`immich.dump\`: \`ok\`
|
||||
- Dump import into isolated Postgres: \`ok\`
|
||||
- HTTP status after redirect: \`$http_status\`
|
||||
- Login page marker: \`$body_check\`
|
||||
- Asset count in test DB: \`$asset_count\`
|
||||
- User count in test DB: \`$user_count\`
|
||||
|
||||
## Notes
|
||||
|
||||
- Test ran without Traefik and without the productive domain.
|
||||
- Productive photo paths under /mnt/user/photos/* were NOT mounted.
|
||||
- Test data was cleaned after success: \`$([ "$KEEP_DATA" -eq 1 ] && echo no || echo yes)\`
|
||||
- Restore-Quelle Dump: \`local/borg-dumps/latest/immich.dump\` aus aktuellem Borg-Archiv.
|
||||
EOF
|
||||
|
||||
echo "Immich restore test ok -> $REPORT_FILE"
|
||||
@@ -0,0 +1,128 @@
|
||||
# Immich Restore Runbook
|
||||
|
||||
## Status
|
||||
|
||||
Skript und Test-Compose sind vorbereitet. **Erster echter Lauf steht noch aus.**
|
||||
|
||||
Vor dem ersten Lauf muss Operator entscheiden:
|
||||
|
||||
- ist genug freier Platz unter `/mnt/user/backups/restore-lab/immich` vorhanden (Dump + Test-Postgres-Datadir + Upload-Dummy)?
|
||||
- ist genug freier RAM/CPU verfuegbar, um Immich-Server + Test-Postgres parallel zur produktiven Last laufen zu lassen?
|
||||
- soll der Lauf zuerst mit `--what-if` ausgefuehrt werden, dann mit `--keep-data` zur Zeitmessung?
|
||||
|
||||
## Vorbedingungen
|
||||
|
||||
- Borg-Quelle ist verfuegbar
|
||||
- Borg-UI laeuft (`docker ps | grep borg-ui`)
|
||||
- Borg-Passphrase-Datei vorhanden: `/mnt/user/appdata/secrets/borg_repo_passphrase.txt`
|
||||
- aktueller Dump `immich.dump` ist Teil des letzten Borg-Archivs (siehe `pre-backup-dumps.sh`)
|
||||
- Testpfade unter `/mnt/user/backups/restore-lab/` und `/mnt/user/backups/restore-reports/` sind freigegeben
|
||||
- produktiver Immich-Stack laeuft (oder ist bewusst aus); der Test ist davon unabhaengig
|
||||
|
||||
## Bestaetigter Host-Stand (Soll)
|
||||
|
||||
- produktiver Immich-Server: `immich_server` Container mit Image `ghcr.io/immich-app/immich-server:release@sha256:c15bff75068effb03f4355997d03dc7e0fc58720c2b54ad6f7f10d1bc57efaa5`
|
||||
- produktive Postgres: `immich_postgres` mit `tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52`
|
||||
- produktive Foto-Pfade: `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`
|
||||
- aktueller Dump-Pfad: `/mnt/user/backups/borg/dumps/latest/immich.dump`
|
||||
- Secret: `/mnt/user/appdata/secrets/immich_postgres_password.txt` (wird vom Test **nicht** gebraucht; Test nutzt eigenes Test-Passwort)
|
||||
|
||||
## Bestaetigter Teststand
|
||||
|
||||
- noch kein echter Mini-Restore gelaufen
|
||||
- Skript-Set vorbereitet:
|
||||
- `ops/restore-tests/immich-compose.test.yml`
|
||||
- `ops/restore-tests/immich-restore-test.sh`
|
||||
- `ops/restore-tests/immich-restore-test.ps1` (Scaffold, kein Live-Run)
|
||||
- `ops/restore-tests/immich-plan.md`
|
||||
- `ops/restore-tests/immich-runbook.md`
|
||||
|
||||
## Erster Lauf - trockene Variante
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab-infra/ops/restore-tests/immich-restore-test.sh --what-if
|
||||
```
|
||||
|
||||
Erwartete Ausgabe: nur Plan-Output, kein Docker-Start, kein Borg-Extract.
|
||||
|
||||
## Erster Lauf - echter Test (Operator-freigegeben)
|
||||
|
||||
```bash
|
||||
# Optional: laufende Borg-Jobs pruefen, damit Borg-UI nicht parallel ausgelastet ist
|
||||
docker exec borg-ui sqlite3 /data/borg.db \
|
||||
"select status, archive_name, datetime(updated_at,'unixepoch') from backup_jobs order by id desc limit 5;"
|
||||
|
||||
# Lauf mit Datenerhalt fuer Zeitmessung
|
||||
bash /mnt/user/services/homelab-infra/ops/restore-tests/immich-restore-test.sh --keep-data
|
||||
```
|
||||
|
||||
Bei erfolgreichem Lauf:
|
||||
|
||||
- Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md`
|
||||
- Test-Container `restoretest-immich-*` sind nach Lauf bereits `down`
|
||||
- Restore-Lab-Daten bleiben mit `--keep-data` erhalten; ohne Flag werden sie geloescht
|
||||
|
||||
## Smoke-Test-Pruefungen
|
||||
|
||||
Minimal erwartet im Report:
|
||||
|
||||
- `HTTP status after redirect: 200|302|303`
|
||||
- `Login page marker: ok`
|
||||
- `Asset count in test DB`: Zahl, oder `n/a` bei Schema-Drift
|
||||
- `User count in test DB`: Zahl, oder `n/a` bei Schema-Drift
|
||||
- Pre-Dump-Hook-Kette (`pg_dump -Fc`) und Restore-Kette (`pg_restore -Fc`) sind kompatibel
|
||||
- pgvecto-rs Extension ist im Restore-DB sichtbar
|
||||
|
||||
Manuelle Folgepruefung (optional):
|
||||
|
||||
Das Skript stoppt die Test-Container auch bei `--keep-data`; dieses Flag erhaelt nur die Restore-Lab-Daten. Fuer eine manuelle Folgepruefung nach einem erfolgreichen `--keep-data`-Lauf die Testinstanz kurz wieder hochfahren und danach wieder stoppen:
|
||||
|
||||
```bash
|
||||
docker compose -f /mnt/user/services/homelab-infra/ops/restore-tests/immich-compose.test.yml up -d \
|
||||
restoretest-immich-postgres restoretest-immich-redis restoretest-immich-server
|
||||
|
||||
docker exec restoretest-immich-postgres psql -U immich -d immich -c "\dx"
|
||||
docker exec restoretest-immich-postgres psql -U immich -d immich -tAc "select count(*) from assets;"
|
||||
docker logs --tail 100 restoretest-immich-server
|
||||
|
||||
docker compose -f /mnt/user/services/homelab-infra/ops/restore-tests/immich-compose.test.yml down
|
||||
```
|
||||
|
||||
## Cleanup nach Lauf ohne `--keep-data`
|
||||
|
||||
Das Skript bereinigt:
|
||||
|
||||
- Test-Container via `docker compose down`
|
||||
- Restore-Lab unter `/mnt/user/backups/restore-lab/immich`
|
||||
- Extract-Cache unter `/mnt/user/appdata/borg-ui/restore/immich-extract`
|
||||
|
||||
**Vorsicht:** `rm -rf` arbeitet ausschliesslich auf dem festen Restore-Lab-Pfad. Produktive Immich-Pfade unter `/mnt/user/photos/*` werden vom Skript niemals beschrieben.
|
||||
|
||||
## Fehlerfaelle
|
||||
|
||||
| Symptom | Ursache | Massnahme |
|
||||
|---|---|---|
|
||||
| `pg_restore: error: could not find extension ... vectors` | Test-Postgres-Image nicht pgvecto-rs | Compose-Pin im Test-Compose pruefen |
|
||||
| HTTP-Timeout nach 120 s | Immich-Migrations laufen noch | Wartezeit im Skript erhoehen oder Logs pruefen |
|
||||
| `pg_isready` nie healthy | Test-Postgres bricht beim Start ab (Datadir-Konflikt) | Restore-Lab vor Lauf vollstaendig leer; `docker logs restoretest-immich-postgres` |
|
||||
| Body matcht keine Marker | Immich UI hat sich versioniert; Marker-Liste anpassen | Marker im Skript erweitern (`grep -qiE`) |
|
||||
| Disk-Space-Mangel | Dump + Postgres-Datadir + Extract-Cache | mehr Platz freigeben oder Lauf abbrechen |
|
||||
|
||||
## Schedule-Eintrag (geplant, noch nicht aktiv)
|
||||
|
||||
Aktuell in `ops/restore-tests/schedule.md` nur als "spaeter, eigener Sprint" gelistet.
|
||||
|
||||
Nach erstem erfolgreichen Lauf vorschlagen:
|
||||
|
||||
- quartalsweise (`0 9 1 1,4,7,10 *` o. ae.)
|
||||
- ohne `--keep-data`
|
||||
- Report wird automatisch von `monthly-random-restore.sh` mit eingelesen, sobald Immich dort eintragbar ist
|
||||
|
||||
## Festgelegte Entscheidungen
|
||||
|
||||
- Immich-Restore-Test nutzt isoliertes Test-Postgres mit gleichem Image wie Produktion.
|
||||
- ML-Container wird im Smoke-Test **nicht** mitgestartet.
|
||||
- Produktive Foto-Pfade werden **nicht** in den Test gemountet.
|
||||
- Test-Daten werden nach erfolgreichem Lauf geloescht (`--keep-data` ueberschreibt das).
|
||||
- Borg-Passphrase wird aus Host-Secret-Datei gelesen und nirgendwo geloggt.
|
||||
- `ntfy` wird im ersten echten Lauf nicht eingebunden.
|
||||
@@ -1,5 +1,5 @@
|
||||
param(
|
||||
[ValidateSet("freshness","vaultwarden","gitea","paperless")]
|
||||
[ValidateSet("freshness","vaultwarden","gitea","paperless","immich")]
|
||||
[string]$Mode,
|
||||
[switch]$WhatIf
|
||||
)
|
||||
@@ -35,4 +35,12 @@ switch ($Mode) {
|
||||
}
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
"immich" {
|
||||
if ($WhatIf) {
|
||||
& (Join-Path $base "immich-restore-test.ps1") -WhatIf
|
||||
} else {
|
||||
& (Join-Path $base "immich-restore-test.ps1")
|
||||
}
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,14 @@ case "$MODE" in
|
||||
fi
|
||||
exec "$SCRIPT_DIR/paperless-restore-test.sh"
|
||||
;;
|
||||
immich)
|
||||
if [ "$WHATIF" = "--what-if" ]; then
|
||||
exec "$SCRIPT_DIR/immich-restore-test.sh" --what-if
|
||||
fi
|
||||
exec "$SCRIPT_DIR/immich-restore-test.sh"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {freshness|vaultwarden|gitea|paperless} [--what-if]" >&2
|
||||
echo "Usage: $0 {freshness|vaultwarden|gitea|paperless|immich} [--what-if]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -7,7 +7,7 @@ SUCCESS_TOPIC="${2:-${RESTORE_SUCCESS_TOPIC:-homelab-info}}"
|
||||
FAILURE_TOPIC="${RESTORE_FAILURE_TOPIC:-homelab-alerts}"
|
||||
|
||||
if [ -z "$MODE" ]; then
|
||||
echo "Usage: $0 <freshness|vaultwarden|gitea|paperless> [success_topic]" >&2
|
||||
echo "Usage: $0 <freshness|vaultwarden|gitea|paperless|immich> [success_topic]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Quartalsweise:
|
||||
|
||||
Spaeter:
|
||||
|
||||
- `immich` als eigener Sprint
|
||||
- `immich` Restore-Smoke-Test ist vorbereitet, aber noch nicht in der Rotation. Erst manuell mit `--what-if`, dann mit `--keep-data` ausfuehren; nach erfolgreichem Report quartalsweise einplanen.
|
||||
|
||||
## Konkreter Kalender
|
||||
|
||||
|
||||
Reference in New Issue
Block a user