### Security-Fixes (K1–K6, W1–W4, W7, N1, N5–N6, V1, V5–V7)
- K1: CSRF-Schutz via Double-Submit-Cookie (httpapi/csrf.go + csrf_helpers.go)
- K2: requireScreenAccess() in allen manage-Handlern (Tenant-Isolation)
- K3: Tenant-Check bei DELETE /api/v1/media/{id}
- K4: requirePlaylistAccess() + GetByItemID() für JSON-API Playlist-Routen
- K5: Admin-Passwort nur noch als [gesetzt] geloggt
- K6: POST /api/v1/screens/register mit Pre-Shared-Secret (MORZ_INFOBOARD_REGISTER_SECRET)
- W1: Race Condition bei order_index behoben (atomare Subquery in AddItem)
- W2: Graceful Shutdown mit 15s Timeout auf SIGTERM/SIGINT
- W3: http.MaxBytesReader (512 MB) in allen Upload-Handlern
- W4: err.Error() nicht mehr an den Client
- W7: Template-Execution via bytes.Buffer (kein partial write bei Fehler)
- N1: Rate-Limiting auf /login (5 Versuche/Minute pro IP, httpapi/ratelimit.go)
- N5: Directory-Listing auf /uploads/ deaktiviert (neuteredFileSystem)
- N6: Uploads nach Tenant getrennt (uploads/{tenantSlug}/)
- V1: Upload-Logik konsolidiert in internal/fileutil/fileutil.go
- V5: Cookie-Name als Konstante reqcontext.SessionCookieName
- V6: Strukturiertes Logging mit log/slog + JSON-Handler
- V7: DB-Pool wird im Graceful-Shutdown geschlossen
### Phase 6: Screenshot-Erzeugung
- player/agent/internal/screenshot/screenshot.go erstellt
- Integration in app.go mit MORZ_INFOBOARD_SCREENSHOT_EVERY Config
### UX: PDF.js Integration
- pdf.min.js + pdf.worker.min.js als lokale Assets eingebettet
- Automatisches Seitendurchblättern im Player
### Ansible: Neue Rollen
- signage_base, signage_server, signage_provision erstellt
- inventory.yml und site.yml erweitert
### Konzept-Docs
- GRUPPEN-KONZEPT.md, KAMPAGNEN-AKTIVIERUNG.md, MONITORING-KONZEPT.md
- PROVISION-KONZEPT.md, TEMPLATE-EDITOR.md, WATCHDOG-KONZEPT.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
305 lines
8.4 KiB
Markdown
305 lines
8.4 KiB
Markdown
# Info-Board Neu - Watchdog-Konzept
|
|
|
|
## Ziel
|
|
|
|
Der Watchdog ueberwacht die kritischen Komponenten des Players und sorgt dafuer, dass der Display-Betrieb bei Abstuerzen oder Verhaengungen automatisch wiederhergestellt wird.
|
|
|
|
Die Ueberwachung erfolgt auf zwei Ebenen:
|
|
|
|
1. **Browser-Watchdog** — Ueberwachung von Chromium
|
|
2. **Agent-Watchdog** — Ueberwachung des Player-Agents
|
|
|
|
## Grundprinzipien
|
|
|
|
- Watchdogs sind extern und unabhaengig von den ueberwachten Prozessen
|
|
- Erkennung erfolgt aktiv durch Health-Checks, nicht durch Liveness-Pings
|
|
- Restart-Strategien sind progressiv und vermeiden Restart-Schleifen
|
|
- Logging ist strukturiert und fuer Admin-Diagnosen aussagekraeftig
|
|
|
|
## Browser-Watchdog (Chromium-Ueberwachung)
|
|
|
|
### Aufgaben
|
|
|
|
Der Browser-Watchdog sorgt dafuer, dass:
|
|
|
|
- Chromium staendig laeuft und antwortet
|
|
- der Renderer nicht in einer Endlosschleife haengt
|
|
- Rendering-Fehler nicht zu permanenten Schwarzbildern fuehren
|
|
- bei Chromium-Crash oder Verhaengung schnell neugestartet wird
|
|
|
|
### Health-Check-Verfahren
|
|
|
|
Der Watchdog fuehrt regelmaeßig folgende Checks durch:
|
|
|
|
#### 1. Prozess-Check
|
|
|
|
```
|
|
Existiert der Chromium-Prozess noch?
|
|
- lsof oder ps-Abfrage auf die PID
|
|
- Timeout: sofort bei fehlender PID
|
|
```
|
|
|
|
#### 2. HTTP-Health-Check auf localhost
|
|
|
|
```
|
|
GET http://localhost:8081/health
|
|
Timeout: 5 Sekunden
|
|
Erwartet: 200 OK und JSON-Antwort {status: "ok"}
|
|
```
|
|
|
|
Die `player-ui` muss einen einfachen `/health`-Endpunkt bereitstellen, der schnell antwortet, auch wenn die Playlist gerade verarbeitet wird.
|
|
|
|
#### 3. Rendering-Verifizierung (optional, Phase 2)
|
|
|
|
```
|
|
Screenshot-basiert erkennen, ob der Browser:
|
|
- Fehlerseite zeigt
|
|
- komplett schwarz ist (mehr als 95% schwarze Pixel)
|
|
- seit mehreren Minuten denselben Content zeigt, obwohl ein Wechsel erwartet wurde
|
|
```
|
|
|
|
Diese Methode ist fuer v1 optional, wird aber fuer spaetere Verhaengungserkennung eingeplant.
|
|
|
|
### Ueberwachungs-Intervall
|
|
|
|
- Health-Check alle **30 Sekunden**
|
|
- Bei Fehler: sofort Neustart pruefen (kein Warten auf naechsten Zyklus)
|
|
|
|
### Restart-Strategie
|
|
|
|
#### Strategie: Exponentieller Backoff mit Maximum
|
|
|
|
```
|
|
Fehlerfall:
|
|
Fehler 1: Sofort neustart (Wait 0s)
|
|
Fehler 2: Warte 2s, versuche Restart
|
|
Fehler 3: Warte 5s, versuche Restart
|
|
Fehler 4: Warte 10s, versuche Restart
|
|
Fehler 5+: Warte 30s, versuche Restart
|
|
Nach 10 aufeinanderfolgende Fehler ohne erfolgreicher Recovery:
|
|
- Alert an Admin (via Server-Status)
|
|
- Overlay auf "Error" setzen
|
|
- Watchdog-Loop verlangsamen auf 5 Min Intervall
|
|
```
|
|
|
|
#### Erfolg-Kriterium
|
|
|
|
Wenn der Health-Check 3x hintereinander erfolgreich ist:
|
|
|
|
- Backoff-Zaehler zuruecksetzen auf 0
|
|
- naechstes Fehler wieder mit sofort-Restart starten
|
|
|
|
### Logging
|
|
|
|
Jeder Watchdog-Ereignis wird protokolliert:
|
|
|
|
```json
|
|
{
|
|
"ts": "2025-03-23T14:22:15Z",
|
|
"component": "browser_watchdog",
|
|
"event": "restart",
|
|
"reason": "health_check_timeout",
|
|
"attempt": 2,
|
|
"next_retry_in_ms": 5000,
|
|
"details": {
|
|
"pid_before": 1234,
|
|
"pid_after": 1245,
|
|
"http_status_before": 0
|
|
}
|
|
}
|
|
```
|
|
|
|
Logging-Ziele:
|
|
|
|
- strukturiert auf stdout/stderr (JSON)
|
|
- lokal in `/var/log/signage/watchdog.log` mit Rotation
|
|
|
|
## Agent-Watchdog (systemd-Integration)
|
|
|
|
### Aufgaben
|
|
|
|
Der Agent-Watchdog (bzw. systemd-Unit) sorgt dafuer, dass:
|
|
|
|
- der Player-Agent staendig laeuft
|
|
- nach Crash oder gewolltem Stop schnell neugestartet wird
|
|
- Restart-Grenzen ein Verhaengungsloop verhindern
|
|
|
|
### systemd-Konfiguration
|
|
|
|
```ini
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/usr/local/bin/player-agent
|
|
Restart=always
|
|
RestartSec=5
|
|
StartLimitInterval=300
|
|
StartLimitBurst=10
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
```
|
|
|
|
**Bedeutung:**
|
|
|
|
- `Restart=always` — Neustart bei jedem Exit (unabhaengig vom Exit-Code)
|
|
- `RestartSec=5` — Warte 5 Sekunden vor Neustart
|
|
- `StartLimitInterval=300` — Zaehle Restarts in einem 300s-Fenster
|
|
- `StartLimitBurst=10` — Mehr als 10 Restarts in 300s fuehrt zu systemd-Stop
|
|
|
|
Wenn `StartLimitBurst` erreicht wird:
|
|
|
|
- systemd laesst den Service stehen
|
|
- Admin wird informiert (Status-API setzt `agent_watchdog_failed`)
|
|
- manueller Eingriff oder Admin-Kommando noetig
|
|
|
|
### Health-Check durch Agent selbst
|
|
|
|
Der Agent sollte intern:
|
|
|
|
- Broker-Verbindung regelmaeßig pruefen
|
|
- Server-Sync-Status tracken
|
|
- bei kritischen Innenfehlern nicht einfach weiterlaeufen
|
|
|
|
Wenn sich der Agent selbst als unheilbar beschaedigt sieht:
|
|
|
|
- strukturiert mit Exit-Code `1` beenden (systemd startet neu)
|
|
- nicht mit `exit(0)` haengend beenden
|
|
|
|
## Verhaeltnis zu systemd
|
|
|
|
### Architektur-Entscheidung
|
|
|
|
`systemd` uebernimmt die Prozess-Wiederbelebung fuer den Agent.
|
|
|
|
Der Browser-Watchdog ist ein **separater, von systemd unabhaengiger Prozess**, weil:
|
|
|
|
- Chromium staendiger Ueberwachung bedarf (Health-Checks im 30s-Rhythmus)
|
|
- ein Systemd-Watchdog-Timer zu unverzeihlich waere (nur on/off, nicht granular)
|
|
- der Browser-Watchdog auch die Systemd-Unit selbst monitoren kann (Defensive Architektur)
|
|
|
|
### Optional: systemd WatchdogSec
|
|
|
|
Fuer den Agent ist es sinnvoll, auch systemd's Watchdog-Timer zu nutzen:
|
|
|
|
```ini
|
|
[Service]
|
|
WatchdogSec=30
|
|
ExecStart=/usr/local/bin/player-agent
|
|
```
|
|
|
|
Der Agent muesste dann periodisch `systemd-notify --ready` senden.
|
|
|
|
Das ist **optional fuer v1**, wird aber fuer spaetere Robustheit eingeplant.
|
|
|
|
## Integration mit Player-Setup
|
|
|
|
### Verzeichnisstruktur
|
|
|
|
```
|
|
/usr/local/bin/
|
|
player-agent — Go-Binary
|
|
browser-watchdog — Go-Binary oder Shell-Script
|
|
|
|
/etc/systemd/system/
|
|
signage-agent.service
|
|
signage-browser-watchdog.service
|
|
|
|
/var/lib/signage/
|
|
watchdog-state.json — letzter Zustand, Backoff-Counter
|
|
|
|
/var/log/signage/
|
|
watchdog.log — strukturiertes Logging
|
|
```
|
|
|
|
### Startup-Reihenfolge
|
|
|
|
1. Basis-System bootet, X11 startet
|
|
2. `signage-agent.service` startet (systemd)
|
|
3. Agent startet, prueft Konfiguration, startet `player-ui` HTTP-Server
|
|
4. `signage-browser-watchdog.service` startet (systemd)
|
|
5. Watchdog wartet initial 10s, bevor erste Checks starten
|
|
6. Agent laesst Chromium starten
|
|
7. Watchdog beginnt Health-Checks
|
|
|
|
Dieses Ordering verhindert, dass der Watchdog versucht, den Browser zu uberwachen, bevor der Agent bereit ist.
|
|
|
|
### Stopp-Reihenfolge bei Shutdown
|
|
|
|
1. systemd sendet SIGTERM an Agent und Browser-Watchdog
|
|
2. Watchdog: beendet sich, versucht nicht zu restarten
|
|
3. Agent: beendet sich, laedt Chromium herunter
|
|
4. Systemd wartet auf Completion
|
|
|
|
## Fehlerklassifizierung und Admin-Reporting
|
|
|
|
### Fehlerklassen
|
|
|
|
| Fehlerklasse | Symptom | Watchdog-Aktion | Admin-Alert |
|
|
|---|---|---|---|
|
|
| Prozess-Crash | PID weg | Sofort neustart | Nach 3x Fehlschlag |
|
|
| Health-Check-Timeout | HTTP timeout | Backoff-Restart | Nach 5x Fehlschlag |
|
|
| Rendering-Fehler | Browser zeigt Fehlerseite | Neustart | Sofort sichtbar |
|
|
| Backoff-Maximum | 10+ Fehler in 5min | Stoppen, Alert | Sofort |
|
|
| Agent-Unhealthy | Server-Sync fehlgeschlagen | Systemd-Neustart | Nach 3x Sync-Fehler |
|
|
|
|
### Admin-Oberflaeche
|
|
|
|
Status-Page und Admin-Dashboard zeigen:
|
|
|
|
```json
|
|
{
|
|
"screen_id": "info01",
|
|
"browser_status": {
|
|
"pid": 1234,
|
|
"health": "ok",
|
|
"last_check_at": "2025-03-23T14:25:00Z",
|
|
"restart_count_5m": 0,
|
|
"last_error": null
|
|
},
|
|
"agent_status": {
|
|
"pid": 567,
|
|
"uptime_seconds": 3600,
|
|
"sync_status": "ok",
|
|
"last_sync_at": "2025-03-23T14:24:55Z",
|
|
"systemd_restart_count": 0
|
|
},
|
|
"watchdog_alert": null
|
|
}
|
|
```
|
|
|
|
## Konfigurierbare Parameter
|
|
|
|
In `/etc/signage/config.yml` oder Umgebungsvariablen:
|
|
|
|
```yaml
|
|
watchdog:
|
|
browser:
|
|
check_interval_sec: 30
|
|
health_check_timeout_sec: 5
|
|
restart_backoff_steps: [0, 2, 5, 10, 30] # Sekunden
|
|
max_consecutive_errors: 10
|
|
error_window_sec: 300
|
|
agent:
|
|
systemd_unit: "signage-agent.service"
|
|
healthcheck_timeout_sec: 10
|
|
```
|
|
|
|
## Testing und Validierung
|
|
|
|
Testfaelle fuer den Watchdog:
|
|
|
|
1. Chromium manuell toeten (`kill -9 PID`) — sollte innerhalb 30s neustartet werden
|
|
2. Player-Agent starten/stoppen — systemd sollte neustart triggern
|
|
3. Player-UI HTTP-Server abschalten — Browser-Watchdog sollte neustarten
|
|
4. Schnelle aufeinanderfolgende Crashes — Backoff-Exponentialfunktion pruefen
|
|
5. Admin-Kommando `restart_player` — geordneter Neustart, dann Restart-Counter nicht erhoeht
|
|
6. Watchdog-Logs auf Struktur und Vollstaendigkeit pruefen
|
|
|
|
## Zusammenfassung
|
|
|
|
Der Watchdog-Ansatz ist:
|
|
|
|
- **Transparent** — klare Logging und Admin-Sichtbarkeit
|
|
- **Progressive** — Backoff statt Restart-Schleife
|
|
- **Defensiv** — mehrere Erkennungsmethoden (Prozess, HTTP, optional Rendering)
|
|
- **Integriert** — arbeitet mit systemd zusammen, nicht gegen es
|
|
- **Skalierbar** — Verfahren gilt fuer alle Player unabhaengig von Standort oder Netzwerk
|