Files
DDI/docs/adr/0022-ausrollen-pull-push-m4.md
T

6.5 KiB
Raw Blame History

0022 – Ausrollen: Betriebsmodi, Push, Änderungsübersicht, Diff, Rollback, Live-Status (M4)

  • Status: Akzeptiert
  • Datum: 2026-10-13

Kontext

M3 rollt jede neue Revision sofort auf alle Agents aus. M4 verlangt laut Brief Betriebsmodi pro Agent, „Jetzt ausrollen“ aus dem UI, Entwürfe, eine Diff-Ansicht, den Deployment-Status live und Rollback über das UI. Grundlage sind ADR 0007, 0009 und 0021.

Entscheidung

Betriebsmodi und Soll-Revision

  • auto_pull (Standard): Soll-Revision ist immer die neueste Revision; neue Revisionen werden sofort gepusht (wie M3).
  • manual: Soll-Revision ist die zuletzt ausdrücklich für diesen Agent ausgerollte Revision (agents.target_revision, anfangs 0). Ohne Push ändert sich nichts.
  • Umschalten über PATCH /agents/{id} (mode, Recht settings.admin). Der Server teilt dem verbundenen Agent den neuen Modus über ein erneutes Welcome mit (Stream wird dazu neu aufgebaut: der Hub trennt die Verbindung, der Agent verbindet sich sofort neu).

Push („Jetzt ausrollen“)

  • POST /revisions/{n}/deploy (Recht deploy) mit optionaler Agent-Liste (leer = alle nicht gesperrten Agents). Für jeden Agent legt der Server ein Deployment im Zustand pending mit eigener ID an, setzt bei manual-Agents target_revision = n und sendet ApplyRevisionCommand(n, deployment_id) über den Stream, falls verbunden.
  • Ältere Revisionen als die neueste dürfen nicht auf auto_pull-Agents gepusht werden (sie würden beim nächsten Abruf wieder auf die neueste wechseln), und keine Revision darf auf einen Agent gepusht werden, der bereits eine neuere aktiv hat (der Replay-Schutz des Agents nach ADR 0009 würde sie ablehnen): in beiden Fällen Fehler rollback_required; dafür gibt es den Rollback. Die gerade aktive Revision erneut zu pushen ist erlaubt (erneutes Anwenden).
  • Der Agent merkt sich die IDs der zuletzt bearbeiteten Push-Deployments und wendet dieselbe ID nie zweimal an; ein erneut angekündigter, schon bearbeiteter Push führt nur zum erneuten Senden des Berichts. Der Server beantwortet doppelte Berichte erfolgreich, ohne etwas zu ändern, und kündigt nur Deployments im Zustand pending an.
  • Nicht verbundene Agents erhalten offene Push-Aufträge beim nächsten Verbindungsaufbau (der Server sendet die offenen pending-Deployments erneut) bzw. beim Polling: GetDesiredStateResponse.deployment_id ist gesetzt, solange ein Push offen ist; der Agent behandelt die Soll-Revision dann als Push, auch im Modus manual.
  • ReportDeployment mit dieser ID schließt das Deployment ab (Ergebnis wie bisher). Berichte ohne ID (Pulls) werden wie in M3 als neue Zeile gespeichert.

Änderungsübersicht („Entwürfe“)

  • IPAM-Änderungen wirken sofort in der Datenbank; ausgerollt wird erst mit einer Revision. Eine eigene pending_change-Tabelle ist deshalb unnötig: Die offenen Änderungen ergeben sich aus dem Audit-Log seit der neuesten Revision, der Unterschied in der Konfiguration aus dem Vergleich „jetzt erzeugt“ gegen „neueste Revision“ (erzeugt mit deren Nummer, damit die SOA-Seriennummer keinen Unterschied vortäuscht).
  • GET /config/pending liefert beides; die Oberfläche zeigt „X Änderungen warten auf Ausrollen“ in der Kopfzeile.

