fix: cluster-aware guest deduplication and multi-agent token binding

- Add cluster-aware guest ID generation (clusterName-VMID instead of instanceName-VMID)
  to prevent duplicate VMs/containers when multiple cluster nodes are monitored

- Add cluster deduplication at registration time - when a node is added that belongs
  to an already-configured cluster, merge as endpoint instead of creating duplicate

- Add startup consolidation to automatically merge duplicate cluster instances

- Change host agent token binding from agent GUID to hostname, allowing:
  - Multiple host agents to share a token (each bound by hostname)
  - Agent reinstalls on same host without token conflicts

- Remove 12-character password minimum requirement

- Remove emoji from auto-registration success message

- Fix grouped view node lookup to support both cluster-aware node IDs
  (clusterName-nodeName) and legacy guest grouping keys (instance-nodeName)

Fixes duplicate guests appearing when agents are installed on multiple
cluster nodes. Also improves multi-agent UX by allowing shared tokens.
This commit is contained in:
rcourtman 2025-12-14 10:16:17 +00:00
parent d9e2f8c80d
commit 397871629c
8 changed files with 358 additions and 91 deletions

View file

@ -1267,15 +1267,14 @@ func (s *State) UpdateNodesForInstance(instanceName string, nodes []Node) {
s.mu.Lock()
defer s.mu.Unlock()
// Create a map of existing nodes, excluding those from this instance
// Build a map of ALL existing nodes by ID (not filtered by instance)
// This handles cluster-based IDs where the same node ID comes from multiple instances
// Also preserve LinkedHostAgentID for nodes that are being updated
existingNodeLinks := make(map[string]string) // nodeID -> linkedHostAgentID
nodeMap := make(map[string]Node)
for _, node := range s.Nodes {
if node.Instance != instanceName {
nodeMap[node.ID] = node
} else if node.LinkedHostAgentID != "" {
// Preserve the link for nodes from this instance
nodeMap[node.ID] = node
if node.LinkedHostAgentID != "" {
existingNodeLinks[node.ID] = node.LinkedHostAgentID
}
}