diff --git a/docs/release-control/v6/internal/subsystems/monitoring.md b/docs/release-control/v6/internal/subsystems/monitoring.md index 50ea99e48..11f407d7a 100644 --- a/docs/release-control/v6/internal/subsystems/monitoring.md +++ b/docs/release-control/v6/internal/subsystems/monitoring.md @@ -496,7 +496,13 @@ changes. fixture registries synced in `internal/mock/metric_personas.go`, never a per-call fixture graph clone on the chart path. A percentage series without its byte companion silently empties the host-capacity memory column instead - of degrading it. + of degrading it. The same obligation is general. Seeded coverage in + `internal/monitoring/mock_metrics_history.go` and the synthetic generator + must carry the same series set per resource kind, so a chart window never + decides whether a series exists. Docker hosts seed disk and network I/O for + that reason, matching what the agent reports on a real host. A series + present on one range and absent on another reads as a broken column, not as + missing history. Discovery config and configured-host IP resolution must stay off the monitor lock. `internal/monitoring/monitor_discovery_helpers.go` exposes the canonical `discoveryConfigSnapshot()` that discovery providers consume, diff --git a/internal/monitoring/mock_metrics_history.go b/internal/monitoring/mock_metrics_history.go index dadbaa087..0d45f7ff7 100644 --- a/internal/monitoring/mock_metrics_history.go +++ b/internal/monitoring/mock_metrics_history.go @@ -914,13 +914,16 @@ func seedMockMetricsHistory(mh *MetricsHistory, ms *metrics.Store, graph mock.Fi continue } + // Docker hosts report disk and network I/O through the agent, and the + // synthetic generator emits both beyond the seeded window. Seeding the + // same series keeps short ranges from being the only ones missing them. recordGuest( []string{"dockerHost:" + host.ID}, "dockerHost", host.ID, true, - false, - false, + true, + true, ) for _, container := range host.Containers { diff --git a/internal/monitoring/mock_metrics_history_test.go b/internal/monitoring/mock_metrics_history_test.go index 22246f52b..1484fa78b 100644 --- a/internal/monitoring/mock_metrics_history_test.go +++ b/internal/monitoring/mock_metrics_history_test.go @@ -1989,3 +1989,29 @@ func TestSeedMockMetricsHistory_DiskTelemetryParityAcrossNativeAndTrueNAS(t *tes } } } + +// Seeded mock history and the synthetic generator must agree on which series a +// resource carries. Docker hosts previously seeded cpu, memory, and disk only, +// so their I/O series existed on ranges past the seed window and nowhere else. +func TestMockDockerHostSeedCoversTheSameSeriesAsTheSyntheticGenerator(t *testing.T) { + previous := mock.IsMockEnabled() + mustSetMockEnabled(t, true) + defer mustSetMockEnabled(t, previous) + + history := NewMetricsHistory(4096, 24*time.Hour) + graph := mock.CurrentFixtureGraph() + if len(graph.State.DockerHosts) == 0 { + t.Fatal("mock fixture graph has no docker hosts") + } + + now := time.Now().UTC() + seedMockMetricsHistory(history, nil, graph, now, 2*time.Hour, time.Minute) + + hostID := graph.State.DockerHosts[0].ID + for _, metricType := range mockGuestChartMetricTypes { + points := history.GetGuestMetrics("dockerHost:"+hostID, metricType, 2*time.Hour) + if len(points) == 0 { + t.Fatalf("seeded docker host %s is missing the %s series", hostID, metricType) + } + } +}