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:
@@ -60,7 +60,7 @@ import (
|
|||||||
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
|
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.161"
|
var version = "1.1.162"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.161"
|
var version = "1.1.162"
|
||||||
|
|
||||||
const usage = `edgeguard-ctl — EdgeGuard CLI
|
const usage = `edgeguard-ctl — EdgeGuard CLI
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.161"
|
var version = "1.1.162"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// renewTickInterval — how often we re-evaluate expiring certs.
|
// renewTickInterval — how often we re-evaluate expiring certs.
|
||||||
|
|||||||
@@ -532,13 +532,16 @@ func (h *ClusterHandler) reconcileJoiningPeers(placeholders []models.HANode) {
|
|||||||
if n.InternalIP == nil {
|
if n.InternalIP == nil {
|
||||||
n.InternalIP = placeholder.InternalIP
|
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)
|
out, err := h.Store.UpsertSelf(ctx, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Warn("cluster: reconcile joining peer: upsert failed",
|
slog.Warn("cluster: reconcile joining peer: upsert failed",
|
||||||
"fqdn", n.FQDN, "real_id", n.ID, "error", err)
|
"fqdn", n.FQDN, "real_id", n.ID, "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_ = h.Store.DeletePlaceholdersByFQDN(ctx, n.FQDN, n.ID)
|
|
||||||
changed = true
|
changed = true
|
||||||
slog.Info("cluster: joining peer reconciled via identity pull",
|
slog.Info("cluster: joining peer reconciled via identity pull",
|
||||||
"id", out.ID, "fqdn", out.FQDN, "placeholder_id", placeholder.ID)
|
"id", out.ID, "fqdn", out.FQDN, "placeholder_id", placeholder.ID)
|
||||||
@@ -690,16 +693,18 @@ func (h *ClusterHandler) AgentRegisterPeer(c *gin.Context) {
|
|||||||
v := req.Version
|
v := req.Version
|
||||||
n.Version = &v
|
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)
|
out, err := h.Store.UpsertSelf(c.Request.Context(), n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Internal(c, err)
|
response.Internal(c, err)
|
||||||
return
|
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-
|
// Firewall-Reload damit peer_ipv4-Set die neue IP aufnimmt. Best-
|
||||||
// effort: Fehler loggen, Response weiter durchreichen — der Peer
|
// effort: Fehler loggen, Response weiter durchreichen — der Peer
|
||||||
// hat seine Identity erfolgreich registriert, Operator kann manuell
|
// hat seine Identity erfolgreich registriert, Operator kann manuell
|
||||||
|
|||||||
Reference in New Issue
Block a user