aa4dfb75ea
Add a host-wide, token-authed GET /host/metrics local-API endpoint that re-serves the slice-4 collector's host + per-storage view to the customer (the de-privileged controller can't read the host itself). Add the one new collector — CPU/chassis temperature via sysfs hwmon/thermal-zones, graceful- null — to the shared HostMetrics struct, so the hub report carries cpu_temp_c too. Cross-repo host-report golden updated byte-identical. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72 lines
2.4 KiB
Go
72 lines
2.4 KiB
Go
package hub
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// fakeTemp is a TempReader returning a fixed (nullable) value.
|
|
type fakeTemp struct{ c *int }
|
|
|
|
func (f fakeTemp) CPUTempC(context.Context) *int { return f.c }
|
|
|
|
func intp(v int) *int { return &v }
|
|
|
|
// HostMetricsNow returns a fresh host block with cpu% from NodeStatus and the temp from the reader.
|
|
func TestHostMetricsNow_PopulatesTemp(t *testing.T) {
|
|
px := &fakePx{node: "demo-felhom", ns: newTestNodeStatus()}
|
|
c := NewCollector(px, fakeProber{status: "active"}, nil, nil, nil, nil, "h", "0.14.0", quietLogger()).
|
|
SetTempReader(fakeTemp{c: intp(46)})
|
|
h, err := c.HostMetricsNow(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("HostMetricsNow: %v", err)
|
|
}
|
|
if h.Node != "demo-felhom" || h.CPUPercent != 5 {
|
|
t.Errorf("host = %+v", h)
|
|
}
|
|
if h.CPUTempC == nil || *h.CPUTempC != 46 {
|
|
t.Fatalf("cpu_temp_c = %v, want 46", h.CPUTempC)
|
|
}
|
|
if h.MemoryPercent != 25 {
|
|
t.Errorf("mem%% = %v, want 25", h.MemoryPercent)
|
|
}
|
|
}
|
|
|
|
// A missing temp sensor gracefully nulls cpu_temp_c without failing the host read.
|
|
func TestHostMetricsNow_GracefulNullTemp(t *testing.T) {
|
|
px := &fakePx{node: "n", ns: newTestNodeStatus()}
|
|
c := NewCollector(px, fakeProber{status: "active"}, nil, nil, nil, nil, "h", "0.14.0", quietLogger()).
|
|
SetTempReader(fakeTemp{c: nil})
|
|
h, err := c.HostMetricsNow(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("HostMetricsNow: %v", err)
|
|
}
|
|
if h.CPUTempC != nil {
|
|
t.Fatalf("cpu_temp_c = %v, want nil (n/a)", h.CPUTempC)
|
|
}
|
|
}
|
|
|
|
// A NodeStatus failure is a hard error (no useful host view).
|
|
func TestHostMetricsNow_NodeStatusErrorIsHard(t *testing.T) {
|
|
px := &fakePx{node: "n", nsErr: errors.New("proxmox down")}
|
|
c := NewCollector(px, fakeProber{status: "active"}, nil, nil, nil, nil, "h", "0.14.0", quietLogger())
|
|
if _, err := c.HostMetricsNow(context.Background()); err == nil {
|
|
t.Fatal("NodeStatus failure must be a hard error")
|
|
}
|
|
}
|
|
|
|
// Collect() (the hub report) also carries the temp now — the operator freebie.
|
|
func TestCollect_HostReportCarriesTemp(t *testing.T) {
|
|
px := &fakePx{node: "n", ns: newTestNodeStatus()}
|
|
c := NewCollector(px, fakeProber{status: "active"}, nil, nil, nil, nil, "h", "0.14.0", quietLogger()).
|
|
SetTempReader(fakeTemp{c: intp(51)})
|
|
r, err := c.Collect(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("Collect: %v", err)
|
|
}
|
|
if r.Host.CPUTempC == nil || *r.Host.CPUTempC != 51 {
|
|
t.Fatalf("report host cpu_temp_c = %v, want 51", r.Host.CPUTempC)
|
|
}
|
|
}
|