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>
6.4 KiB
Auftragsübermittlung an Agenten (Phase 5)
Bis zu dieser Phase war der Agent ein angemeldeter Beobachter: Er meldete sich an und gab Lebenszeichen, aber der Server konnte ihm nichts zu tun geben. Zentral gesteuerte Sicherungen liefen nur für Quellen, die der Control-Server selbst erreicht.
Jetzt läuft die Kette durch:
Server stellt Auftrag ein
→ Agent holt ihn ab
→ Agent sichert über die Engine
→ Agent meldet Fortschritt und Ergebnis
→ Server trägt den Wiederherstellungspunkt ein
Der Agent holt ab, der Server drückt nicht
Das ist keine Bequemlichkeit, sondern die einzige Wahl, die in echten Netzen funktioniert. Ein Agent steht hinter einer Firewall, oft hinter NAT, und ist vom Server aus nicht erreichbar — jedenfalls nicht ohne eine eingehende Portfreigabe auf jedem gesicherten System. Die Verbindung geht deshalb immer vom Agenten aus, in genau der Richtung, die auch seine Lebendmeldung nimmt.
Drei Endpunkte, alle am Betriebstoken des Agenten:
POST /api/v1/agents/tasks/claim # holt den nächsten Auftrag (204 = nichts zu tun)
POST /api/v1/agents/tasks/{id}/progress # Fortschritt und Lebenszeichen
POST /api/v1/agents/tasks/{id}/result # Ergebnis
Jeder prüft, dass der Auftrag dem anfragenden Agenten gehört. Ohne diese Prüfung könnte ein übernommener Agent die Aufträge aller anderen Systeme abholen — samt Quell- und Repositorypfaden, also einer Landkarte der gesamten Anlage.
Ein fremder und ein bereits abgeschlossener Auftrag ergeben dieselbe Antwort: Die Unterscheidung verriete, welche Auftragskennungen es gibt.
Der Fund: Der Server sperrte das Repository für seinen eigenen Agenten
Beim ersten Durchlauf meldete der Agent:
REPOSITORY_UNREACHABLE — Das Repository unter "…/p5/repo" ist von diesem
Agenten aus nicht erreichbar
Das Repository lag einwandfrei da. Gesperrt hatte es der Server: Phase 8 öffnet das Repository einmal je Lauf und hält dabei die Schreibsperre — eine richtige Entscheidung, solange der Server selbst sichert. Bei einer Delegation wartete er nun mit gehaltener Sperre darauf, dass der Agent in dasselbe Repository schreibt.
Der Server öffnet das Repository jetzt nur noch, wenn mindestens eine Quelle des Laufs serverseitig gesichert wird. Ein Lauf mit ausschließlich Agentenquellen löst den Datensatz auf — der Agent braucht den Pfad —, öffnet das Repository aber nicht.
Wie der Agent an das Repository kommt
Der Auftrag enthält den Repositorypfad; der Agent öffnet ihn unmittelbar. Daraus folgt eine Betriebsanforderung, die klar benannt sein muss:
Der Agent braucht Schreibzugriff auf das Repository. Auf einem gemeinsamen
Server ist das der lokale Pfad. Bei getrennten Maschinen braucht es eine
Freigabe (NFS, SMB) oder ein eingehängtes Verzeichnis. Erreicht der Agent das
Ziel nicht, meldet er REPOSITORY_UNREACHABLE mit dem Hinweis auf die Freigabe —
statt einen technischen Pfadfehler weiterzureichen oder eine leere Sicherung
abzuliefern.
Ein Streaming-Protokoll, bei dem der Agent seine Blöcke an den Server schickt und dieser sie ablegt, wäre die Alternative. Es ist bewusst nicht gebaut: Es verdoppelt den Datenweg, macht den Control-Server zum Engpass jeder Sicherung und verlangt ein eigenes Übertragungsprotokoll samt Wiederaufnahme. Für einen ersten funktionierenden Weg ist die Freigabe die ehrlichere Lösung.
Regeln, die auch hier gelten
- Ein Auftrag je Agent. Ein Teilindex auf
(agent_id) WHERE status IN ('claimed','running')erzwingt es. Zwei gleichzeitige Sicherungen desselben Systems konkurrierten um dieselben Dateien und dieselbe Schreibsperre. - Ein Teilfehler bleibt ein Teilfehler. Der Agent meldet ihn als solchen, der Server berichtigt ein widersprüchliches Ergebnis, und die Datenbank lehnt „erfolgreich mit übergangenen Objekten" per CHECK ab. Drei Ebenen für dieselbe Regel — weil sie die wichtigste ist (verbindliche Regel 1).
- Ein Fehler ist eine Antwort. Der Agent meldet auch im Fehlerfall zurück. Ein Agent, der bei einem Fehler schweigt, lässt den Lauf bis zum Ablauf der Frist hängen.
- Verschlüsselung wird nie stillschweigend weggelassen. Verlangt der Auftrag sie und hat der Agent kein Schlüsselmaterial, wird der Auftrag abgelehnt. Ein Backup, das der Server für verschlüsselt hält und das es nicht ist, wäre eine Zusicherung ins Leere.
- Der Lauf wartet synchron auf den Agenten. Würde der Server den Auftrag nur einstellen und den Lauf als erfolgreich vermerken, stünde ein grüner Lauf in der Übersicht, während der Agent noch arbeitet — oder bereits gescheitert ist.
- Verwaiste Aufträge werden freigegeben, nicht wiederholt. Stirbt ein Agent
mitten im Lauf, gilt sein Auftrag nach Fristablauf als gescheitert
(
AGENT_LOST, Klassetransient). Nicht erneut eingereiht: Er könnte bereits Blöcke geschrieben haben. - Der Fortschritt ist zugleich die Lebendmeldung und wird gedrosselt (alle fünf Sekunden). Die Engine ruft ihren Rückruf sehr häufig auf; ungedrosselt erzeugte eine Sicherung mit einer Million Dateien eine Million HTTP-Anfragen.
Nachweis
Auf einer Maschine, auf der Server und Agent laufen:
Agent aufgenommen dev-agent
Auftrag mit agent_id angelegt Quelle ist Agent zugewiesen ✓
Lauf angestoßen HTTP 202
Agent holt ab und führt aus "auftrag wird ausgefuehrt"
Ergebnis succeeded, 3.500.014 Byte, 4 Objekte
Wiederherstellungspunkt in der DB complete, 3.500.014 Byte
Quelle gelöscht, wiederhergestellt ✓ alle Prüfsummen stimmen
Was noch fehlt
- Der Windows-Dienst ist weiterhin ungeprüft.
service_windows.goist geschrieben, aber auf macOS nicht ausführbar. Der Kommandozeilenweg und die Auftragsausführung sind plattformunabhängig; der Dienstwrapper ist der letzte ungeprüfte Teil von Phase 5. - Wiederherstellung über den Agenten. Der Auftragstyp
restoreist im Modell vorgesehen und nicht umgesetzt: Eine Wiederherstellung schreibt auf ein fremdes System und braucht dieselben drei Hürden wie die serverseitige (Phase 9). Sie wird als eigener Schritt gebaut, nicht nebenbei. - Kein Streaming zum Server. Siehe oben — der Agent braucht Zugriff auf das Repository.
- Keine Abbruchmöglichkeit von außen. Ein laufender Agentenauftrag lässt sich derzeit nicht über die API abbrechen; er läuft zu Ende oder in die Frist.