feat(cluster): pull-basierte Peer-Registrierung als autoRegister-Fallback

Wenn autoRegister (Push utm-2→utm-1) fehlschlägt, bleibt der Peer
dauerhaft im 'joining'-Status. Neuer Self-Healing-Mechanismus:

- GET /agent/cluster/identity auf dem Agent-Listener: gibt die eigene
  ha_nodes-Row zurück (echte Node-ID, FQDN, Version)
- ClusterHandler.Status() startet für jeden 'joining'/'pending'-Peer
  einen Background-Reconcile via Aggregator: holt Identity, upsertet
  mit echter ID (public_ip aus Placeholder übernommen für nftables),
  löscht Placeholder
- autoRegister-Fehler werden jetzt als Warn-Log sichtbar statt silent
  verworfen

Damit reicht ein Cluster-Page-Aufruf nach Update beider Nodes um den
Status von 'joining' auf 'online' zu bringen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-29 19:06:19 +02:00
parent 6eb6d6d6a4
commit ffb579879d
6 changed files with 113 additions and 7 deletions

View File

@@ -126,14 +126,26 @@ func Join(req Request) error {
// Auto-register: retry a few times because the primary's nftables may
// need a moment to reload even though preRegisterJoiner is now
// synchronous on the primary side.
var autoRegErr error
for i := 0; i < 3; i++ {
if err := autoRegister(primary, tlsDir, req.CommonName, req.Version, req.NodeID); err == nil {
autoRegErr = nil
break
} else if i < 2 {
slog.Warn("clusterjoin: autoRegister failed, retrying", "attempt", i+1, "error", err)
time.Sleep(2 * time.Second)
} else {
autoRegErr = err
if i < 2 {
slog.Warn("clusterjoin: autoRegister failed, retrying", "attempt", i+1, "error", err)
time.Sleep(2 * time.Second)
}
}
}
if autoRegErr != nil {
slog.Warn("clusterjoin: autoRegister failed after all retries — primary will reconcile via identity pull",
"error", autoRegErr)
}
// Certs are saved; primary will reconcile via /agent/cluster/identity pull
// even if autoRegister failed. Not returning the error — join is
// structurally complete (certs issued), only the ha_nodes update is pending.
return nil
}