mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
fix(monitoring): prefer agent source for physical disk SMART metrics
When a Proxmox node has an agent installed, SMART/temperature metrics are written by the host agent under the agent's disk source ID. But BuildMetricsTarget preferred the Proxmox source first, and Proxmox API does not expose detailed SMART data. The mismatch meant the frontend queried a metrics key that nothing writes, so disk metrics appeared empty. Move the Agent source check ahead of Proxmox/TrueNAS for ResourceTypePhysicalDisk, mirroring the existing pattern for ResourceTypeAgent where agent source already wins over platform sources. When a disk has a serial number, it is used as the canonical metric ID regardless of source (PreferredPhysicalDiskMetricID), so the reorder only affects disks without serials — exactly the case where source priority determines the key. Refs #1487
This commit is contained in:
parent
028e8c8df2
commit
f676dea097
2 changed files with 65 additions and 5 deletions
|
|
@ -98,6 +98,18 @@ func BuildMetricsTarget(resource Resource, sourceTargets []SourceTarget) *Metric
|
|||
return &MetricsTarget{ResourceType: "storage", ResourceID: st.SourceID}
|
||||
}
|
||||
case ResourceTypePhysicalDisk:
|
||||
// The agent source must win over platform sources for physical
|
||||
// disks: SMART/temperature metrics are written by the host agent
|
||||
// under the agent's disk source ID (HostSMARTDiskSourceID in
|
||||
// monitor_agents.go). Proxmox API does not expose detailed SMART
|
||||
// data, so preferring its source ID here would point store readers
|
||||
// at a key nothing writes and disk metrics would appear empty
|
||||
// (GitHub issue #1487).
|
||||
if st, ok := bySource[SourceAgent]; ok {
|
||||
if resourceID := PhysicalDiskMetaMetricID(resource.PhysicalDisk, st.SourceID); resourceID != "" {
|
||||
return &MetricsTarget{ResourceType: "disk", ResourceID: resourceID}
|
||||
}
|
||||
}
|
||||
if st, ok := bySource[SourceProxmox]; ok {
|
||||
if resourceID := PhysicalDiskMetaMetricID(resource.PhysicalDisk, st.SourceID); resourceID != "" {
|
||||
return &MetricsTarget{ResourceType: "disk", ResourceID: resourceID}
|
||||
|
|
@ -108,11 +120,6 @@ func BuildMetricsTarget(resource Resource, sourceTargets []SourceTarget) *Metric
|
|||
return &MetricsTarget{ResourceType: "disk", ResourceID: resourceID}
|
||||
}
|
||||
}
|
||||
if st, ok := bySource[SourceAgent]; ok {
|
||||
if resourceID := PhysicalDiskMetaMetricID(resource.PhysicalDisk, st.SourceID); resourceID != "" {
|
||||
return &MetricsTarget{ResourceType: "disk", ResourceID: resourceID}
|
||||
}
|
||||
}
|
||||
case ResourceTypePod:
|
||||
if st, ok := bySource[SourceK8s]; ok {
|
||||
if resourceID := CanonicalKubernetesPodMetricID(st.SourceID); resourceID != "" {
|
||||
|
|
|
|||
|
|
@ -372,6 +372,59 @@ func TestBuildMetricsTarget_UsesCanonicalPhysicalDiskMetricIDForTrueNAS(t *testi
|
|||
}
|
||||
}
|
||||
|
||||
func TestBuildMetricsTarget_AgentSourceWinsForPhysicalDiskMetrics(t *testing.T) {
|
||||
// When a Proxmox node has an agent, the agent writes SMART/temperature
|
||||
// metrics under its own disk source ID. The metrics target must resolve
|
||||
// to the agent source ID, not the Proxmox source ID, or store readers
|
||||
// query a key nothing writes and disk metrics appear empty (#1487).
|
||||
// Without a serial, the source-specific fallback ID differs between
|
||||
// sources, so source priority determines which key is returned.
|
||||
target := BuildMetricsTarget(
|
||||
Resource{
|
||||
Type: ResourceTypePhysicalDisk,
|
||||
PhysicalDisk: &PhysicalDiskMeta{
|
||||
DiskType: "nvme",
|
||||
},
|
||||
},
|
||||
[]SourceTarget{
|
||||
{Source: SourceProxmox, SourceID: "pve-node:nvme0n1"},
|
||||
{Source: SourceAgent, SourceID: "agent-uuid:nvme0n1"},
|
||||
},
|
||||
)
|
||||
if target == nil {
|
||||
t.Fatal("BuildMetricsTarget() returned nil")
|
||||
}
|
||||
if target.ResourceType != "disk" {
|
||||
t.Fatalf("ResourceType = %q, want disk", target.ResourceType)
|
||||
}
|
||||
if target.ResourceID != "agent-uuid:nvme0n1" {
|
||||
t.Fatalf("ResourceID = %q, want agent-uuid:nvme0n1 (agent source must win for physical disk SMART metrics)", target.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMetricsTarget_PhysicalDiskSerialWinsOverAllSources(t *testing.T) {
|
||||
// When the disk has a serial number, it becomes the metric ID
|
||||
// regardless of source, so the priority order doesn't matter.
|
||||
target := BuildMetricsTarget(
|
||||
Resource{
|
||||
Type: ResourceTypePhysicalDisk,
|
||||
PhysicalDisk: &PhysicalDiskMeta{
|
||||
Serial: "SAMSUNG-SSD-870-500GB",
|
||||
},
|
||||
},
|
||||
[]SourceTarget{
|
||||
{Source: SourceProxmox, SourceID: "pve-node:sda"},
|
||||
{Source: SourceAgent, SourceID: "agent-uuid:sda"},
|
||||
},
|
||||
)
|
||||
if target == nil {
|
||||
t.Fatal("BuildMetricsTarget() returned nil")
|
||||
}
|
||||
if target.ResourceID != "SAMSUNG-SSD-870-500GB" {
|
||||
t.Fatalf("ResourceID = %q, want SAMSUNG-SSD-870-500GB (serial should be used as canonical ID)", target.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMetricsTarget_UsesCanonicalAppMetricIDForTrueNAS(t *testing.T) {
|
||||
target := BuildMetricsTarget(
|
||||
Resource{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue