Enterprise-Backup-, Recovery-, Verification-, Security- und Monitoring-Plattform fuer Proxmox VE, Windows, Linux und Dateisysteme. Der Leitsatz, der fast jede Entscheidung erklaert: Ein Backup gilt erst als vertrauenswuerdig, wenn Integritaet geprueft und Wiederherstellbarkeit nachgewiesen wurde. Deshalb steigt ein Wiederherstellungspunkt erst nach einem tatsaechlich durchgefuehrten Restore-Test auf "recoverable", und Unbekanntes geht in keine Bewertung als "gut" ein. Umfang (Phasen 0-23): - Repository Engine: inhaltsadressierte Bloecke, atomares Commit-Protokoll, Katalogaufbau allein aus den Manifesten — ohne Datenbank - Backup Engine: inhaltsabhaengiges Chunking, Deduplizierung trotz Verschluesselung, zstd, AES-256-GCM, Streaming mit Gegendruck - Agenten fuer Windows und Linux mit Auftragsabholung (Pull-Modell) - Proxmox-Provider mit beiden Zugriffswegen auf die Sicherungsarchive - Scheduler, Recovery Engine mit Pruefpunkt, Verification, Unveraenderlichkeit - Weboberflaeche, Kennzahlen, Meldungen, Berichte, Security Center, Ransomware-Heuristik (meldet, handelt nie) - Disaster Recovery, Haertung, Leistungsmessung, Chaos Testing - Eingefrorene Vertraege fuer API, Migrationen, Backup-Format und Repository - Auslieferungspaket fuer linux/amd64, linux/arm64 und windows/amd64 Nicht enthalten und als solches gekennzeichnet: Kapazitaetsprognose, Backup Copy, Changed Block Tracking bei Proxmox, erweiterte Attribute und ACLs. Gebaut, aber nie auf echter Hardware gefahren: der Windows-Dienst, die systemd-Einheit und der verpflichtende Proxmox-Meilenstein — ob eine wiederhergestellte VM startet, ist ungeprueft. Einzelheiten in CHANGELOG.md und docs/release-candidate.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
139 lines
9.4 KiB
Markdown
139 lines
9.4 KiB
Markdown
# Recovery Engine
|
|
|
|
## Status
|
|
|
|
Umgesetzt sind Vorabprüfung, Wiederherstellung von Dateien und Ordnern über die API, Sitzungen mit Prüfpunkt, Schutz gegen versehentliches Überschreiben und die Ausführungsschleife.
|
|
|
|
Nicht umgesetzt: Plattenwiederherstellung, vollständige Systemwiederherstellung und Proxmox-VM-Wiederherstellung. Für Proxmox fehlt der `ArchiveTransport` (siehe `proxmox.md`); ohne ihn kommt schon die Sicherung nicht zustande.
|
|
|
|
## Die Vorabprüfung ist der Kern
|
|
|
|
> Ein Backup gilt erst als vertrauenswürdig, wenn Integrität geprüft und Wiederherstellbarkeit nachgewiesen wurde.
|
|
|
|
Ein Nachweis, der erst im Ernstfall erbracht wird, ist keiner. `POST /restores/validate` prüft deshalb **ohne etwas zu schreiben**, ob eine Wiederherstellung gelingen kann:
|
|
|
|
| Prüfung | Gewicht bei Befund |
|
|
| --- | --- |
|
|
| Manifest lesbar | verhindernd |
|
|
| Abschlussvermerk vorhanden | verhindernd |
|
|
| **Jeder benötigte Block vorhanden** | verhindernd |
|
|
| Datenschlüssel des Repositorys auffindbar | verhindernd |
|
|
| Zielverzeichnis erreichbar, Elternverzeichnis vorhanden | verhindernd |
|
|
| Freier Platz ausreichend (5 % Aufschlag) | verhindernd |
|
|
| Ziel nicht leer, ohne Zustimmung | verhindernd |
|
|
| Ziel wird überschrieben, mit Zustimmung | Warnung |
|
|
| Backup unverschlüsselt | Warnung |
|
|
| Schlüsselversion weicht ab | Warnung |
|
|
| Blockprüfung übersprungen | Hinweis |
|
|
|
|
**Die Blockprüfung ist der eigentliche Nachweis.** Ein Manifest allein belegt nur, dass jemand einmal etwas gesichert hat — nicht, dass die Daten noch da sind. Ein versehentlich aufgeräumtes Verzeichnis, ein unvollständig kopiertes Repository, ein fehlgeschlagenes Prune: Alles das fällt hier auf und nicht erst, wenn man es braucht.
|
|
|
|
Real geprüft: Nach dem Entfernen eines einzigen Blocks meldet die Prüfung
|
|
|
|
```
|
|
can_proceed: False
|
|
NICHT WIEDERHERSTELLBAR: 1 Hindernisse, 1 fehlende Bloecke.
|
|
[blocking] 1 von 16 benoetigten Bloecken fehlen im Repository.
|
|
betroffen: daten/datei-8.bin
|
|
```
|
|
|
|
Die **betroffene Datei** wird genannt, nicht nur eine Zahl. „Ein Block fehlt" hilft niemandem weiter; „daten/datei-8.bin lässt sich nicht wiederherstellen" schon.
|
|
|
|
Wird die Blockprüfung übersprungen (`skip_deep_check`), steht das als Hinweis im Bericht. Sonst hielte man einen halben Nachweis für einen ganzen.
|
|
|
|
**Die Prüfung läuft zweimal:** einmal beim Anlegen des Auftrags und erneut unmittelbar vor dem Schreiben. Der Bericht am Auftrag kann Minuten oder Tage alt sein; in der Zwischenzeit kann ein Block verschwunden oder das Ziel gefüllt worden sein. Der Bericht wird am Auftrag gespeichert — später muss belegbar sein, was vor dem Start bekannt war.
|
|
|
|
## Drei Hürden vor dem Überschreiben
|
|
|
|
Eine Wiederherstellung an einen belegten Ort richtet sich gegen Daten, die es noch gibt — und die könnten genau die sein, die man eigentlich retten will.
|
|
|
|
1. **Ohne `overwrite_existing` wird ein nicht leeres Ziel abgelehnt.**
|
|
2. **`restores.overwrite` ist eine eigene Berechtigung**, nicht in `restores.execute` enthalten. Wer wiederherstellen darf, darf nicht automatisch überschreiben.
|
|
3. **`confirm_overwrite` muss den Zielpfad wörtlich wiederholen.** Ein zweites Feld neben dem Kennzeichen ist keine Umständlichkeit: Ein versehentlich gesetztes Kennzeichen in einem Skript oder einer Vorlage reicht damit nicht aus, um Daten zu vernichten. Wer den Pfad abtippt, hat ihn gelesen.
|
|
|
|
Läuft der Schalter ins Leere — das Ziel ist leer —, entfällt die Bestätigung. Ein Ritual ohne Anlass gewöhnt nur das Wegklicken an.
|
|
|
|
Jede Wiederherstellung wird auditiert, das Überschreiben unter eigener Aktion (`RESTORE_OVERWRITE_REQUESTED`) und zusätzlich als Warnung im Protokoll.
|
|
|
|
## Sitzungen und Prüfpunkte
|
|
|
|
Ein Abbruch bei 90 Prozent darf nicht bedeuten, dass alles von vorn beginnt — bei mehreren Terabyte wäre das der Unterschied zwischen Stunden und Tagen, und zwar in einer Lage, in der ohnehin schon etwas schiefging.
|
|
|
|
Jeder Auftrag bekommt eine Sitzung mit Prüfpunkt. Der Prüfpunkt hält **einen einzigen Pfad**: den zuletzt vollständig zurückgeschriebenen. Das genügt, weil die Objekte im Manifest fest sortiert sind — alles lexikographisch davor ist erledigt. Eine Liste wäre bei einer Million Dateien unbrauchbar groß.
|
|
|
|
**Der Prüfpunkt entsteht erst, nachdem die Datei vollständig und unter ihrem endgültigen Namen am Platz liegt.** Ein Prüfpunkt auf eine halb geschriebene Datei wäre schlimmer als keiner: Die Fortsetzung übersprünge sie als erledigt.
|
|
|
|
Geschrieben wird er nicht bei jeder Datei, sondern höchstens alle paar Sekunden — bei einer Million kleiner Dateien wären das sonst eine Million Schreibvorgänge in die Datenbank. Der Preis ist, dass eine Fortsetzung wenige Sekunden Arbeit wiederholt.
|
|
|
|
Bei einer Fortsetzung greift der Schutz gegen ein volles Zielverzeichnis **nicht**: Dort liegt notwendigerweise der bereits zurückgeschriebene Teil. Ihn über `overwrite_existing` auszuhebeln wäre falsch — das erlaubte zugleich das Überschreiben fremder Daten.
|
|
|
|
Die Endzahlen beschreiben den **gesamten** Vorgang, nicht nur den letzten Versuch: drei Objekte aus dem ersten Lauf plus zwei aus dem zweiten ergeben fünf.
|
|
|
|
## Kein automatischer Wiederholungsversuch
|
|
|
|
Anders als eine Sicherung wird eine gescheiterte Wiederherstellung **nicht** automatisch erneut gestartet. Ein zweiter Lauf in ein halb gefülltes Zielverzeichnis kann Daten beschädigen, die der erste Versuch bereits am Platz hatte. Der Betreiber soll hinsehen, bevor erneut geschrieben wird — die Sitzung mit ihrem Prüfpunkt bleibt dafür offen.
|
|
|
|
Das gilt auch für verwaiste Aufträge: Stirbt ein Control-Server mitten in einer Wiederherstellung, wird der Auftrag nach fünf Minuten als `SCHEDULER_LOST` gescheitert vermerkt, aber nicht erneut eingereiht. Die Sitzung überlebt.
|
|
|
|
## Nebenläufigkeit
|
|
|
|
**Standard ist eine Wiederherstellung zur Zeit.** Sie läuft im Ernstfall, und dann zählt die Geschwindigkeit *einer* Wiederherstellung, nicht der Durchsatz mehrerer: Wer zwei gleichzeitig laufen lässt, halbiert die Geschwindigkeit derjenigen, auf die alle warten.
|
|
|
|
Ein Teilindex verhindert zwei gleichzeitige Wiederherstellungen in **dasselbe Ziel**. Sie schrieben sich gegenseitig zu — und zwar ohne dass es auffiele, weil beide erfolgreich endeten.
|
|
|
|
**Das Repository wird schreibgeschützt geöffnet.** Eine Wiederherstellung liest nur und kann deshalb neben einer laufenden Sicherung stattfinden, statt auf deren Schreibsperre zu warten. Im Ernstfall wartet niemand gern.
|
|
|
|
## Übergangene Objekte sind ein Teilfehler
|
|
|
|
Wie bei den Sicherungen: Eine Wiederherstellung, die zwei Dateien nicht zurückschreiben konnte, ist unvollständig. Sie darf nicht als Erfolg dastehen — der Anwender glaubte sonst, alles sei wieder da. Die Datenbank erzwingt das über ein CHECK.
|
|
|
|
## API
|
|
|
|
```
|
|
POST /api/v1/restores/validate restores.read prüft, schreibt nichts
|
|
POST /api/v1/restores restores.execute 202: reiht ein, auditiert
|
|
GET /api/v1/restores restores.read Liste mit Pagination
|
|
GET /api/v1/restores/{id} restores.read inkl. Prüfpunkt bei Abbruch
|
|
POST /api/v1/restores/{id}/cancel restores.execute auditiert
|
|
```
|
|
|
|
Die Vorabprüfung braucht nur das **Leserecht**: Sie schreibt nichts und soll niedrigschwellig sein — wer den Zustand der Backups beurteilen soll, muss sie ausführen können.
|
|
|
|
```json
|
|
{
|
|
"backup_id": "…",
|
|
"target_path": "/wiederhergestellt",
|
|
"path_prefix": "dokumente/2026",
|
|
"overwrite_existing": true,
|
|
"confirm_overwrite": "/wiederhergestellt"
|
|
}
|
|
```
|
|
|
|
`path_prefix` beschränkt auf einen Teilbaum — der häufigste Fall im Betrieb ist nicht die vollständige Wiederherstellung, sondern eine einzelne versehentlich gelöschte Datei. Die Präfixgrenze achtet auf Verzeichnisse: `dokumente` trifft nicht auch `dokumentation`.
|
|
|
|
`POST /restores` antwortet mit **202**, nicht 201: Der Auftrag ist eingereiht, die Daten sind noch nicht zurück. Beim Abbruch wird ausdrücklich gesagt, dass bereits zurückgeschriebene Daten am Ziel liegen bleiben — sonst hielte man das Ziel für unberührt.
|
|
|
|
## Nachgewiesen
|
|
|
|
Gegen den laufenden Dienst, 11,4 MiB in 12 Objekten:
|
|
|
|
| Schritt | Ergebnis |
|
|
| --- | --- |
|
|
| Vorabprüfung | „Wiederherstellbar: 9 Dateien, 11.4 MiB", 16 Blöcke geprüft, 0 fehlend |
|
|
| Quelle gelöscht, über die API wiederhergestellt | `succeeded`, 12 Objekte in 0,11 s |
|
|
| Vergleich | **bitgenau identisch** inkl. Rechten (600), Symlink, leerem Verzeichnis |
|
|
| Volles Ziel ohne Zustimmung | abgelehnt |
|
|
| `overwrite_existing` ohne Bestätigung | abgelehnt, nennt den zu wiederholenden Pfad |
|
|
| Falscher Bestätigungswert | abgelehnt |
|
|
| Mit korrekter Bestätigung | 202, überschrieben, im Protokoll als Warnung |
|
|
| Ein Block entfernt | `can_proceed: false`, betroffene Datei benannt, Auftrag mit 422 abgelehnt |
|
|
|
|
## Offene Punkte
|
|
|
|
- **Keine Platten- und Systemwiederherstellung.** Sie setzen Provider voraus, die noch nicht liefern.
|
|
- **Proxmox-VM-Wiederherstellung** ist im Provider umgesetzt, aber ungeprüft und ohne `ArchiveTransport` nicht erreichbar.
|
|
- **Keine Fortsetzung über die API.** Der Prüfpunkt liegt vor und die Schleife nutzt ihn, aber es gibt keinen Endpunkt, der einen gescheiterten Auftrag erneut einreiht — nur den Weg über die Datenbank.
|
|
- **Kein `GET /restores/{id}/logs` und `/metrics`** (SYNCOVA_API.md §13).
|
|
- **Keine Wiederherstellung in der Oberfläche.** Sie geht nur über die API.
|
|
- **Kein Wiederherstellungstest als eigener Auftrag.** Das ist Phase 10 — und der Punkt, an dem aus „prüfbar" ein regelmäßiger Nachweis wird.
|