fix(cluster): Placeholder zuerst löschen vor UpsertSelf (UNIQUE-fqdn-Bug)
ha_nodes hat UNIQUE(fqdn). UpsertSelf nutzt ON CONFLICT(id) — schlägt bei fqdn-Konflikten fehl. Wenn Placeholder und echter Node die gleiche FQDN haben, schlug der INSERT der echten Row mit "duplicate key on ha_nodes_fqdn_unique" fehl. Root cause für "joining" stuck forever: der Peer blieb ewig als Placeholder weil AgentRegisterPeer + reconcileJoiningPeers die Echte- ID-Row nie erfolgreich einfügen konnten. Fix: DeletePlaceholdersByFQDN vor UpsertSelf in beiden Code-Paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -532,13 +532,16 @@ func (h *ClusterHandler) reconcileJoiningPeers(placeholders []models.HANode) {
|
||||
if n.InternalIP == nil {
|
||||
n.InternalIP = placeholder.InternalIP
|
||||
}
|
||||
// Placeholder zuerst löschen: ha_nodes hat UNIQUE(fqdn). Ohne
|
||||
// dieses Delete würde UpsertSelf (ON CONFLICT(id)) mit fqdn-
|
||||
// unique-Violation scheitern.
|
||||
_ = h.Store.DeletePlaceholdersByFQDN(ctx, n.FQDN, n.ID)
|
||||
out, err := h.Store.UpsertSelf(ctx, n)
|
||||
if err != nil {
|
||||
slog.Warn("cluster: reconcile joining peer: upsert failed",
|
||||
"fqdn", n.FQDN, "real_id", n.ID, "error", err)
|
||||
continue
|
||||
}
|
||||
_ = h.Store.DeletePlaceholdersByFQDN(ctx, n.FQDN, n.ID)
|
||||
changed = true
|
||||
slog.Info("cluster: joining peer reconciled via identity pull",
|
||||
"id", out.ID, "fqdn", out.FQDN, "placeholder_id", placeholder.ID)
|
||||
@@ -690,16 +693,18 @@ func (h *ClusterHandler) AgentRegisterPeer(c *gin.Context) {
|
||||
v := req.Version
|
||||
n.Version = &v
|
||||
}
|
||||
// Placeholder zuerst löschen: ha_nodes hat UNIQUE(fqdn). Der INSERT
|
||||
// in UpsertSelf verwendet ON CONFLICT(id) — greift NICHT bei fqdn-
|
||||
// Konflikten. Ohne das Delete würde der INSERT mit "duplicate key on
|
||||
// ha_nodes_fqdn_unique" scheitern und der Peer bliebe ewig "joining".
|
||||
_ = h.Store.DeletePlaceholdersByFQDN(c.Request.Context(), req.FQDN, req.ID)
|
||||
|
||||
out, err := h.Store.UpsertSelf(c.Request.Context(), n)
|
||||
if err != nil {
|
||||
response.Internal(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Remove ALL placeholder rows for this FQDN (both legacy "pre-{timestamp}"
|
||||
// and current "prenode-{fqdn}" style) — the real row just took their place.
|
||||
_ = h.Store.DeletePlaceholdersByFQDN(c.Request.Context(), req.FQDN, req.ID)
|
||||
|
||||
// Firewall-Reload damit peer_ipv4-Set die neue IP aufnimmt. Best-
|
||||
// effort: Fehler loggen, Response weiter durchreichen — der Peer
|
||||
// hat seine Identity erfolgreich registriert, Operator kann manuell
|
||||
|
||||
Reference in New Issue
Block a user