diff --git a/internal/models/models.go b/internal/models/models.go index 110f9fb2f..ad05e92e2 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -2029,6 +2029,25 @@ func (s *State) LinkNodeToHostAgent(nodeID, hostAgentID string) bool { return false } +// UnlinkNodesFromHostAgent clears LinkedHostAgentID from all nodes linked to the given host agent. +// This is called when a host agent is removed to clean up stale references. +func (s *State) UnlinkNodesFromHostAgent(hostAgentID string) int { + s.mu.Lock() + defer s.mu.Unlock() + + count := 0 + for i, node := range s.Nodes { + if node.LinkedHostAgentID == hostAgentID { + s.Nodes[i].LinkedHostAgentID = "" + count++ + } + } + if count > 0 { + s.LastUpdate = time.Now() + } + return count +} + // UpsertCephCluster inserts or updates a Ceph cluster in the state. // Uses ID (typically the FSID) for matching. func (s *State) UpsertCephCluster(cluster CephCluster) { diff --git a/internal/monitoring/monitor.go b/internal/monitoring/monitor.go index f440f8272..7db302a28 100644 --- a/internal/monitoring/monitor.go +++ b/internal/monitoring/monitor.go @@ -1210,6 +1210,15 @@ func (m *Monitor) RemoveHostAgent(hostID string) (models.Host, error) { m.state.RemoveConnectionHealth(hostConnectionPrefix + hostID) + // Clear LinkedHostAgentID from any nodes that were linked to this host agent + unlinkedCount := m.state.UnlinkNodesFromHostAgent(hostID) + if unlinkedCount > 0 { + log.Info(). + Str("hostID", hostID). + Int("unlinkedNodes", unlinkedCount). + Msg("Cleared host agent links from PVE nodes") + } + log.Info(). Str("host", host.Hostname). Str("hostID", hostID).