From dd49fbd93e2eb573beb08aa442e42b73b0ac04b6 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 6 Aug 2026 00:46:59 +0100 Subject: [PATCH] fix(mock): seed docker host disk and network I/O history Seeded mock history recorded docker hosts with cpu, memory and disk only, while the synthetic generator used past the seed window emits the full guest metric set. The result was an inversion across chart ranges: a docker host had no diskread, diskwrite, netin or netout history at 5m through 24h and full history at 7d and 30d. Real docker hosts report both through the agent, so the seed now covers the same series the generator does and every range agrees. The guardrail test asserts seeded coverage matches the synthetic metric set rather than a hand-listed set, so a future series added to one path cannot quietly skip the other. --- .../v6/internal/subsystems/monitoring.md | 8 +++++- internal/monitoring/mock_metrics_history.go | 7 +++-- .../monitoring/mock_metrics_history_test.go | 26 +++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) 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) + } + } +}