Diff

  • GET /revisions/{n}/diff?against=m (Standard m = n−1) liefert pro Datei Status (added, removed, modified) und einen Unified-Diff (Paket server/internal/textdiff, Myers-Algorithmus, 3 Kontextzeilen). Unveränderte Dateien werden ausgelassen.

Rollback

  • POST /revisions/{n}/rollback erzeugt eine neue Revision mit dem Inhalt von n (ADR 0009). Damit die SOA-Seriennummer trotzdem steigt, wird nicht der alte Text kopiert, sondern die gespeicherte Generator-Eingabe von n (config_revisions.source, JSON, ab Migration 00004) mit der neuen Nummer erneut gerendert. Revisionen ohne gespeicherte Eingabe (vor M4) können nicht zurückgerollt werden (rollback_unavailable).
  • Danach gilt die neue Revision wie jede andere: auto_pull-Agents erhalten sie sofort, manual-Agents nach einem Push.

Live-Status

  • GET /events liefert einen Server-Sent-Events-Strom für angemeldete Benutzer (Recht ipam.read). Ereignisse enthalten nur Kennungen, keine Daten: agent (id), deployment (id, agent_id, revision), revision (number), pending; seit M5 außerdem addresses (network_ids) für Adressen, die die Lease-Erfassung angelegt oder geändert hat (ADR 0023). Die Oberfläche lädt daraufhin die betroffenen Abfragen neu und fällt bei Verbindungsabbruch auf Polling zurück. Alle 25 s ein Kommentar als Keepalive.
  • SSE statt WebSocket: nur Server→Browser nötig, funktioniert mit Sitzungscookie, Proxys und EventSource ohne Zusatzbibliothek; der Endpunkt nutzt die bestehende Sitzungsprüfung.
  • Quelle ist ein prozessinterner Ereignisbus (server/internal/events), den Dienst und Agent-API bei Änderungen benachrichtigen. Mehrere Server-Instanzen sind nicht vorgesehen (ADR 0006).

Präzisierungen bei der Umsetzung

  • Beim Wechsel nach manual wird target_revision auf die neueste Revision gesetzt: Der Agent bleibt auf seinem Stand, statt eine Soll-Revision 0 anzuzeigen.
  • Offene Pushes werden auch dann superseded, wenn eine neue Revision oder ein Rollback sie für auto_pull-Agents überholt, beim Wechsel nach auto_pull (für ältere Revisionen) und wenn beim Verbinden oder Abrufen eine andere Revision Soll ist. Ein später doch eintreffender Bericht überschreibt superseded mit dem echten Ergebnis.
  • „Änderungen seit der neuesten Revision“ werden über die Audit-ID des revision.create/revision.rollback-Eintrags abgegrenzt, nicht über Zeitstempel (Server- und Datenbankuhr können abweichen). Die Einträge enthalten keine IP-Adressen, weil auch Leser sie abrufen.
  • Die Revisionsnummer steht auch im Kopfkommentar der BIND-Dateien; ein Rollback-Diff zeigt daher neben der Seriennummer eine Kommentarzeile je Datei.
  • Der Ereignisstrom beginnt mit retry: 5000, sendet alle 25 s : keepalive und endet mit der Sitzung (abgemeldet, abgelaufen, Benutzer gesperrt; geprüft je Keepalive-Intervall, ohne die Sitzung zu verlängern).

Konsequenzen

  • Revisionen bleiben unveränderlich, Rollbacks sind nachvollziehbar und die Seriennummer steigt immer.
  • Die Oberfläche braucht kein Polling mehr für Agents und Deployments; Polling bleibt als Rückfall.
  • Ein offener Push für einen dauerhaft abgeschalteten Agent bleibt pending, bis der Agent sich meldet, gelöscht wird oder ein neuer Push ihn ersetzt (ältere offene Deployments desselben Agents werden dabei als superseded abgeschlossen).