mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
Adopt the agent's preferred host when re-registering a matched node
The resolved-identity match in canonical auto-register always preserved the stored host, so the route-aware IP preference added to the agent in022f170dfcould never take effect for an already-registered node: a reinstall re-matched the node and kept the stale short-DNS host forever. Preserve the stored host only when it is absent from the agent's ordered candidate list (an admin-managed endpoint the agent cannot see); when the agent itself lists the stored host as a lower-priority candidate, adopt the newly selected host. Identity continuity (same node record, same token) is unchanged. Note: commitc21693489carries this same message by mistake; it actually contains concurrent OIDC/SAML mapping work from a parallel session that was staged when the shared index raced. This commit is the real change.
This commit is contained in:
parent
c21693489a
commit
f850099134
2 changed files with 66 additions and 2 deletions
|
|
@ -424,6 +424,22 @@ func canonicalAutoRegisterMatchMessage(reason string) string {
|
||||||
return "Canonical auto-register matched existing node by " + reason
|
return "Canonical auto-register matched existing node by " + reason
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shouldPreserveExistingAutoRegisterHost reports whether an identity-matched
|
||||||
|
// node keeps its stored host on re-registration. The agent orders
|
||||||
|
// candidateHosts by preference, so an existing host that appears anywhere in
|
||||||
|
// that list was deliberately outranked by the selected host and is replaced.
|
||||||
|
// A host absent from the list is an admin-managed endpoint the agent cannot
|
||||||
|
// see; keep it.
|
||||||
|
func shouldPreserveExistingAutoRegisterHost(existingHost string, candidateHosts []string) bool {
|
||||||
|
existing := strings.TrimSpace(existingHost)
|
||||||
|
for _, candidate := range candidateHosts {
|
||||||
|
if strings.EqualFold(strings.TrimSpace(candidate), existing) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func canonicalAutoRegisterCompletionPayloadMessage() string {
|
func canonicalAutoRegisterCompletionPayloadMessage() string {
|
||||||
return "Incomplete canonical auto-register token completion payload"
|
return "Incomplete canonical auto-register token completion payload"
|
||||||
}
|
}
|
||||||
|
|
@ -1314,10 +1330,11 @@ func (h *ConfigHandlers) handleCanonicalAutoRegister(w http.ResponseWriter, r *h
|
||||||
}
|
}
|
||||||
if hostsShareResolvedIdentity(node.Host, host) {
|
if hostsShareResolvedIdentity(node.Host, host) {
|
||||||
existingIndex = i
|
existingIndex = i
|
||||||
preserveHost = true
|
preserveHost = shouldPreserveExistingAutoRegisterHost(node.Host, candidateHosts)
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("existingHost", node.Host).
|
Str("existingHost", node.Host).
|
||||||
Str("newHost", host).
|
Str("newHost", host).
|
||||||
|
Bool("preserveHost", preserveHost).
|
||||||
Str("type", "pve").
|
Str("type", "pve").
|
||||||
Msg(canonicalAutoRegisterMatchMessage("resolved host identity"))
|
Msg(canonicalAutoRegisterMatchMessage("resolved host identity"))
|
||||||
break
|
break
|
||||||
|
|
@ -1391,10 +1408,11 @@ func (h *ConfigHandlers) handleCanonicalAutoRegister(w http.ResponseWriter, r *h
|
||||||
}
|
}
|
||||||
if hostsShareResolvedIdentity(node.Host, host) {
|
if hostsShareResolvedIdentity(node.Host, host) {
|
||||||
existingIndex = i
|
existingIndex = i
|
||||||
preserveHost = true
|
preserveHost = shouldPreserveExistingAutoRegisterHost(node.Host, candidateHosts)
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("existingHost", node.Host).
|
Str("existingHost", node.Host).
|
||||||
Str("newHost", host).
|
Str("newHost", host).
|
||||||
|
Bool("preserveHost", preserveHost).
|
||||||
Str("type", "pbs").
|
Str("type", "pbs").
|
||||||
Msg(canonicalAutoRegisterMatchMessage("resolved host identity"))
|
Msg(canonicalAutoRegisterMatchMessage("resolved host identity"))
|
||||||
break
|
break
|
||||||
|
|
|
||||||
46
internal/api/config_setup_handlers_test.go
Normal file
46
internal/api/config_setup_handlers_test.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestShouldPreserveExistingAutoRegisterHost(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
existingHost string
|
||||||
|
candidateHosts []string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "existing host outranked in candidate list is replaced",
|
||||||
|
existingHost: "https://pve02:8006",
|
||||||
|
candidateHosts: []string{"https://192.168.1.12:8006", "https://pve02:8006"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing host matches candidate case-insensitively",
|
||||||
|
existingHost: "https://PVE02:8006",
|
||||||
|
candidateHosts: []string{"https://192.168.1.12:8006", "https://pve02:8006"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "admin-managed host absent from candidates is preserved",
|
||||||
|
existingHost: "https://pve02.internal.example.com:8006",
|
||||||
|
candidateHosts: []string{"https://192.168.1.12:8006", "https://pve02:8006"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty candidate list preserves existing host",
|
||||||
|
existingHost: "https://pve02:8006",
|
||||||
|
candidateHosts: nil,
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := shouldPreserveExistingAutoRegisterHost(tt.existingHost, tt.candidateHosts); got != tt.want {
|
||||||
|
t.Fatalf("shouldPreserveExistingAutoRegisterHost(%q, %v) = %v, want %v",
|
||||||
|
tt.existingHost, tt.candidateHosts, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue