← Blog

Überwachung und sichere Steuerung einer Flotte von DC-Stromversorgungssystemen über SNMP

DEENESRUUK

Jede Telekommunikationsstelle wird mit Gleichstrom betrieben. Hinter den Radios und Routern befindet sich ein Rektifikator-Schrank – ein Eltek-Anlage, das Wechselstrom in sauberen −48 V umwandelt und eine Batteriegruppe auflädt, die die Anlage bei einem Ausfall versorgen muss. Wenn eine dieser Anlagen Fehlfunktionen zeigt, will man es wissen, bevor die Batterie es tut. Das ist das System, das ich gebaut habe, um eine ganze Flotte zu überwachen – und irgendwann, um sie zu steuern.

Von einem Report-Skript zu einem Live-System

Das Tooling, das es ersetzte, war ein einzelnes Skript, das ein paar statische HTML-Berichte erzeugte – die Geschichte von gestern, eingefroren. Ich wollte den Live-Status, eine Historie dessen, was geändert wurde, und der Teil, der ein Dashboard zu einem Werkzeug macht: die Möglichkeit, einen Controller ohne manuelles Anmelden zu steuern.

Die Flotte ist nicht homogen. Zwei Controller-Familien (das klassische Smartpack-1 und das neuere Smartpack-R / eNexus), unterschiedliche MIBs, unterschiedliche Eigenheiten. Daher musste der Kern geräteunabhängig sein und es einem Bediener ermöglichen, einen neuen Controller ohne Codeänderung beizubringen.

Entdeckung → Klassifizierung → Abfrage (Poll)

Drei geplante Module speisen alles:

  • Discovery zieht die Host-Liste aus Zabbix (das Netzwerk ist dort bereits inventarisiert) und speichert sie zwischen.
  • Classify sondiert jeden Host: es führt ein SNMP-get für eine Identitäts-OID für jedes bekannte Controller-Profil durch, und das erste Profil, das antwortet, gewinnt – dieser Host ist nun ein bekannter Stromversorgungssystem dieser Familie. Hosts, die nichts antworten, landen in einem Unbekannt-Korb.
  • Poll führt alle 15 Minuten SNMP-Walks durch jedes klassifizierte System, verwendet dabei die exakten skalaren OIDs und Tabellenspalten, die in seinem Profil definiert sind, und rendert das Dashboard.

Was dieses System erweiterbar macht, ist, dass Classify und Poll profilgesteuert sind. Ein Profil ist lediglich ein OID-Wörterbuch – eine Identitäts-OID, skalare OIDs (Eingangsspannung, Temperatur, Float/Boost-Sollwerte…) und Tabellenspalten (eine Zeile pro Rektifikator-Slot). Sie leben in der Datenbank und werden in der UI bearbeitet. Ein neuer Hersteller – sagen wir ein Huawei-Anlage – wird hinzugefügt, indem man ein Profil definiert, nicht Code hochlädt. Man erstellt es anhand eines Mustergeräts mit einem Probe-Button, der Live snmpgets ausführt und genau zeigt, was zurückkommt, und fördert dann einen passenden Host zu einem Live-System.

Inventar, das keinen falschen Alarm schlägt

Das Polling erzeugt zwei Dinge: Live-Metriken und ein Komponenteninventar – jedes Rektifikator-Modul und jede Steuereinheit, nach Seriennummer, Slot, Hardware- und Firmware-Revision. Vergleicht man zwei aufeinanderfolgende Polls, erhält man installed / removed / changed-Ereignisse, die jeweils per E-Mail an den Verantwortlichen für diesen Standort gesendet werden.

Der schwierigste Teil des Inventarvergleichs ist nicht der Vergleich selbst – es darf nicht lügen. SNMP über ein schwankendes Netzwerk verliert Pakete; ein einzeln fehlender Poll darf niemanden um 3 Uhr morgens wegen eines Rektifikators alarmieren, der nie weg war. Zwei Mechanismen regeln das:

  • Sanity check — wenn ein Skalar "8 Rektifikatoren" angibt, aber die Rektifikator-Tabelle leer zurückkommt, ist das ein teilweiser SNMP-Ausfall, kein Massenentzug. Diese Komponente wird als für diesen Durchlauf nicht vertrauenswürdig markiert und es werden keine removed-Ereignisse ausgelöst.
  • Grace period — eine Komponente muss für drei aufeinanderfolgende Polls (~45 Minuten) fehlen, bevor sie als entfernt gilt. Einzelne Ausfälle bleiben stumm.

Und der erste Poll eines neu hinzugefügten Standorts ist bootstrap-unterdrückt – die Aufnahme von hundert Standorten auf einmal darf nicht die Mailingliste mit hundert „neue Komponente“-E-Mails bombardieren.

