feat(updateservice): Plattform-Dimension, signierte Releases, Update mit Rollback
Behebt eine Reihe zusammenhaengender Fehler im Update-Weg, die zusammen verhindert haben, fuer mehr als eine Plattform auszuliefern - und die im Fehlerfall halb aktualisierte Installationen hinterliessen. Server - Migration 009: Spalte platform samt neuem Unique-Key. Zuvor verdraengte das zuletzt veroeffentlichte Paket alle anderen Plattformen derselben Version, weil ON DUPLICATE KEY auf (slug, version, channel) griff. Ein Linux-System zog sich damit das Windows-Paket. - Aufloesungsregel: je Version das plattformgenaue Paket, sonst das plattformunabhaengige. Ein Client ohne Plattformangabe sieht ausschliesslich 'any' - lieber kein Update als das falsche. - manifest_json wird endlich befuellt; die Spalte blieb bisher immer leer, wodurch die API nie der Rueckfall sein konnte, als der sie gedacht war. - Releases werden serverseitig mit RSA-SHA256 signiert, neuer Endpunkt /api/updateservice/v1/pubkey. Bewusst kein HMAC: der Pruefende laeuft auf fremden Systemen und darf den Signierschluessel nicht besitzen. Packager - Bricht ab, statt die Versionshistorie zu verlieren. Schlug das Lesen der bestehenden latest.json fehl, ersetzte ein leeres catch die komplette Historie durch einen einzigen Eintrag - ohne jede Meldung. - Echte Glob-Muster. Zuvor trafen "logs/**" und "scratch/**" aus der mitgelieferten Beispielkonfiguration nie zu. - preservePatterns: Konfigurationsvorlagen werden ausgeliefert, ersetzen am Ziel aber keine vorhandene Datei. Eine settings.json mit Zugangsdaten ueberschrieb bisher beim Update die Konfiguration jedes Zielsystems. - Warnt vor Dateien, die nach Zugangsdaten aussehen und auf keiner Liste stehen. - Prueft --version gegen die Hauptassembly. Eine Abweichung fuehrte zu einer Endlosschleife: Clients aktualisieren, melden weiter die alte Version, halten das Release erneut fuer neu. - --platform mit Ableitung aus dem Publish-Pfad. Agent - Anwenden mit Plan, Backup und vollstaendigem Rollback. Die Stelle war als "Atomic Replace with Backup" kommentiert und war eine Kopierschleife. - Verwaiste Dateien werden entfernt, aber nur solche aus dem Manifest der Vorversion. Was nicht aus einem Release stammt, bleibt liegen. - Das laufende Agent-Binary wird zur Seite gelegt statt ueberschrieben. - API-Rueckfall in FetchManifestAsync; bisher nur im SDK vorhanden, weshalb die Anwendung "Update verfuegbar" und der Agent "kein Release" sagen konnte. - Installierte Version aus --current-version oder manifest.json statt des Textes "Unbekannt", der als 0 gelesen wurde und jede Version neuer erscheinen liess. Reparatur funktioniert damit auch ohne manifest.json. - Setzt das Ausfuehrungsbit fuer Linux-Pakete, die unter Windows gebaut wurden. SDK - ResolveAgentPath() liefert den plattformrichtigen Namen; ein fest verdrahtetes "update-agent.exe" wird unter Linux nie gefunden. - LaunchUpdateAgent uebergibt jetzt --restart (wurde nie uebergeben, die Anwendung blieb nach dem Update zu), --wait-for-pid (kein Wettlauf mehr mit dem Herunterfahren) und --platform. Enthaelt ausserdem die bislang nicht committete Arbeit an Watchdog, Lizenz- Client und cli/tick.php samt Migration 008; die betroffenen Dateien liessen sich nicht getrennt stagen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5f9b0c5596
commit
2388b5abe1
@@ -3,7 +3,7 @@
|
||||
Überwachung von Anwendungen, Diensten und Servern über Heartbeats.
|
||||
|
||||
> **Stand:** Version 2.0 — vollständig überarbeitet. Wer eine ältere Integration
|
||||
> betreibt, findet die Änderungen in Abschnitt 8.
|
||||
> betreibt, findet die Änderungen in Abschnitt 9.
|
||||
|
||||
---
|
||||
|
||||
@@ -26,10 +26,11 @@ ausgefallen.
|
||||
> Dienst bliebe dauerhaft grün.
|
||||
>
|
||||
> ```bash
|
||||
> * * * * * curl -fsS -H "Authorization: Bearer <SHARED_KEY>" https://dc.mhdf.de/api/watchdog/v1/evaluate > /dev/null
|
||||
> * * * * * /usr/bin/php /pfad/zum/deploymentcenter/cli/tick.php --quiet
|
||||
> ```
|
||||
>
|
||||
> Fehlt der Job, zeigt das WebUI oben einen Warnhinweis.
|
||||
> Fehlt der Job, zeigt das WebUI oben einen Warnhinweis. Details und die
|
||||
> HTTP-Variante: **[§11](#11-der-evaluator-tick)**.
|
||||
|
||||
---
|
||||
|
||||
@@ -72,6 +73,7 @@ Content-Type: application/json
|
||||
"message": "Verarbeite Warteschlange",
|
||||
"group": "Applications",
|
||||
"os": ".NET 8 Service",
|
||||
"version": "1.4.3",
|
||||
|
||||
"checks": { "db": { "ok": true },
|
||||
"market_feed": { "ok": false, "message": "Letzter Tick vor 14 min" } },
|
||||
@@ -89,9 +91,31 @@ Content-Type: application/json
|
||||
| `message` | nein | Kurztext, erscheint im Dashboard |
|
||||
| `group` | nein | Gruppierung im Dashboard |
|
||||
| `os` | nein | Plattform, steuert auch die Icon-Erkennung |
|
||||
| `version` | nein | Version der laufenden Anwendung (Alias: `app_version`) |
|
||||
| `checks` | nein | Selbst ermittelter Gesundheitszustand, siehe 4. |
|
||||
| `metrics` | nein | Numerische Werte, siehe 5. |
|
||||
|
||||
### Welche Version läuft dort?
|
||||
|
||||
`version` erscheint als eigene Spalte in der Monitorliste und kommt im
|
||||
Heartbeat-Antwortobjekt als `app_version` zurück. Damit ist auf einen Blick
|
||||
sichtbar, ob ein Ausfall zeitlich zu einem Rollout passt — „Monitor X ist seit
|
||||
dem Rollout von 1.4.3 unten".
|
||||
|
||||
Das Feld ist optional und **überschreibt einen früheren Wert nicht mit `null`**:
|
||||
ein Agent, der es nicht mitschickt, löscht die zuletzt gemeldete Version nicht.
|
||||
Bestehende Agenten laufen also unverändert weiter.
|
||||
|
||||
```csharp
|
||||
// Am einfachsten aus der vom Build erzeugten Klasse, siehe
|
||||
// UPDATESERVICE_INTEGRATION_GUIDE §2B
|
||||
version = BuildInfo.Version
|
||||
```
|
||||
|
||||
> Der Fehler-Stream führt `build`, der Bugtracker `build_version`, die
|
||||
> Aktivierungsliste des Lizenzmoduls `app_version` — nur der Watchdog konnte
|
||||
> bis 2.1 nicht sagen, welche Version tatsächlich läuft.
|
||||
|
||||
### Zulässige Werte für `status`
|
||||
|
||||
| Wert | Zustand | Wirkung |
|
||||
@@ -217,6 +241,7 @@ public sealed class WatchdogReporter
|
||||
interval = 60,
|
||||
message,
|
||||
os = Environment.OSVersion.ToString(),
|
||||
version = BuildInfo.Version, // erscheint in der Monitorliste
|
||||
checks,
|
||||
metrics
|
||||
};
|
||||
@@ -372,6 +397,8 @@ Zulässige `kind`-Werte: `started`, `stopped_graceful`, `crash_suspected`,
|
||||
| Geplantes Beenden | nicht möglich | `status: "stopped"` bzw. `"maintenance"` |
|
||||
| Alarme bei Ausfall eines Hosts | eine Meldung je Kind | Kinder werden unterdrückt |
|
||||
| Antwortformat | uneinheitlich | `{"status":"success",…}` bzw. `{"status":"error","error":{"code":…}}` |
|
||||
| Laufende Version | nicht übermittelbar | Feld `version` (seit 2.1) |
|
||||
| OpenAPI-Beschreibung | `/event`, `/events`, `/status` fehlten, ebenso `group` und `type` am Ping | vollständig |
|
||||
|
||||
Bestehende Agenten mit `wd_live_`-Token und einfachem `ok`-Ping laufen
|
||||
unverändert weiter — die neuen Felder sind alle optional.
|
||||
@@ -389,3 +416,75 @@ unverändert weiter — die neuen Felder sind alle optional.
|
||||
4. **`checks` nutzen.** Ein Heartbeat sagt nur, dass ein Thread läuft.
|
||||
5. **Hierarchie pflegen**, wenn Dienste auf gemeinsamen Hosts laufen — sonst
|
||||
bringt ein Hostausfall eine Alarmlawine.
|
||||
6. **`version` mitschicken.** Ohne sie lässt sich ein Ausfall nicht mit einem
|
||||
Rollout in Verbindung bringen.
|
||||
|
||||
---
|
||||
|
||||
## 11. Der Evaluator-Tick
|
||||
|
||||
Der Evaluator ist die Komponente, die Monitore anhand ihres erwarteten
|
||||
Intervalls herabstuft. Er läuft **nicht** von selbst — ohne einen Cron-Eintrag
|
||||
sind die Zustände im Dashboard wertlos.
|
||||
|
||||
Er erledigt in einem Durchlauf:
|
||||
|
||||
- Monitore anhand `expected_interval_sec` auf `warning` bzw. `down` stufen
|
||||
- Zustandswechsel im Ereignisprotokoll festhalten und Webhooks auslösen
|
||||
- Alarme für Kinder eines ausgefallenen Hosts unterdrücken
|
||||
- abgelaufene Bugtracker-Leases freigeben
|
||||
- stündlich den Metrik-Verlauf abräumen
|
||||
|
||||
### Interner Aufruf (empfohlen)
|
||||
|
||||
```bash
|
||||
* * * * * /usr/bin/php /pfad/zum/deploymentcenter/cli/tick.php --quiet
|
||||
```
|
||||
|
||||
Entspricht dem früheren `watchdog/cli/tick.php`. Kein Schlüssel im Crontab,
|
||||
keine Abhängigkeit von Webserver, TLS oder DNS — und damit auch dann
|
||||
lauffähig, wenn der Webserver gerade das Problem ist.
|
||||
|
||||
| Option | Wirkung |
|
||||
|---|---|
|
||||
| `-q`, `--quiet` | Ausgabe nur bei Zustandswechseln und Fehlern (für Cron) |
|
||||
| `-j`, `--json` | Ergebnis maschinenlesbar |
|
||||
| `--no-lock` | Sperre gegen überlappende Läufe übergehen (nur zur Fehlersuche) |
|
||||
| `-h`, `--help` | Hilfe |
|
||||
|
||||
| Rückgabewert | Bedeutung |
|
||||
|---|---|
|
||||
| `0` | Lauf erfolgreich |
|
||||
| `1` | Fehler — Meldung auf `stderr`, Einzelheiten im Log unter `var/log/` |
|
||||
| `2` | Übersprungen, es lief bereits ein Tick |
|
||||
|
||||
Das Skript sperrt sich über `var/watchdog-tick.lock` selbst. Braucht ein Lauf
|
||||
länger als eine Minute, überspringt der nächste Cron-Aufruf — sonst würden
|
||||
zwei Evaluatoren dieselben Zustandswechsel doppelt melden.
|
||||
|
||||
> Der Aufruf ist auf `PHP_SAPI === 'cli'` beschränkt und `cli/` ist zusätzlich
|
||||
> per `.htaccess` gesperrt. Über den Webserver ist das Skript also nicht
|
||||
> erreichbar — sonst ließe sich ein Evaluationslauf ohne jede Authentifizierung
|
||||
> auslösen, während der HTTP-Endpunkt dafür bewusst den Shared Key verlangt.
|
||||
|
||||
### Über die Schnittstelle
|
||||
|
||||
Sinnvoll, wenn der Cron auf einer anderen Maschine läuft:
|
||||
|
||||
```bash
|
||||
* * * * * curl -fsS -H "Authorization: Bearer <SHARED_KEY>" https://dc.mhdf.de/api/watchdog/v1/evaluate > /dev/null
|
||||
```
|
||||
|
||||
Beide Wege rufen denselben Code auf und schreiben denselben Lauf-Vermerk in
|
||||
`watchdog_cron_jobs`. **Nur einen von beiden einrichten** — zwei parallele
|
||||
Zeitpläne bringen keinen Gewinn, nur die Gefahr überlappender Läufe.
|
||||
|
||||
### Prüfen, ob er läuft
|
||||
|
||||
```bash
|
||||
php cli/tick.php --json
|
||||
curl https://dc.mhdf.de/api/health -H "Authorization: Bearer <SHARED_KEY>"
|
||||
```
|
||||
|
||||
`/api/health` meldet unter `checks.evaluator` den letzten Lauf. Im WebUI zeigt
|
||||
das Watchdog-Modul denselben Zustand als Abzeichen **AKTIV** / **INAKTIV**.
|
||||
|
||||
Reference in New Issue
Block a user