Guard writer units against activation and fix backup cancellation

This commit is contained in:
admin committed 2026-09-10 15:28:42 +02:00
1 parent c0a24b63fc
commit ff152c7f0f
9 files changed
+372 -16

No files matched your search

+59 -1
View File
@@ -201,6 +201,40 @@ Gitea: `APP_DATA_PATH`, `[repository] ROOT`, Custom-Verzeichnis und `app.ini` pr
`MAIL_BACKUP_MODE=live` und abgeschaltete Stopps sind bewusste Ausnahmen mit Konsistenzrisiko. Das Log weist darauf hin. Home-Verzeichnisse werden mit `--one-file-system` kopiert: Daten anderer Mounts fehlen dann absichtlich. Mailqueues, zusätzliche Spamfilter-/DKIM-Verzeichnisse oder Maildatenbanken sind nur gesichert, wenn sie explizit im Umfang stehen.
Ein einfacher `systemctl stop` verhindert keinen späteren Start durch andere
Aufträge. Auf Gemini starteten am 10.09.2026 um 15:15:00 Uhr Apache und PHP-FPM
während der bis mindestens 15:16:33 laufenden Nextcloud-Datenkopie erneut. Die
Starts erfolgten vor der Wiederaufnahme durch das Backup. Dieser Lauf erfüllt
die vereinbarte Konsistenzbedingung nicht; eine erfolgreiche Hash-/Remote-Prüfung
kann dies nicht nachträglich beweisen. Der auslösende Auftrag ist noch unbekannt.
Vor dem Stoppen erhält nun jeder konfigurierte Writer eine eigene temporäre
systemd-Ergänzung unter `/run/systemd/system/UNIT.d/zzzz-app-backup-LAUF.conf`.
`ConditionPathExists=!/run/app-backup-guard-ZUFALL` verhindert den Start, solange
das zugehörige Verzeichnis besteht. Das gilt auch für zuvor inaktive konfigurierte
Writer und für Dienste mit eigener Unit-Datei unter `/etc`. Bestehende Maskierungen
werden nicht verändert. Die Laufzeitergänzung muss nach `daemon-reload` als letztes
Drop-in gemeldet werden; andernfalls bricht der Lauf ab, damit spätere
Condition-Resets die Sperre nicht unbemerkt überschreiben.
Nach dem Anhalten aller Writer, vor und nach den Dumps/Dateikopien und unmittelbar
vor der Freigabe prüft das Backup Dienstzustand, eigene Sperrdateien und die
systemd-Zeitpunkte `ActiveEnterTimestampMonotonic` und `InactiveExitTimestampMonotonic`.
Eine erkannte Aktivierung, veränderte Sperre oder nicht prüfbarer Zustand führt
zum Fehler, bevor Archive als vollständiger Satz veröffentlicht werden. Diese
Kontrollen ersetzen keine vollständige Ereignisaufzeichnung und schützen nicht
vor nicht konfigurierten Prozessen, direktem Programmstart außerhalb systemd oder
gezieltem administrativem Entfernen der Absicherung zwischen zwei Kontrollen.
Die systemd-Startbedingung verhindert reguläre Startaufträge während des Fensters.
Quelle: [systemd-Startbedingungen](https://github.com/systemd/systemd/blob/v256/man/systemd.unit.xml).
Bei erfolgreicher Kopie und bei normalen Backupfehlern entfernt der Wiederanlauf
ausschließlich die eigenen Drop-ins, lädt systemd neu und entfernt das zugehörige
Sperrverzeichnis. Erst danach werden die zuvor aktiven Dienste gestartet; deren
aktiver Zustand wird überprüft. Scheitert die Freigabe, bleiben Wiederanlaufdaten
erhalten und es wird kein Erfolg gemeldet. Bei teilweise ausgeführtem Restore
bleiben die Startsperren zusammen mit dem Wartungsmodus zur manuellen Prüfung bestehen.
`ENABLE_MAIL_STORE=true` bleibt der kompatible Default: `MAIL_DIR` muss existieren.
Bei Mailboxen ausschließlich in Benutzerverzeichnissen kann explizit
`ENABLE_MAIL_STORE=false` gesetzt werden. Dann sind aktivierte, nicht leere
@@ -250,6 +284,25 @@ Für den täglichen Zeitplan z. B. bei mehr als 36 Stunden ohne erfolgreichen La
Ein geplanter Backupabbruch erfolgt über `systemctl stop app-backup.service`. Normale INT-/TERM-Behandlung versucht die ursprünglichen Dienste wiederherzustellen. SIGKILL, Kernelabsturz oder Stromverlust können keine Shell-Traps ausführen. Dafür liegt `recovery-LAUFNAME.json` mit vorher aufgezeichnetem Wartungs-/Dienstzustand und Arbeitsordner im Workdir. Diese Datei ist eine manuelle Wiederanlaufhilfe, kein automatischer Neustartauftrag. Das System startet nicht blind Anwendungen über einen teilweise restaurierten Datenbestand.
Backup-Unit und Update-Auftrag verwenden `KillMode=control-group`: Beim Stoppen
erhalten auch laufende Dump-, rsync-, Kompressions- und rclone-Prozesse TERM.
Dadurch können die wartenden Shells ihre Fehlerbehandlung ausführen, statt bis
zum regulären Ende eines langen Uploads zu warten. Die tee-Prozesse ignorieren
INT/TERM und enden mit dem Schließen ihrer Eingabe; so bleibt die Protokollierung
während der Wiederaufnahme erhalten. Die fünfminütige Stop-Frist bleibt bestehen.
Sie garantiert keine Wiederherstellung bei blockierten Kernelzugriffen oder
fehlgeschlagenen Dienststarts. Quelle:
[systemd-Signalzustellung](https://github.com/systemd/systemd/blob/v256/man/systemd.kill.xml).
Die Wiederanlaufdatei enthält außerdem `service_guard_files` und
`service_guard_directory`. Bei manueller Wiederherstellung nur die darin genannten
eigenen Drop-in-Dateien entfernen, `systemctl daemon-reload` ausführen und danach
das zugehörige leere Sperrverzeichnis mit `rmdir` entfernen. Keine fremden Drop-ins
oder Maskierungen löschen. Erst nach Prüfung des Datenzustands die aufgezeichneten
Dienste und den Wartungsmodus wiederherstellen. Die Sperren liegen unter `/run`
und überleben keinen Neustart; ein Reboot ist deshalb keine sichere Reparatur
eines teilweise ausgeführten Restores.
## Wiederherstellung
### Prüfphase
@@ -360,10 +413,15 @@ Die Entfernung der drei DB-Dateien aus dem aktuellen Baum löscht deren Historie
Reproduzierbar mit `tests/Dockerfile` und `tests/run.sh`. Der Container bekommt das Repository nur lesbar und benötigt während der Tests kein Netzwerk. Die MariaDB läuft ohne TCP-Port in einem temporären Verzeichnis. systemd/occ werden simuliert; alle eigentlichen Archive, Dateikopien, Dumps/Imports und Crypt-Operationen sind real.
Ergebnis des lokalen Abschlusslaufs am 10.09.2026: **44 Tests erfolgreich**, Shell-Syntax und ShellCheck ohne Befund. Testumgebung: Debian 13.6, MariaDB 11.8.6, rclone 1.60.1-DEV (Distributionspaket), ShellCheck 0.10.0. Diese Versionsangaben beschreiben die Testumgebung, keine Empfehlung für die Produktivversion.
Verifikation am 10.09.2026: **52 Testfälle erfolgreich** — 50 im vollständigen Durchlauf, anschließend beide zusätzlichen Abbruchtests für Kopie und Upload auf dem ergänzten Stand. Shell-Syntax und ShellCheck abschließend ohne Befund. Testumgebung: Debian 13.6, MariaDB 11.8.6, rclone 1.60.1-DEV (Distributionspaket), ShellCheck 0.10.0. Diese Versionsangaben beschreiben die Testumgebung, keine Empfehlung für die Produktivversion.
Geprüfte Fälle umfassen:
- Fremde Startversuche während realer rsync-Kopien werden durch das systemd-Testmodell übersprungen; zuvor inaktive Writer bleiben nach dem Lauf inaktiv.
- Aktive sowie zwischenzeitlich gestartete und wieder gestoppte Writer verhindern die Veröffentlichung eines vollständigen Satzes.
- Nicht geladene Startsperre, Erhalt vorhandener Maskierungen und fehlgeschlagene Sperrfreigabe mit erhaltener Wiederanlaufdatei.
- Bei teilweise ausgeführtem Restore bleiben eigene Startsperren erhalten. `systemd-analyze` prüft die reale Condition-Auswertung und Unit-Syntax separat, ohne einen Dienst zu starten.
- TERM an die gesamte simulierte Unit-Prozessgruppe während blockierter Kopie beziehungsweise blockiertem Upload: zeitnahes Fehlerergebnis, Dienstwiederaufnahme, freigegebene Startsperren, erhaltenes Protokoll und gestoppter Backup-Timer.
- Verweigerter rsync-Quellzugriff bricht das Update vor Installation und Dienst-Stopp ab.
- Verweigerte Verzeichnisattribute werden vor Wartungsmodus erkannt; der private Prüfbereich wird entfernt.
- Attributprobe kopiert keine Kindobjekte; rsync erbt bei Prüfung, Backup und Restore keine Update-/Backup-Sperrdeskriptoren.