Ensure agent ID collisions respect token boundaries (Related to #658)

This commit is contained in:
rcourtman 2025-11-12 22:46:56 +00:00
parent bb55144637
commit 1166576b21
2 changed files with 94 additions and 13 deletions

View file

@ -1344,7 +1344,12 @@ func findMatchingDockerHost(hosts []models.DockerHost, report agentsdocker.Repor
if agentID != "" {
for _, host := range hosts {
if strings.TrimSpace(host.AgentID) == agentID {
if strings.TrimSpace(host.AgentID) != agentID {
continue
}
existingToken := strings.TrimSpace(host.TokenID)
if tokenID == "" || existingToken == tokenID {
return host, true
}
}
@ -8245,12 +8250,12 @@ func (m *Monitor) GetConfigPersistence() *config.ConfigPersistence {
func (m *Monitor) pollStorageBackupsWithNodes(ctx context.Context, instanceName string, client PVEClientInterface, nodes []proxmox.Node, nodeEffectiveStatus map[string]string) {
var allBackups []models.StorageBackup
seenVolids := make(map[string]bool) // Track seen volume IDs to avoid duplicates
hadSuccessfulNode := false // Track if at least one node responded successfully
storagesWithBackup := 0 // Number of storages that should contain backups
contentSuccess := 0 // Number of successful storage content fetches
contentFailures := 0 // Number of failed storage content fetches
storageQueryErrors := 0 // Number of nodes where storage list could not be queried
seenVolids := make(map[string]bool) // Track seen volume IDs to avoid duplicates
hadSuccessfulNode := false // Track if at least one node responded successfully
storagesWithBackup := 0 // Number of storages that should contain backups
contentSuccess := 0 // Number of successful storage content fetches
contentFailures := 0 // Number of failed storage content fetches
storageQueryErrors := 0 // Number of nodes where storage list could not be queried
storagePreserveNeeded := map[string]struct{}{}
storageSuccess := map[string]struct{}{}

View file

@ -14,12 +14,12 @@ func newTestMonitor(t *testing.T) *Monitor {
t.Helper()
m := &Monitor{
state: models.NewState(),
alertManager: alerts.NewManager(),
removedDockerHosts: make(map[string]time.Time),
rateTracker: NewRateTracker(),
dockerTokenBindings: make(map[string]string),
dockerMetadataStore: config.NewDockerMetadataStore(t.TempDir()),
state: models.NewState(),
alertManager: alerts.NewManager(),
removedDockerHosts: make(map[string]time.Time),
rateTracker: NewRateTracker(),
dockerTokenBindings: make(map[string]string),
dockerMetadataStore: config.NewDockerMetadataStore(t.TempDir()),
}
t.Cleanup(func() { m.alertManager.Stop() })
return m
@ -114,6 +114,82 @@ func TestApplyDockerReportGeneratesUniqueIDsForCollidingHosts(t *testing.T) {
}
}
func TestApplyDockerReportUsesTokenToDisambiguateAgentIDCollisions(t *testing.T) {
monitor := newTestMonitor(t)
baseReport := agentsdocker.Report{
Agent: agentsdocker.AgentInfo{
ID: "duplicate-agent",
Version: "1.0.0",
IntervalSeconds: 30,
},
Host: agentsdocker.HostInfo{
Hostname: "docker-one",
Name: "Docker One",
MachineID: "machine-A",
DockerVersion: "26.0.0",
TotalCPU: 4,
TotalMemoryBytes: 16 << 30,
UptimeSeconds: 120,
},
Containers: []agentsdocker.Container{
{ID: "container-a", Name: "api"},
},
Timestamp: time.Now().UTC(),
}
tokenOne := &config.APITokenRecord{ID: "token-one", Name: "Token One"}
hostOne, err := monitor.ApplyDockerReport(baseReport, tokenOne)
if err != nil {
t.Fatalf("ApplyDockerReport hostOne: %v", err)
}
if hostOne.ID == "" {
t.Fatal("expected hostOne to receive an identifier")
}
secondReport := baseReport
secondReport.Host.Hostname = "docker-two"
secondReport.Host.Name = "Docker Two"
secondReport.Host.MachineID = "machine-B"
secondReport.Containers = []agentsdocker.Container{
{ID: "container-b", Name: "db"},
}
secondReport.Timestamp = baseReport.Timestamp.Add(30 * time.Second)
tokenTwo := &config.APITokenRecord{ID: "token-two", Name: "Token Two"}
hostTwo, err := monitor.ApplyDockerReport(secondReport, tokenTwo)
if err != nil {
t.Fatalf("ApplyDockerReport hostTwo: %v", err)
}
if hostTwo.ID == "" {
t.Fatal("expected hostTwo to receive an identifier")
}
if hostOne.ID == hostTwo.ID {
t.Fatalf("expected different identifiers for hosts sharing an agent ID, got %q", hostOne.ID)
}
hosts := monitor.state.GetDockerHosts()
if len(hosts) != 2 {
t.Fatalf("expected 2 hosts after two reports, got %d", len(hosts))
}
updatedReport := baseReport
updatedReport.Timestamp = baseReport.Timestamp.Add(60 * time.Second)
updatedReport.Containers = append(updatedReport.Containers, agentsdocker.Container{
ID: "container-c",
Name: "cache",
})
updatedHostOne, err := monitor.ApplyDockerReport(updatedReport, tokenOne)
if err != nil {
t.Fatalf("ApplyDockerReport hostOne update: %v", err)
}
if updatedHostOne.ID != hostOne.ID {
t.Fatalf("expected hostOne to retain identifier %q, got %q", hostOne.ID, updatedHostOne.ID)
}
}
func TestApplyDockerReportIncludesContainerDiskDetails(t *testing.T) {
timestamp := time.Now().UTC()
report := agentsdocker.Report{