feat(cluster): Phase 3 Foundation — node.conf + ha_nodes-Drift + UI

Code-Vorbereitung für Multi-Node, ohne dass eine zweite Box nötig ist.
Single-Node-Mode bleibt der Default; alles existiert und wird sichtbar,
sobald ein 2. Knoten joined (Phase 3.2 später).

Migration 0020:
  ha_nodes += version (edgeguard-api-Version)
              config_hash (drift-Detection-Hash)
              mgmt_ip (Management-IP, niemals VIP)
              status (online|offline|joining|leaving|unknown)

internal/cluster/local_config.go:
  /etc/edgeguard/node.conf — INI-style, node-lokale Identität:
  NODE_ID, HOSTNAME, MGMT_IP, ROLE, PEER_HOSTS. NIEMALS zwischen
  Cluster-Peers replizieren. LoadLocalConfig / SaveLocalConfig /
  EnsureLocalConfig (auto-Generierung beim ersten Boot).
  MgmtIP-Default = firstNonLoopbackIPv4(); Operator kann
  überschreiben (mehrere Interfaces).

internal/cluster/store.go:
  - HANode-Model um die 4 neuen Felder erweitert
  - UpsertSelf nimmt jetzt mgmt_ip/version/config_hash/status, COALESCE
    erhält werte wenn der Caller sie nicht setzt
  - EnsureSelfRegistered-Signatur: + role + version-Argument

internal/handlers/cluster.go:
  GET /api/v1/cluster/status — strukturierter Endpoint:
    {local_id, local_node, peers[], mode, health, drift_found, updated_at}
  GET /api/v1/cluster/nodes bleibt für Tools.

UI (pages/Cluster):
  - Header zeigt Mode-Tag (Single-Node / Cluster) + Health-Tag (OK /
    degraded / split-brain)
  - Self-Card: Descriptions mit FQDN, Node-ID, Status, Role, Version,
    MGMT-IP, API-URL, Config-Hash
  - Peers-Tabelle nur wenn vorhanden, mit "drift"-Marker pro Row
  - Drift-Alert-Banner wenn ein Peer einen anderen config_hash hat
  - Single-Node-Mode Hinweis-Alert ("cluster-join kommt in 3.2")

postinst: leeres /etc/edgeguard/node.conf wird angelegt (chown
edgeguard); API auto-befüllt beim ersten boot.

main.go ruft EnsureLocalConfig + EnsureSelfRegistered mit version.

Verifiziert auf der Box (1.0.70):
  - /etc/edgeguard/node.conf hat NODE_ID, HOSTNAME, MGMT_IP=89.163.205.6,
    ROLE=primary
  - ha_nodes-Row: status=online, version=1.0.70, mgmt_ip=89.163.205.6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-13 08:27:00 +02:00
parent df77b814ff
commit ea7c356455
14 changed files with 618 additions and 78 deletions

View File

@@ -267,12 +267,37 @@
},
"cluster": {
"title": "Cluster",
"intro": "{{count}} Node(s) registriert. Multi-Node-Cluster (KeyDB Active-Active + PG Streaming Replication) folgt in einem späteren Release.",
"intro": "{{count}} Node(s) registriert. Multi-Node (KeyDB-AA + PG-Streaming-Replication + Leader-Election) folgt schrittweise.",
"id": "Node-ID",
"fqdn": "FQDN",
"role": "Rolle",
"joinedAt": "Beigetreten",
"self": "diese Node"
"self": "diese Node",
"drift": "Drift",
"modeSingle": "Single-Node",
"modeCluster": "Cluster",
"health": {
"ok": "OK",
"degraded": "degraded",
"split-brain": "split-brain"
},
"selfTitle": "Dieser Knoten",
"noSelf": "Selbst-Registrierung in ha_nodes fehlgeschlagen — Setup-Wizard durchlaufen.",
"peersTitle": "Peers ({{count}})",
"singleNodeTitle": "Single-Node-Modus",
"singleNodeDesc": "Nur diese Box bekannt. Zusätzlicher Knoten? `edgeguard-ctl cluster-join` (kommt in Phase 3.2).",
"driftBanner": "Config-Drift erkannt",
"driftBannerDesc": "Ein oder mehrere Peers haben einen anderen Config-Hash als dieser Node. Entweder stehen noch Änderungen in der Outbox, oder auf einem Peer wurde direkt in der DB editiert. Warte bis die Outbox leer ist oder starte Diagnostics.",
"col": {
"node": "Knoten",
"status": "Status",
"role": "Rolle",
"apiUrl": "API-URL",
"configHash": "Config-Hash",
"version": "Version",
"lastSeen": "Last seen",
"mgmtIp": "MGMT-IP"
}
},
"ssl": {
"title": "SSL-Zertifikate",