collector/redfish: make prefetch/post-probe adaptive with metrics

This commit is contained in:
2026-02-28 19:05:34 +03:00
parent fe5da1dbd7
commit 2fa4a1235a
2 changed files with 319 additions and 38 deletions
+83
View File
@@ -1634,6 +1634,89 @@ func TestShouldPostProbeCollectionPath(t *testing.T) {
}
}
func TestShouldAdaptivePostProbeCollectionPath(t *testing.T) {
withExplicitNamedMembers := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/EthernetInterfaces/NIC-0-0"},
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/EthernetInterfaces/NIC-0-1"},
},
}
if shouldAdaptivePostProbeCollectionPath("/redfish/v1/Systems/1/EthernetInterfaces", withExplicitNamedMembers) {
t.Fatalf("expected explicit non-numeric members to skip adaptive post-probe")
}
withNumericMembers := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/1"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/2"},
},
}
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/PCIeDevices", withNumericMembers) {
t.Fatalf("expected numeric members to allow adaptive post-probe")
}
withoutMembers := map[string]interface{}{"Name": "Drives"}
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/Drives", withoutMembers) {
t.Fatalf("expected missing members to allow adaptive post-probe")
}
}
func TestShouldAdaptiveNVMeProbe(t *testing.T) {
withMembers := map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/Drives/OB01"},
},
}
if shouldAdaptiveNVMeProbe(withMembers) {
t.Fatalf("expected drives collection with explicit members to skip NVMe probe")
}
withoutMembers := map[string]interface{}{"Name": "Drives"}
if !shouldAdaptiveNVMeProbe(withoutMembers) {
t.Fatalf("expected drives collection without members to allow NVMe probe")
}
}
func TestRedfishAdaptivePrefetchTargets(t *testing.T) {
candidates := []string{
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Processors",
"/redfish/v1/Systems/1/Storage",
}
rawTree := map[string]interface{}{
"/redfish/v1/Systems/1/Memory": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Memory/DIMM1"},
},
},
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/1"},
},
},
}
fetchErrs := map[string]string{
"/redfish/v1/Systems/1/Memory/DIMM1": "Get \"https://bmc/redfish/v1/Systems/1/Memory/DIMM1\": context deadline exceeded",
"/redfish/v1/Systems/1/Storage/1": "status 404 from /redfish/v1/Systems/1/Storage/1: not found",
"/redfish/v1/Systems/1/Processors": "Get \"https://bmc/redfish/v1/Systems/1/Processors\": context deadline exceeded",
"/redfish/v1/Systems/1/Storage/Volumes": "status 404 from /redfish/v1/Systems/1/Storage/Volumes: not found",
}
got := redfishAdaptivePrefetchTargets(candidates, rawTree, fetchErrs)
joined := strings.Join(got, "\n")
for _, wanted := range []string{
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Processors",
} {
if !strings.Contains(joined, wanted) {
t.Fatalf("expected adaptive prefetch target %q", wanted)
}
}
if strings.Contains(joined, "/redfish/v1/Systems/1/Storage") {
t.Fatalf("expected storage with only non-retryable missing members to be skipped")
}
}
func TestRedfishSnapshotPrioritySeeds_DefaultSkipsNoisyBranches(t *testing.T) {
seeds := redfishSnapshotPrioritySeeds(
[]string{"/redfish/v1/Systems/1"},