Documentation
¶
Overview ¶
Package thanos implements a read-only client for the Thanos Querier endpoints of external OpenShift clusters (v0.8.575, audit: docs/audit/thanos-multicluster-metrics-audit.md). It powers the /clusters surface: per-(namespace, pod) CPU + memory pulled straight from each cluster's platform monitoring stack — telemetry the applications themselves never emit.
Structure mirrors internal/tempo/client.go (the canonical external-query-service template): typed Settings blob in system_settings under "thanos_clusters", narrow settingsStore interface, LoadPersisted at boot + StartConfigRefresh 30s poll for multi-pod sync, SavePersisted + live Configure swap, and a masked Snapshot for the settings UI. The one structural difference: Settings holds a LIST of clusters, and TLS-verify varies per cluster — so instead of tempo's rebuild-on-toggle single client, this package uses the Zoom two-singleton pattern (notify.go:1106): one verifying client + one lazily-built insecure twin, picked per request via thanosClientFor.
Index ¶
- func ValidJMXMetric(m string) bool
- type AlertRow
- type ClusterConfig
- type ClusterSnapshot
- type ClusterSummary
- type DeploymentRow
- type NamedSeries
- type NamespaceRow
- type NetTrendPoint
- type NodeRow
- type PodRow
- type PodSeriesTrend
- type Service
- func (s *Service) ClusterByName(name string) (ClusterConfig, bool)
- func (s *Service) Configure(cfg Settings)
- func (s *Service) CurrentSettings() Settings
- func (s *Service) DeployTrend(ctx context.Context, c ClusterConfig, namespace, deploy, metric string, ...) ([]NamedSeries, int, error)
- func (s *Service) DeploymentMetrics(ctx context.Context, c ClusterConfig, namespace string) ([]DeploymentRow, error)
- func (s *Service) FiringAlerts(ctx context.Context, c ClusterConfig) ([]AlertRow, error)
- func (s *Service) HaproxyTrend(ctx context.Context, c ClusterConfig, namespace, kind string, ...) ([]NamedSeries, error)
- func (s *Service) HasEnabledClusters() bool
- func (s *Service) JMXMetricNames(ctx context.Context, c ClusterConfig, namespace, deploy string) ([]string, error)
- func (s *Service) JMXTrend(ctx context.Context, c ClusterConfig, namespace, deploy, metric string, ...) ([]NamedSeries, int, error)
- func (s *Service) LoadPersisted(ctx context.Context, store settingsStore) error
- func (s *Service) NamespaceMetrics(ctx context.Context, c ClusterConfig) ([]NamespaceRow, error)
- func (s *Service) NamespacePodsTrend(ctx context.Context, c ClusterConfig, namespace string, from, to time.Time) ([]PodSeriesTrend, int, error)
- func (s *Service) NamespaceTrend(ctx context.Context, c ClusterConfig, namespace string, from, to time.Time) ([]TrendPoint, error)
- func (s *Service) NetworkTrend(ctx context.Context, c ClusterConfig, from, to time.Time) ([]NetTrendPoint, error)
- func (s *Service) NodeMetrics(ctx context.Context, c ClusterConfig) ([]NodeRow, error)
- func (s *Service) PodMetrics(ctx context.Context, c ClusterConfig, podRe string) ([]PodRow, bool, error)
- func (s *Service) PodTrend(ctx context.Context, c ClusterConfig, namespace, pod string, ...) ([]TrendPoint, error)
- func (s *Service) ResourceTrend(ctx context.Context, c ClusterConfig, metric string, byNode bool, ...) ([]NamedSeries, error)
- func (s *Service) SavePersisted(ctx context.Context, store settingsStore, cfg Settings) error
- func (s *Service) Snapshot() Snapshot
- func (s *Service) StartConfigRefresh(ctx context.Context, store settingsStore, interval time.Duration)
- func (s *Service) Summary(ctx context.Context, c ClusterConfig) (ClusterSummary, error)
- type Settings
- type Snapshot
- type TrendPoint
- type ValuePoint
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ValidJMXMetric ¶ added in v0.9.140
ValidJMXMetric — ham metrik adının güvenli JMX adı olup olmadığı.
Types ¶
type AlertRow ¶ added in v0.9.36
type AlertRow struct {
AlertName string `json:"alertName"`
Severity string `json:"severity"`
Namespace string `json:"namespace,omitempty"`
Pod string `json:"pod,omitempty"`
AgeSec int64 `json:"ageSec,omitempty"`
}
AlertRow — firing bir alert (v0.9.36, design handoff B3 + panel). AgeSec best-effort (ALERTS_FOR_STATE join'i; yoksa 0).
type ClusterConfig ¶
type ClusterConfig struct {
Name string `json:"name"`
URL string `json:"url"`
// AuthType — none | bearer. Bearer covers the standard
// OpenShift path: a ServiceAccount token with the
// cluster-monitoring-view ClusterRole against the
// oauth-proxy'd thanos-querier route.
AuthType string `json:"authType,omitempty"`
// Token — never echoed; Snapshot exposes HasToken only.
Token string `json:"token,omitempty"`
// NamespaceFilter is a PromQL regex injected as
// namespace=~"..." into every query — the cardinality shield
// that keeps a 10k-pod estate from riding home in one
// response. Empty = all namespaces (topk still caps rows).
NamespaceFilter string `json:"namespaceFilter,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
Enabled bool `json:"enabled"`
}
ClusterConfig is one remote cluster entry. Name doubles as the APM join key: it must equal the cluster value spans carry (k8s.cluster.name / openshift.cluster.name — clusterDeriveExpr) for the service→cluster pivot to light up; the Settings UI suggests observed names for exactly that reason.
type ClusterSnapshot ¶
type ClusterSnapshot struct {
Name string `json:"name"`
URL string `json:"url"`
AuthType string `json:"authType,omitempty"`
HasToken bool `json:"hasToken"`
NamespaceFilter string `json:"namespaceFilter,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
Enabled bool `json:"enabled"`
}
ClusterSnapshot mirrors ClusterConfig with the token masked.
type ClusterSummary ¶ added in v0.8.586
type ClusterSummary struct {
Cluster string `json:"cluster"`
Nodes int `json:"nodes,omitempty"`
Pods int `json:"pods,omitempty"`
CPUUsedCores float64 `json:"cpuUsedCores,omitempty"`
MemUsedBytes float64 `json:"memUsedBytes,omitempty"`
// v0.9.9 — cluster toplam network hızı (node-exporter, lo hariç).
// Best-effort: seri yoksa 0 kalır, UI kartı hiç render etmez.
NetInBps float64 `json:"netInBps,omitempty"`
NetOutBps float64 `json:"netOutBps,omitempty"`
// v0.9.30 (design handoff B1) — kapasite (%), pod-fazı (donut),
// firing-alert sayısı (banner/KPI). Hepsi best-effort; 0 =
// kube-state-metrics/ALERTS serisi yok, UI ilgili görseli gizler.
CPUCapacityCores float64 `json:"cpuCapacityCores,omitempty"`
MemCapacityBytes float64 `json:"memCapacityBytes,omitempty"`
PodsRunning int `json:"podsRunning,omitempty"`
PodsPending int `json:"podsPending,omitempty"`
PodsFailed int `json:"podsFailed,omitempty"`
AlertsCritical int `json:"alertsCritical,omitempty"`
AlertsWarning int `json:"alertsWarning,omitempty"`
}
ClusterSummary — genel görünüm kartının verisi (v0.8.586, redesign audit §3.1). Her alan kendi sorgusundan BEST-EFFORT dolar: token tenancy-port'a bağlıysa node ailesi boş kalır ama pod sayısı yine gelir (kısmi kart > hata kartı). Dört sorgunun DÖRDÜ de başarısızsa cluster erişilemez sayılır ve hata döner.
type DeploymentRow ¶ added in v0.9.22
type DeploymentRow struct {
Cluster string `json:"cluster"`
Namespace string `json:"namespace"`
Deployment string `json:"deployment"`
Pods int `json:"pods"`
CPUCores float64 `json:"cpuCores"`
MemBytes float64 `json:"memBytes"`
PodNames []string `json:"podNames"`
// v0.9.39 — KSM replicas/status (best-effort). Status boş = KSM
// ailesi bu iş yükü için yok (heuristik eşleşen StatefulSet/
// DaemonSet dahil); ready/desired yalnız Status doluyken anlamlı.
DesiredReplicas int `json:"desiredReplicas"`
ReadyReplicas int `json:"readyReplicas"`
Status string `json:"status,omitempty"`
}
DeploymentRow — bir namespace içindeki iş yükü (Deployment/STS/DS) rollup satırı (v0.9.22). PodNames pod tablosunun ?deployment= süzgecini besler (istemci üyelikle süzer — ad-önek sezgiseli değil, gerçek eşleme).
type NamedSeries ¶ added in v0.9.35
type NamedSeries struct {
Name string `json:"name"`
Points []ValuePoint `json:"points"`
}
NamedSeries — adlandırılmış çok-serili trend (v0.9.35): total modda tek seri (Name=""), byNode modda instance başına.
type NamespaceRow ¶ added in v0.8.588
type NamespaceRow struct {
Cluster string `json:"cluster"`
Namespace string `json:"namespace"`
Pods int `json:"pods,omitempty"`
CPUCores float64 `json:"cpuCores"`
MemBytes float64 `json:"memBytes"`
// v0.9.37 (B4) — restart toplamı + failing pod sayısı (best-effort).
Restarts int `json:"restarts,omitempty"`
Failing int `json:"failing,omitempty"`
}
NamespaceRow — bir namespace'in rollup satırı (v0.8.588, redesign audit §3.3). Ayrı sorgudan gelir — pod listesinin topk kesmesinden ETKİLENMEZ (toplamlar tam).
type NetTrendPoint ¶ added in v0.9.9
type NetTrendPoint struct {
Bucket int64 `json:"bucket"`
InBps float64 `json:"inBps"`
OutBps float64 `json:"outBps"`
}
NetTrendPoint — cluster network throughput trendi (v0.9.9): dakika bucket'ında in/out byte/s.
type NodeRow ¶ added in v0.8.582
type NodeRow struct {
Cluster string `json:"cluster"`
Node string `json:"node"`
CPUCores float64 `json:"cpuCores"`
MemBytes float64 `json:"memBytes"`
CPUPct float64 `json:"cpuPct,omitempty"`
MemPct float64 `json:"memPct,omitempty"`
// v0.9.9 — node network hızı (node-exporter, lo hariç; best-effort).
NetInBps float64 `json:"netInBps,omitempty"`
NetOutBps float64 `json:"netOutBps,omitempty"`
// v0.9.37 (B4) — rol (heatmap dot + Nodes tab); kube_node_role.
Role string `json:"role,omitempty"`
}
NodeRow — bir node'un anlık CPU/memory kullanımı (v0.8.582, audit: clusters-node-metrics-audit.md §3). Node = kube_node_info eşleşirse gerçek node adı, yoksa instance (ip:port). Pct'ler kendi paydalarına oran: CPUPct çekirdek sayısına (best-effort — 0 = bilinmiyor), MemPct MemTotal'a (zorunlu aileden, hep dolu).
type PodRow ¶
type PodRow struct {
Cluster string `json:"cluster"`
Namespace string `json:"namespace"`
Pod string `json:"pod"`
CPUCores float64 `json:"cpuCores"`
MemBytes float64 `json:"memBytes"`
CPUPct float64 `json:"cpuPct,omitempty"`
MemPct float64 `json:"memPct,omitempty"`
// Request-based percentages (v0.8.580) — provisioning accuracy
// axis, alongside the limit-based throttle/OOM axis above. Can
// legitimately exceed 100 (pod using more than it requested) —
// deliberately NOT clamped like the limit pcts; the overshoot
// IS the signal. 0 = requests not exposed (best-effort).
CPUPctOfReq float64 `json:"cpuPctOfReq,omitempty"`
MemPctOfReq float64 `json:"memPctOfReq,omitempty"`
// Ham limit/request değerleri (v0.9.3, trend-upgrade audit §1
// düzeltmesi): threshold referans ÇİZGİLERİ mutlak değer ister
// (cores/bytes ekseninde) — yüzdeler yetmez. acc'ta zaten
// vardı, satıra indirildi; 0 = bilinmiyor.
CPULimitCores float64 `json:"cpuLimitCores,omitempty"`
MemLimitBytes float64 `json:"memLimitBytes,omitempty"`
CPURequestCores float64 `json:"cpuRequestCores,omitempty"`
MemRequestBytes float64 `json:"memRequestBytes,omitempty"`
// v0.9.9 — pod network hızı (cAdvisor, best-effort).
NetInBps float64 `json:"netInBps,omitempty"`
NetOutBps float64 `json:"netOutBps,omitempty"`
// Service (v0.9.11) — Coremetry servis eşleşmesi (host_name =
// pod adı köprüsü). API katmanı doldurur (chstore.PodServiceMap
// + pickPodService); thanos paketi bu alana yazmaz. Boş =
// eşleşme yok (instrument edilmemiş / infra pod'u / belirsiz).
Service string `json:"service,omitempty"`
// v0.9.37 (B4) — faz + restart (Pods tab Status/Restarts).
// Best-effort: kube-state-metrics yoksa Phase="" / Restarts=0.
// v0.9.371 — Restarts'ta omitempty YOK artık: gerçek 0 wire'da
// görünür (Clusters sayfası 0'ı '—' çiziyordu). Bilinmezlik ayrı
// bayrak: restart SERİSİ hiç gelmediyse (KSM yok ya da 1000-seri
// parse tavanı) RestartsUnknown=true — 0 sağlıklıymış gibi değil,
// '—' bilinmiyor gibi çizilir. Üyelik = bilgi: KSM 0 restart'lı
// pod için de seri döndürür.
Phase string `json:"phase,omitempty"`
Restarts int `json:"restarts"`
RestartsUnknown bool `json:"restartsUnknown,omitempty"`
}
PodRow is one (cluster, namespace, pod) sample from the merged instant queries. CPU is CORES (rate of cpu-seconds), not the 0-1 utilization ratio HostRow carries — deliberately a separate shape (audit §7). Pct fields are 0 when the cluster doesn't expose kube-state-metrics limits — same "0 = unknown" contract HostRow.MemPct already established.
type PodSeriesTrend ¶ added in v0.9.3
type PodSeriesTrend struct {
Pod string `json:"pod"`
Trend []TrendPoint `json:"trend"`
}
PodSeriesTrend — multi-pod görünümün seri birimi (v0.9.3): bir pod'un dakika-bucket trendi.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service holds the live cluster list. Concurrency contract is tempo's: RWMutex around the config, background refresh poll keeping multi-pod deployments in sync via the shared blob.
func (*Service) ClusterByName ¶
func (s *Service) ClusterByName(name string) (ClusterConfig, bool)
ClusterByName returns the ENABLED cluster entry for name.
func (*Service) CurrentSettings ¶
CurrentSettings — full config INCLUDING tokens; only for the PUT handler's stored-token merge. Never echo over the wire (tempo contract).
func (*Service) DeployTrend ¶ added in v0.9.50
func (s *Service) DeployTrend(ctx context.Context, c ClusterConfig, namespace, deploy, metric string, byPod bool, from, to time.Time) ([]NamedSeries, int, error)
DeployTrend — bir deployment'ın pod'larına kapsanmış CPU/Mem trendi (v0.9.50, design handoff §8 — Servis → Infrastructure sekmesi). ResourceTrend'in deployment-kapsamlı aynası: total tek seri, byPod modunda sum by (pod) ham çekilir ve top-8 seçimi ortalamaya göre Go'da yapılır (topk'siz — v0.9.3 adım-kayması notu). Metrik ailesi yoksa boş döner; UI grafiği gizler (görünmez-düşer). İkinci dönüş (v0.9.539): kesme ÖNCESİ seri sayısı — UI "N / M pod" rozetini bununla çizer (NamespacePodsTrend'in aynı sözleşmesi).
func (*Service) DeploymentMetrics ¶ added in v0.9.22
func (s *Service) DeploymentMetrics(ctx context.Context, c ClusterConfig, namespace string) ([]DeploymentRow, error)
DeploymentMetrics — namespace'in pod başına cpu/mem'ini (zorunlu 2 sorgu) kube-state-metrics owner eşlemesiyle (best-effort 2 sorgu) iş yüküne toplar. Fallback zinciri (deployment audit uyarlaması — probe yerine runtime): tam join → rs-hash soyma → pod-adı sezgiseli → "(unassigned)".
func (*Service) FiringAlerts ¶ added in v0.9.36
FiringAlerts — firing alert listesi (kritik-önce). ALERTS (authoritative firing set) + ALERTS_FOR_STATE (best-effort yaş, join by label). Metrik yoksa boş liste; UI paneli gizler.
func (*Service) HaproxyTrend ¶ added in v0.9.534
func (s *Service) HaproxyTrend(ctx context.Context, c ClusterConfig, namespace, kind string, from, to time.Time) ([]NamedSeries, error)
HaproxyTrend — v0.9.534. Namespace'in route'larına router (HAProxy) gözünden trend: kind = "2xx" | "5xx" (yanıt oranı, req/s) | "latency" (backend ortalama, ms). DeployTrend'in aynası: query_range, seri adı route etiketi, top-N seçimi ortalamaya göre Go'da (topk'siz — v0.9.3 adım-kayması notu). Metrik ailesi cluster'da yoksa boş döner; UI bölümü gizler (görünmez-düşer).
func (*Service) HasEnabledClusters ¶
HasEnabledClusters gates the /clusters surface: false → the page shows its Empty state without any HTTP attempts.
func (*Service) JMXMetricNames ¶ added in v0.9.144
func (s *Service) JMXMetricNames(ctx context.Context, c ClusterConfig, namespace, deploy string) ([]string, error)
JMXMetricNames — bir deployment'ın Thanos'ta taşıdığı jvm_/jboss_ metrik ADLARINI keşfeder (v0.9.144 auto-discovery). count by (__name__) instant sorgusu; her serinin __name__ label'ını toplar, sıralı+tekilleştirir. Boş dönmesi = cluster'da servisin JMX'i yok (UI o cluster'ı göstermez).
func (*Service) JMXTrend ¶ added in v0.9.140
func (s *Service) JMXTrend(ctx context.Context, c ClusterConfig, namespace, deploy, metric string, byPod bool, podFilter string, from, to time.Time) ([]NamedSeries, int, error)
JMXTrend — keşfedilen bir JBoss/JVM JMX metriğinin trendi (v0.9.140, selector+discovery v0.9.144). DeployTrend'in JMX aynası: aynı query_range + Go-tarafı top-8 seçimi (topk'siz), tek fark seri adının `pod` label'ından okunması ve JMX-özel selector (jmxTrendQuery). Metrik ailesi yoksa boş döner; UI grafiği gizler (görünmez-düşer). İkinci dönüş (v0.9.370): kesme ÖNCESİ toplam seri sayısı. Saf pod grouping'te top-8 kesilir (aşağıda) ve UI "8 / N pod" diyebilsin diye N burada döner — sekmenin var olma sebebi "hangi pod'un heap'i dolu" sorusuyken en DÜŞÜK ortalamalı pod'ların sessizce düşmesi, pencere sonunda OOM'a tırmanan pod'u da düşürebiliyordu (ortalaması düşük).
func (*Service) LoadPersisted ¶
LoadPersisted hydrates from system_settings. Missing blob = empty list (HasEnabledClusters reports false; handlers 404).
func (*Service) NamespaceMetrics ¶ added in v0.8.588
func (s *Service) NamespaceMetrics(ctx context.Context, c ClusterConfig) ([]NamespaceRow, error)
NamespaceMetrics — cpu+mem zorunlu (2 sorgu), pod sayısı best-effort (1 sorgu; aynı metrik ailesi, pratikte hep döner).
func (*Service) NamespacePodsTrend ¶ added in v0.9.3
func (s *Service) NamespacePodsTrend(ctx context.Context, c ClusterConfig, namespace string, from, to time.Time) ([]PodSeriesTrend, int, error)
NamespacePodsTrend — namespace'in pod başına dakika-bucket trendleri (v0.9.3). Sorgu topk'siz (adım-başına set kayması kırar — promql.go notu); top-10 seçimi ortalama CPU'ya göre Go'da, cpu+mem AYNI pod setine filtrelenir. İkinci dönüş: kesme öncesi toplam pod sayısı ("top 10 of N" etiketi için).
func (*Service) NamespaceTrend ¶ added in v0.9.2
func (s *Service) NamespaceTrend(ctx context.Context, c ClusterConfig, namespace string, from, to time.Time) ([]TrendPoint, error)
NamespaceTrend — PodTrend'in namespace-scoped aynası (v0.9.2): aynı dakika-bucket sözleşmesi, pod pini yok — namespace toplamı.
func (*Service) NetworkTrend ¶ added in v0.9.9
func (s *Service) NetworkTrend(ctx context.Context, c ClusterConfig, from, to time.Time) ([]NetTrendPoint, error)
NetworkTrend — cluster toplam ağ hızının dakika-bucket trendi (Overview throughput grafiği). rangeTrend'in net karşılığı; iki sorgu da zorunlu (grafiğin kendisi bu — best-effort'luk üst katmanda: seri boşsa UI grafiği hiç göstermez).
func (*Service) NodeMetrics ¶ added in v0.8.582
NodeMetrics — PodMetrics'in node-scope aynası: 3 zorunlu sorgu (cpu used, mem total, mem avail) + 2 best-effort (çekirdek sayısı, kube_node_info ad güzelleştirmesi). Sabit 5 sorgu/cluster.
func (*Service) PodMetrics ¶
func (s *Service) PodMetrics(ctx context.Context, c ClusterConfig, podRe string) ([]PodRow, bool, error)
PodMetrics runs the per-cluster instant queries (CPU rate, working-set memory, cpu/mem limits) and merges them by (namespace, pod). Exactly four queries per cluster regardless of pod count — never a query per pod (audit §4). PodMetrics'in ikinci dönüşü truncated: cpu/mem serilerinden biri podListLimit tavanına DAYANDIYSA liste cluster'ın tamamı değildir — düşük trafikli pod'lar topk dışında kalmıştır. v0.9.369: bu bayrak olmadan 3000-pod'luk cluster'da sakin bir servisin sekmesi kendinden emin "Pods (0)" diyordu; süzme istemcide, kesme sunucuda ve İFŞASIZDI. podRe — v0.9.536: boş = tüm cluster (eski davranış, /clusters sayfası); dolu = hedefli seçici pod=~"<re>" (servis sekmeleri). Hedefli modda topk(500) servisin KENDİ pod'ları içinde işler — düşük trafikli pod cluster-geneli kesime takılmaz (operator-reported: BFF pod'ları 0.001 core'da top-500'e giremiyordu, "No pods matched").
func (*Service) PodTrend ¶
func (s *Service) PodTrend(ctx context.Context, c ClusterConfig, namespace, pod string, from, to time.Time) ([]TrendPoint, error)
PodTrend returns per-bucket CPU + memory for ONE pod (drawer path — bounded by construction). Bucket = adaptif step (stepForWindow, v0.9.26): dar pencerede 15s'e kadar iner.
func (*Service) ResourceTrend ¶ added in v0.9.35
func (s *Service) ResourceTrend(ctx context.Context, c ClusterConfig, metric string, byNode bool, from, to time.Time) ([]NamedSeries, error)
ResourceTrend — Overview CPU/Mem area chart verisi. metric "cpu"|"mem"; byNode false→tek toplam seri, true→top-N instance. Bucket adaptif step'e bağlı (stepForWindow); byNode'da instance adı instanceHost ile güzelleştirilir.
func (*Service) SavePersisted ¶
SavePersisted writes the merged config (handler does the empty-token-preserves-stored merge first) and swaps it live.
func (*Service) StartConfigRefresh ¶
func (s *Service) StartConfigRefresh(ctx context.Context, store settingsStore, interval time.Duration)
StartConfigRefresh — multi-pod blob sync, 30s default (tempo v0.5.324 precedent). Run as a goroutine from main().
func (*Service) Summary ¶ added in v0.8.586
func (s *Service) Summary(ctx context.Context, c ClusterConfig) (ClusterSummary, error)
Summary — kart başına sabit 4 skaler sorgu (topk'li vektör yok; pod sayısı topk kesmesiz TAM).
type Settings ¶
type Settings struct {
Clusters []ClusterConfig `json:"clusters"`
}
Settings is the persisted blob: the whole cluster list, written atomically (custom_roles convention — no per-row races at the realistic N≤20 scale).
type Snapshot ¶
type Snapshot struct {
Clusters []ClusterSnapshot `json:"clusters"`
}
Snapshot is what GET /api/settings/thanos returns.
type TrendPoint ¶
type TrendPoint struct {
Bucket int64 `json:"bucket"`
CPUCores float64 `json:"cpuCores"`
MemBytes float64 `json:"memBytes"`
}
TrendPoint matches HostTrendPoint's bucket contract: unix SECONDS on minute boundaries, so the frontend drawer reuses the same rendering path.