From 3bef45a8d44fc637e1d0396bac285b4caaab189c Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 24 Dec 2025 16:09:22 +0000 Subject: [PATCH] fix: handle DHCP IP changes without creating duplicates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #891 fix - also match by name+tokenID to handle the case where the same physical host gets a new IP (DHCP). This ensures: 1. Same hostname + DIFFERENT token = different physical hosts → create separate nodes 2. Same hostname + SAME token = same host with new IP → update existing node Also updates the host URL when an existing node is matched, so IP changes are properly reflected in the saved configuration. --- internal/api/config_handlers.go | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/internal/api/config_handlers.go b/internal/api/config_handlers.go index 146a40aa9..c7341b206 100644 --- a/internal/api/config_handlers.go +++ b/internal/api/config_handlers.go @@ -5890,9 +5890,10 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque } // Check if a node with this host already exists - // IMPORTANT: Only match by Host URL, NOT by name! - // Different physical hosts can have the same hostname (e.g., "px1" on different networks). - // Matching by name caused duplicate hostnames to be collapsed into one entry. + // IMPORTANT: Match by Host URL primarily. + // Also match by name+tokenID for DHCP scenarios where IP changed but it's the same host. + // Different physical hosts can have the same hostname (e.g., "px1" on different networks) + // but they'll have different tokens, so we only merge if BOTH name AND token match. // See: Issue #891, #104, and multiple fix attempts in Dec 2025. existingIndex := -1 if req.Type == "pve" { @@ -5901,6 +5902,18 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque existingIndex = i break } + // DHCP case: same hostname AND same token = same physical host with new IP + // This allows IP changes to update existing nodes without creating duplicates + if req.ServerName != "" && strings.EqualFold(node.Name, req.ServerName) && node.TokenName == req.TokenID { + existingIndex = i + // Update the host to the new IP + log.Info(). + Str("oldHost", node.Host). + Str("newHost", host). + Str("node", req.ServerName). + Msg("Detected IP change for existing node - updating host") + break + } } } else { for i, node := range h.config.PBSInstances { @@ -5908,6 +5921,16 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque existingIndex = i break } + // DHCP case: same hostname AND same token = same physical host with new IP + if req.ServerName != "" && strings.EqualFold(node.Name, req.ServerName) && node.TokenName == req.TokenID { + existingIndex = i + log.Info(). + Str("oldHost", node.Host). + Str("newHost", host). + Str("node", req.ServerName). + Msg("Detected IP change for existing node - updating host") + break + } } } @@ -5916,6 +5939,8 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque // Update existing node if req.Type == "pve" { instance := &h.config.PVEInstances[existingIndex] + // Update host in case IP changed (DHCP scenario) + instance.Host = host // Clear password auth when switching to token auth instance.User = "" instance.Password = "" @@ -5949,6 +5974,8 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque // Keep other settings as they were } else { instance := &h.config.PBSInstances[existingIndex] + // Update host in case IP changed (DHCP scenario) + instance.Host = host // Clear password auth when switching to token auth instance.User = "" instance.Password = ""