Wartung: SSH-Bulk-Update & -Neustart für Linux-Clients

Neue Seite "Wartung" (Geräte-Bereich, eigenes Rechtepaar
maintenance.view/maintenance.edit), komplett getrennt vom PoE-Neustart
auf dem Dashboard:

- Dashboard-Neustart bleibt ausschließlich PoE-Reset über den Switch
- Wartung läuft immer per SSH direkt auf dem Gerät, unabhängig von
  jeder Switch-Zuordnung -- nur Geräte mit SSH-Zugangsdaten der
  Kategorie "Linux-Client" erscheinen dort (Windows/PowerShell folgt
  als eigener, separater Schritt -- kein Testsystem dafür verfügbar)

Backend:
- _run_ssh_command()/_run_ssh_reboot(): nicht-interaktive SSH-Ausführung
  mit paramiko.RejectPolicy() gegen dieselbe known_hosts-Datei wie das
  interaktive Browser-Terminal -- ein Host muss vorher einmal per
  "Verbindung testen" bestätigt worden sein, da hier (anders als im
  Terminal) niemand eine "yes/no"-Rückfrage beantworten kann
- _apt_upgrade_command(): "apt update && apt upgrade -y" nicht-
  interaktiv mit DEBIAN_FRONTEND=noninteractive und
  --force-confdef/--force-confold, damit ein Paket-Postinst-Skript
  nicht auf eine nie kommende Config-Rückfrage wartet
- Reboot behandelt einen abrupten Verbindungsabbruch NACH dem Kommando
  als Erfolg (die Maschine fährt herunter, bevor sie antworten kann);
  nur ein Fehler VOR dem Reboot-Kommando zählt als echter Fehler
- Job-Status lebt im Prozessspeicher (wie das SSH-Terminal), Live-
  Anzeige per Polling (/maintenance/status)

Live gegen ein dediziertes Testsystem (getrennt vom gemeinsam
genutzten App-Host, um dort kein echtes apt upgrade auszulösen)
verifiziert: echtes "apt update && apt upgrade" inkl. Kernel-/systemd-/
netplan-Paketen lief vollständig durch, anschließender SSH-Neustart hat
das System nachweislich neu gestartet (uptime nach dem Job bestätigt).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 11:12:07 +02:00
co-authored by Claude Sonnet 5
parent 63ca7782ba
commit 8772f7777b
5 changed files with 620 additions and 13 deletions
+15
View File
@@ -750,6 +750,21 @@ table.data-table {
.row-actions { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.row-actions form { display: flex; }
.job-output-pre {
font-family: var(--font-mono);
font-size: 12px;
color: var(--text-dim);
background: var(--bg-input);
border: 1px solid var(--border-soft);
border-radius: 8px;
padding: 12px 14px;
margin: 6px 0;
max-height: 320px;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
}
.empty-row td {
text-align: center;
padding: 40px 16px;