internal/backup.PruneTiered: reine GFS-Funktion (Tag/Woche/Monat) fuer Datenbank-Generationen, behaelt strukturell immer die neueste Generation (Sicherheitsnetz gegen Legal-Hold-Kollision). internal/objectbackup. PruneTiered: duenner Wrapper um restics native --keep-daily/-weekly/ -monthly-Staffelung. Beide CLIs nutzen die Staffelung, wenn konfiguriert, bleiben sonst abwaertskompatibel zur flachen "letzte N"-Regel. Real gegen zeitversetzt erzeugte restic-Snapshots getestet (Fund: restics --time-Flag erwartet eigenes Format, nicht RFC3339), Pruning-Sicherheit nach dem Loeschen alter Snapshots ueber vollstaendigen Restore + restic check --read-data bewiesen. Beide Rotationswege real ueber systemd auf 131 ausgeloest.
5.3 KiB
BAK-07 – Prüfprotokoll: Aufbewahrungsfrist für Backup-Snapshots
Voraussetzung BAK-01, BAK-02 – erledigt, siehe eigene Protokolle.
Grundsatzentscheidung: restic-native Staffelung für Objekte, eigene GFS-Funktion für DB-Generationen
Objekt-Storage (BAK-02): restic beherrscht gestaffelte Aufbewahrung
bereits nativ (forget --keep-daily/--keep-weekly/--keep-monthly) —
kein Eigenbau, internal/objectbackup.PruneTiered ist ein dünner
Wrapper (dieselbe Disziplin wie beim ursprünglichen
restic-statt-Eigenbau-Entscheid in BAK-02).
Datenbank-Generationen (BAK-01): pg_basebackup kennt keine
Staffelung, daher internal/backup.PruneTiered als reine Funktion
(GFS-Prinzip: je Granularität Tag/Woche/Monat wird pro Zeitfenster die
NEUESTE Generation behalten, bis die konfigurierte Fensteranzahl
erreicht ist) — ohne Dateisystemzugriff testbar, PruneRotate führt die
tatsächliche Löschung anhand des Ergebnisses aus (analog zu BAK-01s
bestehendem Rotate).
Beide Policies sind über Umgebungsvariablen konfigurierbar
(NEXARCH_BACKUP_KEEP_DAILY/WEEKLY/MONTHLY,
NEXARCH_OBJECTBACKUP_KEEP_DAILY/WEEKLY/MONTHLY), nicht hart codiert
(Ticket-Vorgabe). Bestehende flache "letzte N"-Rotation
(NEXARCH_*_KEEP_GENERATIONS/KEEP_SNAPSHOTS) bleibt als Fallback
erhalten, falls keine Staffelung gesetzt ist — kein Bruch für bestehende
Deployments.
Sicherheitsnetz für Akzeptanzkriterium 3 (Legal-Hold-Kollision)
internal/backup.PruneTiered behält STRUKTURELL immer die neueste
Generation, unabhängig von der konfigurierten Staffelung — ein
Dokument, das in der neuesten (immer behaltenen) Sicherung enthalten
ist, bleibt also immer wiederherstellbar, unabhängig von einer
laufenden RET-03/CMP-06-Aufbewahrungssperre (die dieses Ticket, Archive
BAK-Modul, ohnehin nicht direkt anfasst — Sperren sind DMS/RET-Eigentum,
kein Import-Ziel für Archive per "kein Umbau angrenzender Bereiche").
Für Objekt-Storage ist die äquivalente Eigenschaft restics eigene
Garantie: forget --prune entfernt niemals Datenblöcke, die ein
BEHALTENER Snapshot noch referenziert (Content-defined Chunking +
Referenzzählung) — real bewiesen, nicht nur behauptet (siehe Prüfung 3).
Umsetzung
internal/backup.RetentionPolicy/PruneTiered(retention.go) — reine GFS-Funktion.internal/backup.PruneRotate(rotate.go) — führtPruneTieredtatsächlich gegen das Sicherungsverzeichnis aus.internal/objectbackup.RetentionPolicy/PruneTiered(restic.go) — Wrapper um restics native Staffelung.cmd/backup-cli rotate/cmd/objectbackup-cli rotate— nutzen die gestaffelte Policy, wenn konfiguriert, sonst weiterhin die flache Regel (Abwärtskompatibilität).
Prüfungen
| # | Prüfung | Ergebnis |
|---|---|---|
| 1 | Prune-Test mit simulierten Snapshots über mehrere Altersstufen ergibt korrekte Staffelung | bestanden — TestPruneTiered_KeepsCorrectStaggering (Datenbank, reine Funktion, simulierte Generationen über Tage/Wochen/Monate) UND TestPruneTiered_KeepsCorrectStaggering_RealSnapshots (Objekt-Storage, ECHTE restic-Snapshots mit erzwungenem Zeitstempel restic backup --time, KeepDaily=3 reduziert 10 reale Snapshots korrekt auf 3) |
| 2 | Automatisierte Löschung abgelaufener Snapshots im Test nachgewiesen | bestanden — TestPruneRotate_DeletesOnlyExpiredGenerations: reales Verzeichnis, abgelaufene Generation tatsächlich vom Dateisystem entfernt, aktuelle unangetastet; real auf 131: backup-cli rotate und objectbackup-cli rotate über systemd ausgelöst, Journal zeigt „gestaffelte rotation abgeschlossen“ |
| 3 | Legal-Hold-Test bestätigt, dass Pruning nicht mit Dokumenten-Retention kollidiert | bestanden — TestPruneTiered_AlwaysKeepsNewest (Datenbank-Sicherheitsnetz: neueste Generation immer behalten, selbst bei Policy 0/0/0) UND TestPruneTiered_KeptSnapshotStillFullyRestorable (Objekt-Storage, real: 5 ältere Snapshots eines Dokuments weggeprunt, verbleibender Snapshot danach vollständig und inhaltlich korrekt wiederhergestellt, zusätzlich restic check --read-data bestätigt Datenintegrität nach dem Pruning) |
Zusätzlich: TestPruneTiered_DeterministicForIdenticalInput.
Echte Verdrahtung auf 192.168.1.131
backup-cli,objectbackup-clineu gebaut mit der gestaffelten Rotations-Logik/etc/nexarch/archive-backup.envund/etc/nexarch/archive-objectbackup.envumKEEP_DAILY=14/KEEP_WEEKLY=12/KEEP_MONTHLY=12ergänzt- Beide
*-rotate.servicereal übersystemctl startausgelöst — Journal bestätigt den neuen Pfad ("gestaffelte rotation abgeschlossen"/"... entfernt: [...]"), nicht mehr die alte flache Regel
Build/Test-Ergebnis (192.168.1.131, make check)
go build ./... -> clean
go vet ./... -> clean
golangci-lint run ./... -> 0 issues
go test ./... -p 1 -count=1 -> 7/7 Pakete mit Tests ok, 0 Fehlschläge
Gesamtergebnis
Bestanden. Alle drei Akzeptanzkriterien und alle drei
Pflichtprüfungen real erfüllt — sowohl mit simulierten (Datenbank) als
auch mit tatsächlich zeitversetzt erzeugten, realen restic-Snapshots
(Objekt-Storage). Ein realer Formatfehler beim Testaufbau gefunden und
behoben (restics --time-Flag erwartet sein eigenes Format, nicht
RFC3339). Beide Rotations-Wege real über systemd auf 192.168.1.131
ausgelöst, nicht nur isolierter Testcode.