1. Manuelle Reservierungen (dhcp_manual_reservations) fuer Geraete, die nicht als Client in dieser App gepflegt werden -- bewusst eine eigene, explizite Aktion (MAC/IP/Name), damit kein externes Geraet unueberwacht automatisch eine feste IP bekommt. _dhcp_reservation_candidates fuehrt automatische (aus devices) und manuelle Reservierungen jetzt zusammen, case-insensitiv nach MAC dedupliziert (automatisch gewinnt bei Konflikt). Automatische Reservierungen sind in der Tabelle nicht loeschbar (Schloss-Symbol statt Button, sie entstehen/verschwinden mit den Client-Stammdaten), manuelle schon. Live verifiziert: Hinzufuegen, doppelte MAC ablehnen, ungueltige MAC ablehnen, generierte Kea-Config mit gemischten Auto-/manuellen Reservierungen besteht kea-dhcp4 -t. 2. Standard-DHCP-Optionen um 10 weitere verifizierte Optionen erweitert (u.a. host-name/12 -- Kea-Name mit Bindestrich, NICHT "hostname", live gegen echtes Kea geprueft) -- jetzt 57 insgesamt. Standard-Optionen sind nicht mehr loeschbar (Backend lehnt es ab, UI zeigt ein Schloss-Symbol statt Loeschen-Button) -- vorher liess sich eine vorbefuellte Options- Definition versehentlich entfernen. 3. Options-Tabellen (global UND pro Reservierung) zeigen jetzt nur noch tatsaechlich genutzte Options -- eigene immer, Standard-Optionen nur mit gesetztem Wert. Weitere Standard-Optionen kommen ueber ein Dropdown "+ Option hinzufuegen" dazu statt permanent alle 57 als leere Felder zu zeigen. Das neu eingeblendete Feld wird automatisch in den sichtbaren Bereich gescrollt und fokussiert (bei bis zu 57 moeglichen Optionen kann das Feld sonst weit unterhalb des sichtbaren Modal-Ausschnitts liegen und es wirkt so, als waere nichts passiert). 4. Lease-Countdown-Fix: die Ablaufzeit wird jetzt explizit als UTC ausgewiesen (Kea arbeitet intern in UTC-Epoch) und zusaetzlich als live tickender Countdown angezeigt (gleiches Prinzip wie der bestehende "Naechste Pruefung"-Timer). Vorher wirkte eine reine Absolutzeit auf der nicht selbst aktualisierenden Seite bei den kurzen Standard-Lease-Zeiten (600s) schnell "schon abgelaufen", sobald etwas Zeit vergangen war, bis man tatsaechlich hinschaut -- live im echten Betrieb genau als dieses Missverstaendnis beobachtet und anhand der rohen Kea-CSV verifiziert, dass die richtige Spalte (expire) korrekt gelesen wird. 5. UI-Feinschliff: "In Datei schreiben" bei den Reservierungen heisst jetzt "Speichern" und ist der primaere (orange) Button, "Reservierung hinzufuegen" sekundaer -- das Hinzufuegen legt nur einen Datensatz an, erst "Speichern" schreibt die tatsaechlich wirksame Kea-Config. Alles live auf der Test-VM deployt und verifiziert (Playwright fuer die Dropdown-Sichtbarkeit/Fokus-Interaktion, curl fuer die Backend-Validierung, kea-dhcp4 -t fuer die generierte Konfiguration), keine Fehler im journalctl-Log.
613 lines
36 KiB
Markdown
613 lines
36 KiB
Markdown
# PoE Manager — Modern UI Rebuild
|
|
|
|
Webbasierte Verwaltung und Monitoring von PoE-Devices und Aruba-Switchen —
|
|
funktionales Rebuild von [Aruba-PoE](https://gitea.int.eertmoed.net/WiS/Aruba-PoE)
|
|
mit komplett neuem, modernem Frontend und einem granularen Rechtesystem.
|
|
|
|
**Das Projekt ist ausschließlich für Linux ausgelegt** (Zielsystem: eine
|
|
Linux-VM). Entwickelt wird unter WSL2 (Ubuntu) unter Windows — siehe
|
|
[Entwicklung unter WSL](#entwicklung-unter-wsl) weiter unten.
|
|
|
|
Die App ermöglicht:
|
|
|
|
- **Öffentliches Kachel-Dashboard ohne Login** — zeigt nur aktive (nicht
|
|
deaktivierte) Geräte, nur Online/Offline/Gesamt-Statistik; volle Verwaltung,
|
|
Aktivieren/Deaktivieren und PoE-Neustart bleiben hinter dem Login. Eingeloggt
|
|
sind zusätzlich deaktivierte Geräte sichtbar (eigene Kachel-Sektion). Alle
|
|
Kacheln sind durchsuchbar und in drei Abschnitten sortiert: Offline, Online,
|
|
Deaktiviert — jeweils alphabetisch
|
|
- Verwaltung von Devices und Switches
|
|
- **Zugangsdaten als eigene, wiederverwendbare Entität**: SSH-Logins werden
|
|
einmal angelegt und können mehreren Switchen zugeordnet werden; beim
|
|
Anlegen eines Switches lassen sich bestehende Zugangsdaten auswählen oder
|
|
direkt neue hinterlegen, ohne vorher zu „Zugangsdaten“ wechseln zu müssen
|
|
- **Browser-SSH-Terminal beim Anlegen/Bearbeiten eines Switches**, um den
|
|
Host-Key zu bestätigen und die Zugangsdaten direkt zu prüfen, bevor der
|
|
Switch gespeichert wird — funktioniert auf jedem Betriebssystem, die
|
|
SSH-Verbindung wird dabei immer vom PoE-Server aus aufgebaut
|
|
- Manueller PoE-Neustart einzelner Geräte per Klick; bei deaktivierten
|
|
Geräten bietet das Detail-Popup stattdessen direkt eine Aktivieren-Option
|
|
- Einstellbares Prüfintervall (steuert den Hintergrund-Check-Dienst) —
|
|
der Countdown „Nächste Prüfung“ wird aus dem tatsächlichen letzten
|
|
Log-Eintrag berechnet, nicht bei jedem Seitenaufruf neu gestartet, und
|
|
läuft **global in der Topbar auf jeder Seite** (nicht nur im Dashboard)
|
|
- Live-Log-Ansicht mit farblicher Hervorhebung (online/offline/Neustart);
|
|
Dashboard und Live-Log aktualisieren sich automatisch im Hintergrund
|
|
(per AJAX, ohne vollen Seiten-Reload). Ein „Jetzt prüfen"-Icon neben dem
|
|
Timer (nur Admins) startet manuell einen sofortigen Prüf-Durchlauf —
|
|
der Countdown setzt sich dabei auf den manuell ausgelösten Zeitpunkt zurück
|
|
- **Einheitliches Seiten-Layout**: die Topbar zeigt rechts ausschließlich
|
|
den „Nächste Prüfung“-Timer; Anlegen-Buttons und eine kurze Beschreibung
|
|
sitzen stattdessen direkt über der jeweiligen Tabelle. Die Listen
|
|
(Geräte, Switche, Zugangsdaten, Benutzer, Gruppen) sind per Klick auf die
|
|
Spaltenüberschrift sortierbar
|
|
- **Rechtesystem mit Gruppen**: Admins dürfen immer alles (als Gruppe „Admin“
|
|
überall mit aufgeführt); normalen Benutzern lassen sich über Gruppen
|
|
einzelne Verwaltungsrechte gezielt zuweisen, inkl. reiner Ansichtsrechte
|
|
(siehe [Rechtesystem](#rechtesystem-gruppen--berechtigungen))
|
|
- Einklappbare Sidebar (Desktop: dauerhaft, über Neuladen hinweg gemerkt;
|
|
mobil: temporäres Überlagern)
|
|
- **Änderungslog**: jede Anlage/Bearbeitung/Löschung sowie Aktivieren/
|
|
Deaktivieren von Geräten, Switchen, Zugangsdaten, Benutzern und Gruppen
|
|
wird protokolliert (wer, wann, was) — einsehbar unter „Logs → Änderungslog“;
|
|
Geräte und Switche merken sich zusätzlich direkt am Datensatz, wer sie
|
|
zuletzt geändert hat. PoE-Neustarts werden bewusst **nicht** geloggt
|
|
(siehe [Änderungslog](#änderungslog))
|
|
- **Verschlüsselter Import/Export**: Geräte, Switche und Zugangsdaten lassen
|
|
sich unter „Einstellungen → Im-/Export" als ein mit selbstgewählter
|
|
Passphrase verschlüsseltes Bundle exportieren und auf einer neuen Umgebung
|
|
wieder importieren (siehe [Import/Export](#importexport))
|
|
- **Eigenes Konto**: das Zahnrad-Symbol neben dem eigenen Namen unten in der
|
|
Sidebar führt zu „Mein Konto“ — Vor-/Nachname, eigenes Passwort und
|
|
Profilbild pflegen (siehe [Eigenes Konto](#eigenes-konto--profilbild))
|
|
- **Anpassbare Navigation**: Admins legen dort zusätzlich die Reihenfolge der
|
|
Sidebar-Hauptpunkte per Auf-/Ab-Buttons fest; jeder Benutzer sieht davon
|
|
ohnehin nur, wofür er berechtigt ist — auch pro Unterpunkt innerhalb einer
|
|
Gruppe (siehe [Navigation anpassen](#navigation-anpassen))
|
|
|
|
## Was ist neu gegenüber dem Original?
|
|
|
|
- **Komplett neues Frontend**: eigenes Design-System (kein Bootstrap mehr),
|
|
Logo mittig in der Topbar (auf jeder Seite, skaliert auf die Balkenhöhe),
|
|
Sidebar-Navigation (nur für eingeloggte Nutzer sichtbar), Dark/Light-
|
|
Umschalter, Karten-Dashboard mit Live-Zählern, moderne Modals/Toasts statt
|
|
Browser-`confirm()` und Bootstrap-Alerts.
|
|
- **Dashboard jetzt teilweise öffentlich**: `/` ist ohne Login erreichbar und
|
|
zeigt eine reduzierte Lese-Ansicht (Hostname, IP, Status, letzte Prüfung)
|
|
mit Login-Button; alle Verwaltungsseiten und der PoE-Neustart bleiben
|
|
`@login_required` und zusätzlich rechtebasiert (s.u.).
|
|
- **Browser-SSH-Terminal für Switche**, implementiert mit **paramiko** (reines
|
|
Python) statt eines lokalen pty + System-`ssh`-Client — läuft dadurch
|
|
plattformunabhängig. Die SSH-Verbindung zum Switch wird immer serverseitig
|
|
(vom PoE-Server) aufgebaut, nie vom Browser/Client aus.
|
|
- **Granulares Rechtesystem mit Gruppen** (neu, siehe unten) statt der
|
|
ursprünglichen reinen Admin/User-Unterscheidung.
|
|
- **Gleiche Kernlogik**: Datenbankschema (erweitert um Gruppen/Rechte),
|
|
Login, PoE-Restart-Mechanismus (`poe.sh` per SSH/`expect` auf die
|
|
Aruba-Switche) sind ansonsten unverändert.
|
|
- **Aufgeräumtes Backend**: konsistente, konfigurierbare Pfade (`POE_DB_PATH`,
|
|
`POE_SCRIPT`, `POE_LOG_GLOB`, …) statt hart codierter/inkonsistenter Pfade;
|
|
Secret-Key und Fernet-Key werden beim ersten Start automatisch generiert
|
|
statt im Repo zu liegen.
|
|
|
|
> ⚠️ **Sicherheitshinweis zum Original-Repo:** Im Original sind `sqlite.db`
|
|
> (Nutzer-Passwort-Hashes, verschlüsselte Switch-Passwörter) und `fernet.key`
|
|
> (der zugehörige Schlüssel) mit im Git-Repo eingecheckt — die `.gitignore`
|
|
> dort schließt sie über die `!`-Regeln versehentlich wieder ein. In diesem
|
|
> Rebuild sind beide Dateien in `.gitignore` ausgeschlossen und werden beim
|
|
> ersten Start frisch erzeugt. Empfehlung fürs Original-Repo: beide Dateien
|
|
> aus der Git-Historie entfernen und Fernet-Key sowie alle Switch-/User-
|
|
> Passwörter rotieren.
|
|
|
|
## Rechtesystem (Gruppen & Berechtigungen)
|
|
|
|
Admins dürfen immer alles. Zusätzlich gibt es **Gruppen** mit einem
|
|
**vollständig granularen, an der Navbar gespiegelten Rechtebaum** — jeder
|
|
Bereich der App (nicht nur Devices/Switches) lässt sich einzeln freischalten.
|
|
Ein Benutzer kann mehreren Gruppen angehören, die Rechte addieren sich
|
|
(Vereinigung, nicht Schnittmenge).
|
|
|
|
### Zweistufiger Rechtebaum
|
|
|
|
Der Baum hat genau zwei Ebenen, exakt gespiegelt an den drei Sidebar-Gruppen
|
|
(Geräte/Logs/Einstellungen). Auf der Gruppen-Seite stehen sie als drei
|
|
kompakte Spalten nebeneinander, mit einer kurzen Legende direkt darüber.
|
|
Jede Spalte ist eine kleine Tabelle: die Kopfzeile enthält in EINER Zeile
|
|
sowohl den Bereichsnamen mit seinem Kästchen (dem Kill-Switch, dicht
|
|
nebeneinander statt an den Rand gestellt) als auch die Buchstaben-Spalten
|
|
**R**(ead/Lesen), **W**(rite/Schreiben, Anlegen), **E**(dit/Ändern) — nur
|
|
die Rechte, die dieser Bereich tatsächlich nutzt. Darunter je eine
|
|
eingerückte Zeile pro Unterpunkt. **„Ändern“ deckt Löschen überall mit
|
|
ab** — es gibt bewusst kein eigenes Löschen-Recht. Eine vierte Spalte **D**
|
|
gibt es nur bei Geräte → Clients, und sie bedeutet dort **nicht** Löschen,
|
|
sondern *PoE-Neustart über das Dashboard-Popup auslösen* (automatische
|
|
Neustarts bei Ausfall über `poe.sh` sind davon komplett unabhängig und
|
|
laufen immer). Für Zeilen ohne passendes Recht (z.B. „D“ bei Switche/
|
|
Zugangsdaten/Benutzer/Gruppen) wird eine ausgegraute, nicht anklickbare
|
|
Checkbox angezeigt statt die Zelle wegzulassen:
|
|
|
|
```
|
|
☑ Geräte R W E D ☑ Logs R W E ☑ Einstellungen R W E
|
|
Clients ☑ ☑ ☑ ☑ Live ☑ ☑ ☑ Benutzer ☑ ☑ ☑
|
|
Switche ☑ ☑ ☑ ▢ Änd. ☑ ☑ ☑ Gruppen ☑ ☑ ☑
|
|
Zugangsd. ☑ ☑ ☑ ▢ Systemeinst. ☑ ▢ ☑
|
|
Im-/Export ☑ ▢ ☑
|
|
```
|
|
|
|
Das jeweilige „Bereich sichtbar“-Recht (`devices_group.view` /
|
|
`logs_group.view` / `settings_group.view`, das Kästchen in der Kopfzeile
|
|
einer Spalte) wirkt als **Kill-Switch**: ist es für eine Gruppe nicht
|
|
gesetzt, greift kein einziges Recht darunter mehr — selbst wenn z.B.
|
|
`devices.view` einzeln noch angehakt ist. So lässt sich ein ganzer Bereich
|
|
mit einem Klick sperren, ohne jedes Unterrecht einzeln zurücknehmen zu
|
|
müssen (`User.has_permission()` in `app.py`). Auf der Gruppen-Seite sind
|
|
die Unterpunkt-Zeilen einer Spalte per JavaScript so lange gesperrt UND
|
|
sichtbar ausgegraut (nicht nur das dezente native disabled-Styling), bis
|
|
das Kopfzeilen-Kästchen angehakt ist.
|
|
|
|
### Systemgruppen
|
|
|
|
Zwei Gruppen sind fest und **weder umbenennbar noch in ihren Rechten
|
|
änderbar** (auch nicht durch Admins über die UI) — Mitgliedschaft bleibt bei
|
|
beiden frei verwaltbar:
|
|
- **Admin** — virtuell (kein echter `groups`-Datensatz), intern über den
|
|
`is_admin`-Schalter der Benutzer gesteuert, immer alle Rechte. Mindestens
|
|
ein Admin muss bestehen bleiben (serverseitig erzwungen).
|
|
- **Benutzer** — die Standardgruppe (`is_system`-Flag), der jeder neu
|
|
angelegte Nicht-Admin automatisch zugeordnet wird. Fester Rechtesatz:
|
|
Geräte-Bereich + Clients/Switche lesen, Logs-Bereich + Live-Log lesen.
|
|
|
|
Alle anderen Gruppen sind vom jeweiligen Rechteinhaber (`groups.edit`, das
|
|
auch Anlegen und Löschen von Gruppen umfasst) frei konfigurierbar.
|
|
|
|
### Eskalationsschutz
|
|
|
|
Da jetzt auch **Benutzer-** und **Gruppenverwaltung** delegierbar sind (z.B.
|
|
eine Gruppe mit nur `users.edit`, ohne Admin zu sein), gelten zusätzlich zu
|
|
den granularen Rechten diese fest einprogrammierten Schranken, unabhängig
|
|
davon, was eine Gruppe an Rechten hat:
|
|
- Ein Benutzer als Admin anlegen/dazu machen (`group_id=admin` bei
|
|
Anlegen/Zuweisen) bleibt echten Admins vorbehalten.
|
|
- Ein bestehendes Admin-Konto bearbeiten, löschen oder ihm die Gruppe ändern
|
|
bleibt echten Admins vorbehalten.
|
|
- Wer Admin ist, wird ausschließlich über „Admin-Mitglieder verwalten“ auf
|
|
der Gruppen-Seite gesteuert — bleibt admin-exklusiv, unabhängig von
|
|
`groups.edit`.
|
|
|
|
Sowohl das Anzeigen jeder Seite als auch jede einzelne Aktion (Buttons,
|
|
Formulare) ist an das jeweilige Recht gekoppelt — im Frontend ausgeblendet
|
|
**und** im Backend serverseitig durchgesetzt, unabhängig vom Frontend.
|
|
|
|
Datenmodell: `groups` (inkl. `is_default`- und `is_system`-Flag),
|
|
`group_permissions` (Gruppe → Recht), `user_groups` (Benutzer → Gruppe).
|
|
Bestehende Datenbanken werden beim App-Start automatisch migriert
|
|
(`_ensure_schema()` in `app.py`): `devices.toggle` → `devices.edit`,
|
|
`switches.*` → gespiegelte `credentials.*`, nachträgliches Setzen der neuen
|
|
Bereichs-Rechte für bereits vergebene Unterrechte, sowie (spätere Revision)
|
|
sämtliche `*.delete`-Rechte → `*.edit` (Löschen wurde nachträglich überall in
|
|
Ändern gefaltet). Jede dieser Migrationen läuft **nur einmalig** über einen
|
|
eigenen Guard in der `settings`-Tabelle, damit z.B. ein bewusst deaktiviertes
|
|
Bereichs-Recht nicht bei jedem Neustart automatisch wieder gesetzt wird.
|
|
|
|
## Zugangsdaten (wiederverwendbare SSH-Logins)
|
|
|
|
Switch-Zugangsdaten (Username + verschlüsseltes Passwort) sind eine eigene
|
|
Entität (`credentials`-Tabelle) statt direkt am Switch zu hängen — mehrere
|
|
Switche mit demselben Login teilen sich einen Eintrag. Beim Anlegen/Bearbeiten
|
|
eines Switches lässt sich per Dropdown ein bestehender Eintrag auswählen oder
|
|
über „+ Neue Zugangsdaten anlegen“ direkt im selben Formular ein neuer
|
|
anlegen, ohne vorher zur eigenen **Zugangsdaten**-Seite wechseln zu müssen.
|
|
Löschen ist nur möglich, wenn kein Switch mehr auf den Eintrag verweist.
|
|
Bestehende Datenbanken aus einer älteren Version (Username/Passwort direkt
|
|
am Switch) werden beim ersten Start automatisch migriert.
|
|
|
|
Jeder Switch kann außerdem einen individuellen **SSH-Port** hinterlegen
|
|
(Feld „SSH-Port“ beim Anlegen/Bearbeiten) — bleibt er leer, wird überall
|
|
automatisch **Port 22** angenommen (`SWITCH_DEFAULT_SSH_PORT` in `app.py`).
|
|
Der Port wird konsistent an allen drei Stellen verwendet, an denen die App
|
|
sich per SSH mit einem Switch verbindet: dem Web-Terminal (Verbindungstest),
|
|
`generate_ips.py` (liefert ihn als eigenes Feld an `poe.sh`) und den
|
|
`expect`-Aufrufen in `poe.sh` selbst (`ssh -p <port> ...`) für automatische
|
|
wie manuelle PoE-Neustarts.
|
|
|
|
## DHCP-Reservierungen & eigene Options (Systemeinstellungen → DHCP)
|
|
|
|
Erzeugt aus den vorhandenen Client-Stammdaten (MAC + IP + Name) automatisch
|
|
feste DHCP-Reservierungen inkl. eigener/herstellerspezifischer Options, ohne
|
|
die Daten ein zweites Mal pflegen zu müssen. Eigenes Rechtepaar
|
|
`settings_dhcp.view`/`settings_dhcp.edit`, gespiegelt in der Navbar unter
|
|
Einstellungen.
|
|
|
|
**Backend: Kea DHCP** (`kea-dhcp4-server`), nicht das ältere
|
|
`isc-dhcp-server` — ISC hat isc-dhcp-server 2022 als EOL erklärt, Kea ist
|
|
der aktiv weiterentwickelte Nachfolger und bildet „globaler Wert, pro Client
|
|
überschreibbar“ nativ ab (siehe unten).
|
|
|
|
- **Status-Erkennung** (rein lesend): `shutil.which("kea-dhcp4")` +
|
|
`systemctl is-active`/`is-enabled`. Zeigt Version, Lauf- und
|
|
Autostart-Status.
|
|
- **Installation & Dienststeuerung**: eigene, jeweils einzeln bestätigte
|
|
Buttons — „kea-dhcp4-server installieren“ (`apt-get install -y`),
|
|
„Aktivieren & (neu) starten“ (`systemctl enable` + `restart`) und
|
|
„Stoppen“ (`systemctl stop` **+ `disable`**, damit ein bewusst gestoppter
|
|
Dienst nach einem Host-Neustart nicht trotzdem automatisch wieder
|
|
hochfährt — ein Host-Neustart übernimmt so genau den zuletzt bewusst
|
|
gewählten Zustand, an oder aus). Bewusst **nicht** automatisch an
|
|
„Konfiguration speichern“ oder „In Datei schreiben“ gekoppelt — ein
|
|
unerwartet aktiver oder fehlkonfigurierter DHCP-Server kann ein ganzes
|
|
Netzsegment stören, jede dieser Aktionen soll ein bewusster, separater
|
|
Klick bleiben.
|
|
- **Mehrere Subnetze gleichzeitig**: ein Host kann mehrere IPs/Interfaces
|
|
mit jeweils eigenem Netz haben, für die alle DHCP angeboten werden soll
|
|
(`dhcp_subnets`-Tabelle statt einer einzelnen globalen Range) — jedes
|
|
Subnetz hat eigene Interface/Range sowie optional eigenes Gateway/DNS,
|
|
generiert wird ein eigener `subnet4`-Block je Subnetz in der Kea-Config.
|
|
Domain, Lease-Zeiten und Ausgabepfad bleiben global (Kea-weit gültig).
|
|
- **Netzwerk-Kopplung**: Subnet und Netzmaske werden **nie manuell
|
|
eingegeben**, sondern bei jeder Anzeige/Generierung live aus der
|
|
System-Netzwerkkonfiguration des jeweiligen Interfaces gelesen
|
|
(`_detect_interface_network()`/`_detect_interface_networks()`:
|
|
`ip -4 addr show dev <iface>` + `ip route show default`) — berücksichtigt
|
|
dabei ALLE IPv4-Adressen eines Interfaces, nicht nur die erste (ein
|
|
Interface kann mehrere IPs/Subnetze gleichzeitig tragen, z.B. Alias-IPs).
|
|
Die generierte Kea-Konfiguration ist dadurch immer an das Netz gekoppelt,
|
|
in dem der Host tatsächlich hängt, auch wenn sich dessen IP/Subnet mal
|
|
ändert.
|
|
- **Range ist Pflicht und muss zu einem echten Netz passen**: kein
|
|
vorausgefüllter Default für Range/DNS (nur Platzhaltertext) — ein
|
|
Subnetz ohne zu einem tatsächlich vorhandenen Netz passende Range wird
|
|
beim Anlegen/Bearbeiten abgelehnt (`_dhcp_matching_network()`), da Kea
|
|
ohne eine echte, physisch vorhandene IP im gewünschten Bereich keine
|
|
gültige Subnet-CIDR zugeordnet werden kann. Dieselbe Prüfung läuft
|
|
zusätzlich bei „In Datei schreiben“ (Subnetze, die inzwischen zu keinem
|
|
echten Netz mehr passen — z.B. nach einem Netzwechsel des Hosts — werden
|
|
übersprungen und in der Erfolgsmeldung benannt, statt die ganze Aktion
|
|
abzubrechen) und bei „Aktivieren & (neu) starten“ (verweigert den Start,
|
|
falls kein einziges gültiges Subnetz mehr existiert). Live auf einer
|
|
echten Fehlkonfiguration reproduziert und verifiziert.
|
|
- **Subnetze einzeln deaktivierbar**: ein Subnetz lässt sich ohne Löschen
|
|
pausieren (`enabled`-Flag) — wird dann bei „In Datei schreiben“ und
|
|
„Aktivieren & (neu) starten“ komplett ignoriert (kein Fehler, bewusst
|
|
kein "ungültig", da das Fehlen des Netzes hier Absicht ist), statt es
|
|
jedes Mal neu anlegen zu müssen.
|
|
- **DHCP-Options** (`dhcp_option_defs`/`dhcp_option_values`): eine kuratierte
|
|
Auswahl an **57 Standard-Optionen** (analog den „Vordefinierten Optionen“
|
|
eines Windows-DHCP-Servers — u.a. Hostname erzwingen, NTP-/WINS-/TFTP-/
|
|
SMTP-Server, Boot-Datei, Domain-Search, IP-Forwarding) ist automatisch
|
|
vorbefüllt und **nicht löschbar** (Backend lehnt es ab, UI zeigt statt
|
|
eines Löschen-Buttons ein Schloss-Symbol) — Router/DNS-Server/Domain-Name/
|
|
Lease-Zeiten sind bewusst ausgenommen, da dafür bereits eigene, dedizierte
|
|
Felder existieren (Subnetze bzw. globale Einstellungen oben); ebenso
|
|
client-/protokollinterne Optionen (message-type, parameter-request-list,
|
|
requested-address, ...), die serverseitig nicht sinnvoll setzbar sind.
|
|
Alle 57 Namen sind live gegen eine echte Kea-2.4.1-Instanz verifiziert
|
|
(`kea-dhcp4 -t`, jede Option einzeln getestet — u.a. „host-name“ mit
|
|
Bindestrich statt „hostname“ als Kea-Name richtiggestellt). Standard-
|
|
Optionen bekommen bewusst **kein eigenes `option-def`** in der generierten
|
|
Konfiguration — Kea kennt sie bereits nativ, eine Neudefinition würde die
|
|
eingebaute duplizieren; nur zusätzlich angelegte, wirklich eigene/
|
|
herstellerspezifische Options (z.B. eine Terminal-Boot-URL) bekommen eines
|
|
und bleiben frei löschbar.
|
|
In der Tabelle sind grundsätzlich nur **tatsächlich genutzte** Options
|
|
sichtbar (eigene immer, Standard-Optionen nur mit gesetztem globalen Wert)
|
|
— weitere Standard-Optionen kommen über ein Dropdown „+ Standard-Option
|
|
hinzufügen“ dazu, statt alle 57 dauerhaft als leere Zeilen anzuzeigen.
|
|
Jede Option hat einen **globalen** Wert sowie optional einen **Wert pro
|
|
Client** — ein Client-Override überschreibt den globalen Wert
|
|
ausschließlich für dieses eine Gerät (technisch: globale Werte landen im
|
|
Top-Level `option-data`, Overrides im `option-data` der jeweiligen
|
|
Kea-Reservierung, was Kea automatisch pro Client Vorrang geben lässt). Im
|
|
Reservierungs-Options-Dialog gilt dasselbe Prinzip: nur Options mit
|
|
gesetztem Override sind sichtbar, weitere kommen über ein Dropdown dazu
|
|
(das neu eingeblendete Feld wird automatisch in den sichtbaren Bereich
|
|
gescrollt und fokussiert).
|
|
- **Reservierungen aus zwei Quellen**: automatisch für jedes aktive Gerät mit
|
|
gültiger MAC + IP (Client-Stammdaten dieser App) sowie zusätzlich **manuell
|
|
anlegbar** („Reservierung hinzufügen“, MAC/IP/Name) — für Geräte, die
|
|
nicht als Client gepflegt werden (z.B. ein externes Gerät), sodass ihnen
|
|
bewusst und mit voller Kontrolle eine feste IP gegeben werden kann, statt
|
|
sie unüberwacht automatisch anzubinden. Automatische Reservierungen können
|
|
in dieser Tabelle **nicht gelöscht** werden (Schloss-Symbol statt Button —
|
|
sie entstehen/verschwinden mit den Client-Stammdaten), manuelle schon. Bei
|
|
einer MAC in beiden Quellen gewinnt immer die automatische. Jede
|
|
Reservierung wird ins **passende Subnetz** einsortiert (die IP entscheidet,
|
|
zu welchem der ggf. mehreren konfigurierten Subnetze sie gehört); der
|
|
Hostname wird aus dem Namen abgeleitet (nur `a-z0-9-`, Kollisionen
|
|
innerhalb desselben Subnetzes bekommen automatisch ein `-2`/`-3`-Suffix).
|
|
Einträge ohne MAC/IP oder mit einer IP außerhalb aller konfigurierten
|
|
Subnetze werden mit Hinweis übersprungen — Kea lehnt eine Reservierung
|
|
außerhalb ihres Subnets als Konfigurationsfehler ab (mit einer echten
|
|
Kea-Instanz verifiziert, inkl. einer Mischung aus automatischer und
|
|
manueller Reservierung im selben Subnetz).
|
|
- **Aktive Leases**: eigene Karte, liest die tatsächlich vergebenen Adressen
|
|
direkt aus Keas Lease-Datenbank (`kea-leases4.csv`, memfile-Backend —
|
|
kein Control-Agent nötig, reiner Lesezugriff auf die Datei). Zeigt damit
|
|
auch Clients **ohne eigene Reservierung**, die sich einfach eine freie IP
|
|
aus dem Pool genommen haben — deutlich als „Ohne Reservierung“ markiert,
|
|
statt nur die (unvollständige) Reservierungsliste zu zeigen. Die
|
|
Ablaufzeit wird explizit als **UTC** ausgewiesen (Kea arbeitet intern in
|
|
UTC-Epoch) und zusätzlich als live tickender Countdown angezeigt — eine
|
|
reine Absolutzeit auf einer nicht selbst aktualisierenden Seite wirkte bei
|
|
den kurzen Standard-Lease-Zeiten (600s) schnell „schon abgelaufen“, sobald
|
|
etwas Zeit vergangen war, bis man tatsächlich hinschaut (live auf der
|
|
Test-VM als genau dieses Missverständnis reproduziert).
|
|
- **Schreiben**: „Speichern“ bei den Reservierungen (nur mit
|
|
`settings_dhcp.edit`) schreibt die vollständige, generierte Kea-JSON-
|
|
Konfiguration an den konfigurierten Ausgabepfad. Wirksam wird sie erst
|
|
nach einem Dienst-Neustart über den separaten Button.
|
|
- **Ampel im Topbar**: neben dem Prüfintervall-Timer zeigt ein grüner/roter
|
|
Punkt, ob der Kea-Dienst läuft — nur sichtbar mit `settings_dhcp.view`.
|
|
- Reservierungen mit aktiven eigenen Options zeigen in der Tabelle, welche
|
|
Option greift (global oder Client-Override).
|
|
|
|
Live gegen eine echte, frisch installierte Kea-Instanz verifiziert:
|
|
Installation, generierte Konfiguration besteht `kea-dhcp4 -t`, Dienststart
|
|
übernimmt sie fehlerfrei (`DHCP4_CONFIG_COMPLETE`), globaler Options-Wert
|
|
sowie Client-spezifischer Override erscheinen korrekt getrennt in der
|
|
Konfiguration.
|
|
|
|
Die Mehrfach-Subnetz-Unterstützung selbst (Anlegen/Bearbeiten/Löschen samt
|
|
Validierung, mehrere generierte `subnet4`-Blöcke mit korrekten Pools/
|
|
Interfaces, Migration einer bestehenden Einzel-Range) ist live auf einem
|
|
echten Host verifiziert. Zwei tatsächlich **unabhängige** Netze (z.B. über
|
|
zwei physische NICs) standen beim Test nicht zur Verfügung — verifiziert
|
|
wurde daher zusätzlich zwei Ranges innerhalb desselben real vorhandenen
|
|
Netzes (identischer `subnet`-CIDR, unterschiedliche Pools); ob Kea zwei
|
|
`subnet4`-Blöcke mit identischem `subnet`-Wert akzeptiert oder als Fehler
|
|
ablehnt, wurde nicht gegen eine echte Kea-Instanz geprüft — bei tatsächlich
|
|
unterschiedlichen Netzen (der eigentliche Anwendungsfall) besteht dieses
|
|
Risiko nicht. Die Leases-Anzeige wurde vollständig End-to-End im echten
|
|
Betrieb bestätigt: ein tatsächlicher, unreservierter Client im Testnetz
|
|
(„shellyhtg3-...“) hat sich selbstständig eine IP aus dem Pool geholt und
|
|
wurde korrekt mit der „Ohne Reservierung“-Markierung angezeigt.
|
|
|
|
## Netzwerkeinstellungen des Hosts (Systemeinstellungen)
|
|
|
|
Eigene, klar getrennte Funktion von obigem DHCP-*Server*: hier geht es um
|
|
die Netzwerkkonfiguration des Hosts, auf dem der PoE Manager selbst läuft
|
|
(IP-Adresse, DNS-Server, DHCP-Client vs. statisch, Hostname) — nicht um
|
|
Adressen, die er an andere Geräte vergibt. Der Hostname wird separat und
|
|
risikolos über `hostnamectl set-hostname` gesetzt (kein Revert-Timer nötig,
|
|
da eine Änderung nicht die Erreichbarkeit kappt).
|
|
|
|
- **Backend-Erkennung**: prüft, ob NetworkManager oder dhcpcd aktiv ist
|
|
(`systemctl is-active`); ist keins von beiden aktiv, aber `systemd-networkd`
|
|
aktiv und `netplan` installiert, wird **netplan** angenommen — der Standard
|
|
auf einem frisch installierten Ubuntu (Server wie Cloud-Image). Ist keins
|
|
der drei erkennbar, bleibt die Seite bewusst **rein lesend** (Status wird
|
|
trotzdem angezeigt) — ohne zuverlässige Erkennung des Backends keine
|
|
Änderung, um nicht ins Blaue zu raten.
|
|
- **Anzeige**: aktuelles Interface, IP/Prefix, Gateway, DNS-Server sowie
|
|
Modus (DHCP/Statisch) — Modus wird backend-spezifisch ermittelt
|
|
(`nmcli ipv4.method`, ein `static ip_address=`-Eintrag im betreffenden
|
|
`interface`-Block von `/etc/dhcpcd.conf`, bzw. bei netplan am `dynamic`-Flag
|
|
des Kernels auf der aktuellen Adresse — zuverlässiger als die u.U. mehreren
|
|
überlagernden YAML-Dateien unter `/etc/netplan/` selbst zu parsen).
|
|
- **Änderung**: Interface, Modus (DHCP/Statisch), bei Statisch zusätzlich
|
|
IP/Prefix/Gateway, sowie unabhängig davon eigene DNS-Server (funktioniert
|
|
in beiden Modi — z.B. IP per DHCP, aber feste DNS-Server). Bei netplan
|
|
landet die Änderung in einer eigenen, niedrig priorisierten Override-Datei
|
|
(`/etc/netplan/90-poe-manager.yaml`) statt in der vom Distributor bzw.
|
|
cloud-init mitgelieferten — netplan wendet Dateien alphabetisch an, spätere
|
|
Werte gewinnen pro Schlüssel, damit bleibt die Original-Datei unangetastet.
|
|
- **Sicherheitsnetz** (wie `netplan try`): vor jeder Änderung wird die
|
|
vorherige Konfiguration gesichert. Nach dem Anwenden läuft ein
|
|
Hintergrund-Timer (Standard 45s) — wird die Änderung nicht **explizit
|
|
bestätigt** (nur möglich, wenn die Seite über die neue Konfiguration noch
|
|
erreichbar ist), rollt die App automatisch auf die gesicherte
|
|
Konfiguration zurück. Verhindert, dass ein Tippfehler bei IP/Gateway den
|
|
Host von der Web-UI/SSH abschneidet.
|
|
- **DHCP-Server wird vorsorglich gestoppt UND deaktiviert**: eine vorher
|
|
passende Range (siehe DHCP-Konfiguration oben) kann nach einer
|
|
IP-/Subnetzänderung plötzlich zum falschen Netz gehören. Läuft Kea beim
|
|
Anwenden oder beim Auto-Rollback, wird der Dienst deshalb gestoppt und
|
|
deaktiviert (nicht automatisch neu gestartet — die Range muss der Admin
|
|
aktiv auf der DHCP-Seite prüfen und den Dienst dort bewusst wieder
|
|
starten). Das zusätzliche Deaktivieren verhindert, dass ein Host-Neustart
|
|
vor dieser Prüfung den Dienst trotzdem automatisch mit der ggf. falschen
|
|
Range wieder hochfährt, statt dass die App mit einer möglicherweise
|
|
falschen Konfiguration weiterläuft oder blind rät.
|
|
- Live gegen eine echte Ubuntu-24.04-VM verifiziert (Standard-Installation,
|
|
Netz per DHCP über netplan/systemd-networkd bezogen) — sowohl die
|
|
Erkennung/Statusanzeige als auch der komplette Anwenden-Pfad inkl. der
|
|
eigenen Override-Datei. NetworkManager und dhcpcd sind zusätzlich per
|
|
gemockten `subprocess.run`/Dateizugriffen verifiziert (inkl. eines echten
|
|
`dhcpcd.conf`-Rewrites und eines vollständigen Anwenden-dann-Auto-
|
|
Rollback-Durchlaufs), da in der WSL-Entwicklungsumgebung keins von beiden
|
|
verfügbar ist.
|
|
|
|
## Änderungslog
|
|
|
|
Jede Anlage, Bearbeitung, Löschung sowie jedes Aktivieren/Deaktivieren von
|
|
Geräten, Switchen, Zugangsdaten, Benutzern und Gruppen wird in der Tabelle
|
|
`audit_log` protokolliert (Zeitpunkt, Benutzer, Aktion, Ziel, Details) —
|
|
einsehbar unter **Logs → Änderungen** (Recht `logs_activity.view`). Zusätzlich merken
|
|
sich Geräte und Switche direkt am Datensatz (`last_modified_by`,
|
|
`last_modified_at`), wer sie zuletzt geändert hat, damit man das nicht erst
|
|
im Log nachschlagen muss.
|
|
|
|
PoE-Neustarts werden **bewusst nicht** im Änderungslog erfasst — die stehen
|
|
bereits im Live-Log von `poe.sh`. Eine Ausnahme ist die Änderung des
|
|
Prüfintervalls selbst (eine Einstellungsänderung, kein Neustart), die wird
|
|
mitprotokolliert.
|
|
|
|
## Import/Export
|
|
|
|
Unter **Einstellungen** lassen sich Geräte, Switche und Zugangsdaten
|
|
(inkl. entschlüsselter Passwörter) als ein einziges JSON-Bundle exportieren.
|
|
Das Bundle wird mit einem aus einer selbstgewählten Passphrase abgeleiteten
|
|
Schlüssel verschlüsselt (PBKDF2-HMAC-SHA256 + Fernet) — unabhängig vom
|
|
`fernet.key` dieser Installation, damit die Datei auf einer komplett neuen
|
|
Umgebung (mit eigenem, neu generiertem `fernet.key`) wieder eingelesen
|
|
werden kann. Gedacht für einen Umzug auf einen neuen Server.
|
|
|
|
Beim Import wird dieselbe Passphrase erneut abgefragt; Zugangsdaten werden
|
|
nach Name, Switche nach Hostname und Geräte nach MAC-Adresse abgeglichen —
|
|
bestehende Einträge mit gleichem Schlüssel werden aktualisiert, neue werden
|
|
angelegt. Switche referenzieren ihre Zugangsdaten dabei über den Namen (nicht
|
|
die interne ID), damit der Import auch bei abweichender ID-Vergabe auf dem
|
|
Zielsystem korrekt verknüpft.
|
|
|
|
## Eigenes Konto & Profilbild
|
|
|
|
Das Zahnrad-Symbol neben dem eigenen Namen unten in der Sidebar führt zu
|
|
**„Mein Konto“** (`/account`): Vor-/Nachname ändern, ein Profilbild
|
|
hochladen (PNG/JPG/GIF/WEBP) und das eigene Passwort ändern (erfordert
|
|
Eingabe des aktuellen Passworts). Das ist bewusst getrennt vom Admin-Bereich
|
|
„Benutzer“, der andere Konten verwaltet. Ist ein Profilbild hinterlegt,
|
|
erscheint es statt der Initialen sowohl in der Sidebar als auch im
|
|
Änderungslog neben dem Benutzernamen. Admins sehen auf derselben Seite
|
|
zusätzlich die Navbar-Reihenfolge (siehe unten).
|
|
|
|
## Navigation anpassen
|
|
|
|
Die Sidebar ist in drei aufklappbare Gruppen strukturiert:
|
|
|
|
- **Geräte** — Clients (die eigentlichen Devices), Switche, Zugangsdaten
|
|
- **Einstellungen** — Benutzer, Gruppen, Systemeinstellungen (Prüfintervall),
|
|
Im-/Export
|
|
- **Logs** — Live, Änderungen (Änderungslog)
|
|
|
|
Die Reihenfolge dieser drei Gruppen (und von „Dashboard“) ist für Admins
|
|
unter **Mein Konto** (Zahnrad-Symbol in der Sidebar) per Auf-/Ab-Buttons
|
|
konfigurierbar (gespeichert als JSON-Liste unter `settings.nav_order`) und
|
|
gilt global für alle Benutzer. Unabhängig von der Reihenfolge sieht jeder
|
|
Benutzer ohnehin nur, wofür er berechtigt ist — sowohl auf Gruppenebene als
|
|
auch pro Unterpunkt: hat ein Benutzer z.B. nur `devices.view`, erscheint die
|
|
Gruppe „Geräte“ nur mit dem Unterpunkt „Clients“ (ohne Switche/
|
|
Zugangsdaten); eine Gruppe verschwindet komplett, wenn kein Unterpunkt
|
|
sichtbar ist.
|
|
|
|
## Entwicklung unter WSL
|
|
|
|
Da das Projekt ausschließlich für Linux gebaut ist, empfiehlt sich die
|
|
Entwicklung direkt unter WSL2 (Ubuntu), auch wenn der Editor unter Windows
|
|
läuft — das Projektverzeichnis liegt dabei ganz normal unter
|
|
`C:\...\aruba-poe-modern` und wird aus WSL über `/mnt/c/...` erreicht:
|
|
|
|
```bash
|
|
wsl --install -d Ubuntu # einmalig, falls noch nicht vorhanden
|
|
wsl -d Ubuntu
|
|
sudo apt update && sudo apt install -y python3 python3-venv python3-pip sqlite3 expect openssh-client
|
|
cd /mnt/c/Users/<dich>/aruba-poe-modern/srv/poe_manager
|
|
python3 -m venv venv
|
|
./venv/bin/pip install -r requirements.txt
|
|
./venv/bin/python create_db.py
|
|
./venv/bin/python create_admin.py
|
|
./venv/bin/python app.py # http://localhost:5000 — via WSL2-Portweiterleitung
|
|
# auch aus dem Windows-Browser erreichbar
|
|
```
|
|
|
|
**Hinweis zu `rpi-check.service`:** Der „Speichern & Service neustarten“-Button
|
|
unter Systemeinstellungen sowie das „Jetzt prüfen“-Icon funktionieren nur,
|
|
wenn `rpi-check.service` tatsächlich als echter systemd-Service läuft (viele
|
|
aktuelle WSL2-Installationen unterstützen systemd, siehe `wsl.conf`
|
|
`[boot] systemd=true`). Für lokale Tests reicht es, `etc/systemd/system/
|
|
rpi-check.service` sowie `usr/local/bin/custom/poe.sh` per Symlink an ihre
|
|
Produktivpfade (`/etc/systemd/system/`, `/usr/local/bin/custom/`) zu legen
|
|
und `/srv/poe_manager` auf den Checkout zu verlinken, dann `systemctl
|
|
daemon-reload && systemctl enable --now rpi-check.service`. Ohne systemd
|
|
(z.B. `systemctl` nicht vorhanden) scheitert der Neustart-Aufruf lautlos —
|
|
das Intervall in der DB wird trotzdem aktualisiert, greift dann aber erst
|
|
nach einem manuellen Neustart des Prozesses.
|
|
|
|
## Lokal starten (Entwicklung)
|
|
|
|
```bash
|
|
cd srv/poe_manager
|
|
python3 -m venv venv
|
|
source venv/bin/activate
|
|
pip install -r requirements.txt
|
|
|
|
python create_db.py # legt sqlite.db + Tabellen an
|
|
python create_admin.py # legt ersten Admin-Benutzer an
|
|
|
|
python app.py # http://localhost:5000
|
|
```
|
|
|
|
## Produktiv-Deployment (auf der Ziel-VM, App landet unter `/srv/poe_manager`)
|
|
|
|
Das Repo wird bewusst **nicht** direkt nach `/srv/poe_manager` geklont —
|
|
`install.sh` kopiert (`rsync`) den Inhalt von `srv/poe_manager/` aus dem Repo
|
|
gezielt dorthin und lässt Quell-Checkout und Zielverzeichnis damit sauber
|
|
getrennt (kein doppeltes `/srv/poe_manager/srv/poe_manager/…`):
|
|
|
|
```bash
|
|
sudo git clone <dieses-repo> /opt/aruba-poe-modern-src
|
|
cd /opt/aruba-poe-modern-src
|
|
sudo bash install.sh
|
|
sudo /srv/poe_manager/venv/bin/python3 /srv/poe_manager/create_admin.py
|
|
```
|
|
|
|
Nach der Installation liegt die laufende App vollständig unter
|
|
**`/srv/poe_manager`** (so wie es `poe_web.service`, `rpi-check.service` und
|
|
`POE_SCRIPT`/`POE_DB_PATH` als Default erwarten) — `/opt/aruba-poe-modern-src`
|
|
wird nur als Checkout-Quelle für `install.sh` gebraucht und kann danach
|
|
liegen bleiben (für spätere Updates: `git pull` dort, dann `install.sh`
|
|
erneut ausführen) oder gelöscht werden.
|
|
|
|
`install.sh` installiert Systempakete, richtet die venv ein, initialisiert die
|
|
Datenbank (falls nicht vorhanden), kopiert `poe.sh` nach
|
|
`/usr/local/bin/custom/`, registriert die systemd-Units
|
|
(`poe_web.service`, `rpi-check.service`, `rpi-check-restart.timer`) und
|
|
konfiguriert nginx als Reverse-Proxy auf Port 80.
|
|
|
|
### Relevante Umgebungsvariablen (optional)
|
|
|
|
| Variable | Zweck | Default |
|
|
|-----------------------|------------------------------------------|---------------------------------------|
|
|
| `POE_DB_PATH` | Pfad zur SQLite-DB | `<app-dir>/sqlite.db` |
|
|
| `POE_SCRIPT` | Pfad zum PoE-Restart-Skript | `/usr/local/bin/custom/poe.sh` |
|
|
| `POE_LOG_GLOB` | Glob-Pattern der Check-Logs | `/var/log/rpi-*.log` |
|
|
| `POE_FERNET_KEY` | Pfad zum Fernet-Schlüssel | `<app-dir>/fernet.key` (auto-erzeugt)|
|
|
| `POE_KNOWN_HOSTS` | Pfad zur SSH-known_hosts-Datei des Terminals| `<app-dir>/known_hosts` (auto-erzeugt)|
|
|
| `POE_SECRET_KEY` | Flask Secret Key (überschreibt Datei) | zufällig, in `secret.key` gespeichert|
|
|
| `PORT`, `FLASK_DEBUG` | Flask-Serverport / Debug-Modus | `5000` / aus |
|
|
|
|
## Browser-SSH-Terminal (Switch-Verbindungstest)
|
|
|
|
„Verbindung testen“ im Switch-Modal öffnet eine WebSocket-Verbindung zu
|
|
`/ws/ssh_terminal`. Serverseitig baut **paramiko** eine echte SSH-Sitzung
|
|
zum Switch auf (inkl. interaktiver Host-Key-Bestätigung beim Erstkontakt,
|
|
danach dauerhaft in `known_hosts` gemerkt) und reicht eine interaktive Shell
|
|
1:1 an ein xterm.js-Terminal im Browser durch. Die Zugangsdaten aus dem
|
|
Formular werden direkt für die SSH-Authentifizierung verwendet (nicht als
|
|
Tastatureingabe in die Shell getippt) — Erfolg/Fehlschlag der Anmeldung wird
|
|
sofort und eindeutig im Terminal angezeigt. Ein Klick auf „Passwort
|
|
einfügen“ sendet den aktuell im Formular eingetragenen Wert zusätzlich als
|
|
Tastatureingabe (z.B. für ein `sudo`-Passwort in der geöffneten Sitzung).
|
|
|
|
Voraussetzungen:
|
|
- Läuft auf **jedem Betriebssystem** (paramiko ist reines Python) — die
|
|
SSH-Verbindung wird dabei immer vom PoE-Server aus aufgebaut, nie vom
|
|
Browser/Client.
|
|
- Nur für eingeloggte **Admins** erreichbar.
|
|
- Der Flask-Entwicklungsserver muss mit `threaded=True` laufen (ist bereits
|
|
so konfiguriert) — für einen echten Produktivbetrieb empfiehlt sich
|
|
ohnehin ein WSGI-Server mit WebSocket-Unterstützung (z.B. Gunicorn mit
|
|
`gevent`- oder `eventlet`-Worker) statt des eingebauten Dev-Servers.
|
|
- **nginx muss den WebSocket-Upgrade für `/ws/` durchreichen** (`Upgrade`/
|
|
`Connection`-Header, siehe `etc/nginx/sites-available/poe_manager`) — ohne
|
|
das lehnt Flask den Handshake mit `400 Bad Request` ab und das Terminal
|
|
bleibt leer auf „Getrennt“ hängen, obwohl derselbe Aufruf direkt gegen
|
|
Port 5000 (an nginx vorbei) funktioniert. War auf einer frisch per
|
|
`install.sh` aufgesetzten Ubuntu-VM live reproduzierbar, da alle bisherigen
|
|
Terminal-Tests ausschließlich direkt gegen Flask liefen, nie durch nginx.
|
|
- Da `poe_web.service` (wie im Original) als `root` läuft, kann über dieses
|
|
Terminal im Prinzip jeder erreichbare Host per SSH kontaktiert werden —
|
|
bewusst so gewählt, da Admins über die App ohnehin schon vollen Zugriff auf
|
|
alle hinterlegten Switch-Zugangsdaten haben. Für eine strengere Trennung
|
|
empfiehlt es sich, `poe_web.service` künftig unter einem eigenen,
|
|
unprivilegierten Systembenutzer laufen zu lassen (im Original wie auch hier
|
|
aktuell `root`, um Änderungen am produktiven Setup nicht zu vergrößern).
|
|
|
|
## Projektstruktur
|
|
|
|
```
|
|
srv/poe_manager/ Flask-App (Backend + Templates + Static-Assets)
|
|
usr/local/bin/custom/ poe.sh — Ping-Check & PoE-Restart per SSH (expect)
|
|
etc/systemd/system/ Service-/Timer-Units (Web-App + Check-Dienst)
|
|
etc/nginx/ Reverse-Proxy-Konfiguration
|
|
install.sh Produktiv-Installer
|
|
```
|