Files
seaweedfs/telemetry/server/storage/confirmed_test.go
T
Chris Lu 0973634fd4 telemetry: keep only clusters that store at least 10 GiB (#11138)
* telemetry: tidy the server module after the protobuf bump

Claude-Session: https://claude.ai/code/session_01VGiphDxpsKMwu9XpUFhybQ

* telemetry: keep only clusters that store at least 10 GiB

Fresh weed server runs, CI jobs and throwaway containers each mint their
own cluster id. They came in at tens of thousands a day, were most of
the counted clusters and held almost none of the bytes, and the state
file and the metrics page grew with every one of them. Reports under
the floor are counted and dropped, and a state file written before the
floor sheds them on the first restart.

Claude-Session: https://claude.ai/code/session_01VGiphDxpsKMwu9XpUFhybQ

* master: report telemetry only once the cluster stores 10 GiB

A throwaway cluster no longer registers itself with its first report a
minute after start; a real one begins reporting at the first daily tick
after it crosses the floor.

Claude-Session: https://claude.ai/code/session_01VGiphDxpsKMwu9XpUFhybQ
2026-09-03 12:36:00 -07:00

88 lines
2.8 KiB
Go

package storage
import (
"testing"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/seaweedfs/seaweedfs/telemetry/proto"
)
func report(id, version string) *proto.TelemetryData {
return &proto.TelemetryData{
TopologyId: id,
Version: version,
Os: "linux/amd64",
VolumeServerCount: 1,
TotalDiskBytes: proto.MinDiskBytes,
TotalVolumeCount: 1,
}
}
func statsOf(t *testing.T, s *PrometheusStorage) map[string]interface{} {
t.Helper()
stats, err := s.GetStats()
if err != nil {
t.Fatalf("stats: %v", err)
}
return stats
}
func TestConfirmedClusters(t *testing.T) {
s := newPrometheusStorage(prometheus.NewRegistry())
// A single-day cluster is active but not confirmed; with no confirmed
// clusters yet, distributions fall back to all active clusters.
if err := s.StoreTelemetry(report("aaaaaaaa-0000-0000-0000-000000000001", "4.40")); err != nil {
t.Fatal(err)
}
stats := statsOf(t, s)
if stats["active_instances"] != 1 || stats["confirmed_instances"] != 0 {
t.Fatalf("day one: active=%v confirmed=%v, want 1/0", stats["active_instances"], stats["confirmed_instances"])
}
if v := stats["versions"].(map[string]int); v["4.40"] != 1 {
t.Fatalf("fallback distribution missing active cluster: %v", v)
}
// Give cluster A samples from the six previous days: now seen on 7
// distinct days.
s.mu.Lock()
id := "aaaaaaaa-0000-0000-0000-000000000001"
var older []HistorySample
for offset := -6; offset < 0; offset++ {
older = append(older, HistorySample{
Ts: time.Now().AddDate(0, 0, offset).Unix(),
TotalDiskBytes: 50,
})
}
s.histories[id] = append(older, s.histories[id]...)
s.mu.Unlock()
// A one-shot cluster B arrives (like an injected report): it counts as
// active, but the distributions now only reflect confirmed clusters.
if err := s.StoreTelemetry(report("bbbbbbbb-0000-0000-0000-000000000002", "9.99")); err != nil {
t.Fatal(err)
}
stats = statsOf(t, s)
if stats["active_instances"] != 2 || stats["confirmed_instances"] != 1 {
t.Fatalf("day seven: active=%v confirmed=%v, want 2/1", stats["active_instances"], stats["confirmed_instances"])
}
v := stats["versions"].(map[string]int)
if v["4.40"] != 1 {
t.Errorf("confirmed cluster missing from distribution: %v", v)
}
if _, ok := v["9.99"]; ok {
t.Errorf("one-shot cluster polluted the distribution: %v", v)
}
// Cluster A meets the 1/3/7-day thresholds, B only the 1-day one, and
// unmet thresholds are present as zero so the dashboard can show them.
byDays := stats["confirmed_by_days"].(map[int]int)
want := map[int]int{1: 2, 3: 1, 7: 1, 14: 0, 30: 0}
for threshold, expected := range want {
if got, ok := byDays[threshold]; !ok || got != expected {
t.Errorf("confirmed_by_days[%d] = %v (present=%v), want %d", threshold, got, ok, expected)
}
}
}