Vom Lesen zum Schreiben — SNMP SET mit Schutzmechanismen

Das Überwachen ist die einfache Hälfte. Die interessante Hälfte ist es, einem Bediener zu erlauben, einen Controller zu ändern – Float- und Boostspannung, Ladestrombegrenzung, Alarmgrenzwerte – direkt aus dem Browser über SNMP, ohne sich per SSH in eine laufende Batterieanlage einzuloggen.

Schreiben an Stromversorgungssysteme ist genau dort, wo man Paranoia braucht. Jeder SET durchläuft denselben Zyklus:

edit a parameter
   │
   ├─ validate against the MIB     (type · enum · range → reject out-of-bounds)
   ├─ battery-critical? ───────────→ require an explicit confirm
   ├─ SET
   ├─ read the value BACK          (mismatch = the change FAILED, not succeeded)
   └─ write an audit record        (who · what · old → new) · one-click revert

Der Read-Back ist der tragende Schritt. Eine erfolgreiche SNMP SET Antwort bedeutet nicht, dass der Controller den Wert akzeptiert hat – daher liest das System die OID zurück und meldet die Änderung nur dann als erfolgt, wenn das Gerät nun meldet, was man verlangt hat. Werte außerhalb des Bereichs werden verhindert, bevor sie die App verlassen; die batteriekritischen Werte – die Spannungen, die entscheiden, ob eine Gruppe überhitzt oder unterladen wird – werden ohne ausdrückliche Bestätigung nicht durchgeführt; und jede Änderung kehrt mit einem einzigen Button zu ihrem vorherigen Wert zurück.

Der schreibbare OID Katalog wird aus den Hersteller-MIBs erstellt, nicht von Hand eingegeben. Die MIB kodiert bereits den Typ, Bereich und Zugriff jeder OID, sodass die Sicherheitsregeln aus der Quelle der Wahrheit stammen und nicht aus einer Vermutung.

Der Batterietest

Eine Steuerung verdient einen eigenen Absatz. Ein Batterietest entlädt absichtlich die Gruppe, um ihre tatsächliche Kapazität zu messen – nützlich, und genau das, was man nicht leichtfertig mit bereits schwankendem Netzstrom auslösen möchte. Es ist ein einziger Dashboard-Button, der vor dem Start warnt und dann während des Tests einmal pro Minute den Systemstatus überprüft; wenn der Controller seine minimale Endspannung erreicht (oder einen Alarm auslöst), beendet er den Test von selbst und der Button kehrt von selbst zurück. Die UI rät niemals über den Zustand – sie liest ihn vom Controller ab.

Das Gerät ohne dessen Passwort erreichen

Das letzte Stück verbindet „den Tracker“ mit der „eigenen Web-UI des Controllers“. Jedes Gerät hat eine native Weboberfläche, aber die Verteilung von Geräteseiten funktioniert nicht und auditiert auch nicht. Stattdessen klickt ein authentifizierter Benutzer auf Web UI und landet in der eigenen Oberfläche des Controllers, hinter einem Reverse-Proxy mit demselben Login – der Proxy wird durch die Sitzung des Trackers geschützt und injiziert die gespeicherten Gerätekennungen, sodass der Bediener sie nie sieht. Die Konfiguration des Proxy pro Gerät wird aus dem Inventar generiert, niemals manuell gepflegt: die Flotte ändert sich, die Konfiguration regeneriert, validiert und lädt neu – oder rollt zurück. Gerätegeheimnisse sind im Ruhezustand verschlüsselt; Klartext landet nie in der Datenbank.

Die Form davon

FastAPI + APScheduler, PostgreSQL, SNMP, eine serverseitig gerenderte Jinja UI, alles in Docker. Aber das Framework war nie der Punkt. Der Punkt ist eine Idee, die durchgehend angewendet wird: behandle das Gerät als Quelle der Wahrheit und verifiziere dagegen. Klassifiziere danach, was das Gerät tatsächlich antwortet; erkläre eine Komponente für nicht vorhanden, nur wenn sie wirklich weg ist; melde einen Parameter geändert, nur wenn der Controller ihn zurückliest. Das Monitoring sagt dir, was ist – die interessante Ingenieurskunst besteht darin, etwas damit zu tun, ohne es schlimmer zu machen.

Transparenz: Die meisten Beiträge werden mit KI-Unterstützung verfasst, und die nicht-englischen Versionen werden von einem lokalen LLM maschinell übersetzt und anschließend geprüft. Fehler entdeckt? Bitte gib mir Bescheid.