v0.171.0: disk-health card device-model label (pairs with agent v0.95.0)

agentapi.SmartSummary.ModelName mirrors the agent's model_name; the card row label
prefers the device model over the raw name/UUID, falling back to Name(+hint) on an
old agent. Additive. Test + red-proof (drop fallback -> A4 fails).
This commit is contained in:
2026-07-25 08:23:30 +02:00
parent de14eedb9f
commit f6a8249593
4 changed files with 42 additions and 3 deletions
+9
View File
@@ -1,5 +1,14 @@
## Changelog
### v0.171.0 — Disk-health card: device-model label (pairs with agent v0.95.0) (2026-07-25)
`agentapi.SmartSummary` gains `ModelName` (mirrors the agent v0.95.0 `model_name`); the "Lemezek
állapota" card row label now prefers the device model ("TOSHIBA MQ04ABF100") over the raw storage
name/UUID, falling back to Name (+ speed hint) on an older agent or a modelless disk. With agent
v0.95.0 the system SSD and the USB drive now carry real SMART, so the card shows real verdicts
(Rendben) with human labels instead of "Nincs adat" on a raw UUID. Additive; old-agent payloads render
exactly as before. Test `TestDiskDisplayLabel_PrefersModel` (red-proof: drop the fallback → A4 fails).
### v0.170.0 — Root → Indítópult; gofmt normalization; stale-note fix (2026-07-25)
- **`/` is now the Indítópult** (operator ruling, reversing the v0.163.0 landing choice). `GET /` 302s
+4 -3
View File
@@ -1012,9 +1012,10 @@ type ThinPoolFill struct {
// The SATA set (reallocated/pending/offline-uncorrectable) and the NVMe set
// (critical_warning/media_errors/percentage_used) are both carried; a device populates only its own.
type SmartSummary struct {
Health string `json:"health"` // PASSED | FAILING | UNKNOWN
TemperatureC *int `json:"temperature_c"`
PowerOnHours *int `json:"power_on_hours"`
Health string `json:"health"` // PASSED | FAILING | UNKNOWN
ModelName *string `json:"model_name,omitempty"` // smartctl device model (agent v0.95.0+); nil on older agents
TemperatureC *int `json:"temperature_c"`
PowerOnHours *int `json:"power_on_hours"`
// SATA attributes.
ReallocatedSectors *int `json:"reallocated_sectors"`
PendingSectors *int `json:"pending_sectors"`
+5
View File
@@ -75,6 +75,11 @@ func isPhysicalDisk(d agentapi.DiskInfo) bool {
// diskDisplayLabel is the customer-facing disk label (PVE name + a Hungarian speed hint when known).
func diskDisplayLabel(d agentapi.DiskInfo) string {
// Prefer the device model (agent v0.95.0) over the raw storage name/UUID — a customer reads
// "TOSHIBA MQ04ABF100", not "47a3361a-…". Falls back to Name (+ speed hint) on an older agent.
if d.Smart != nil && d.Smart.ModelName != nil && *d.Smart.ModelName != "" {
return *d.Smart.ModelName
}
switch d.Class {
case "fast":
return d.Name + " (gyors)"
@@ -167,3 +167,27 @@ func TestCachedDisks_TTL(t *testing.T) {
t.Errorf("two fetches within the TTL should call the agent once, got %d", calls)
}
}
func sptr(s string) *string { return &s }
// v0.171.0: the card label prefers the device model (agent v0.95.0) over the raw name/UUID; it falls
// back to Name (+ speed hint) on an older agent or a modelless disk.
// Red-proof: drop the fallback (always return ModelName) → the nil-model/old-agent cases return "" and
// TestDiskDisplayLabel_PrefersModel fails (A4 — old-payload tolerance).
func TestDiskDisplayLabel_PrefersModel(t *testing.T) {
withModel := agentapi.DiskInfo{Name: "47a3361a-uuid", Class: "slow",
Smart: &agentapi.SmartSummary{Health: agentapi.SmartPassed, ModelName: sptr("TOSHIBA MQ04ABF100")}}
if got := diskDisplayLabel(withModel); got != "TOSHIBA MQ04ABF100" {
t.Errorf("label = %q, want the model name", got)
}
// A4: an old (v0.94.0) agent carries no model → Name (+ speed hint), byte-identical to before.
oldAgent := agentapi.DiskInfo{Name: "local", Class: "fast",
Smart: &agentapi.SmartSummary{Health: agentapi.SmartUnknown}}
if got := diskDisplayLabel(oldAgent); got != "local (gyors)" {
t.Errorf("old-agent label = %q, want 'local (gyors)'", got)
}
// No SMART at all → bare Name.
if got := diskDisplayLabel(agentapi.DiskInfo{Name: "sdb"}); got != "sdb" {
t.Errorf("nil-smart label = %q, want 'sdb'", got)
}
}