refactor: unified ingest pipeline + modular Redfish profile framework

Implement the full architectural plan: unified ingest.Service entry point
for archive and Redfish payloads, modular redfishprofile package with
composable profiles (generic, ami-family, msi, supermicro, dell,
hgx-topology), score-based profile matching with fallback expansion mode,
and profile-driven acquisition/analysis plans.

Vendor-specific logic moved out of common executors and into profile hooks.
GPU chassis lookup strategies and known storage recovery collections
(IntelVROC/HA-RAID/MRVL) now live in ResolvedAnalysisPlan, populated by
profiles at analysis time. Replay helpers read from the plan; no hardcoded
path lists remain in generic code.

Also splits redfish_replay.go into domain modules (gpu, storage, inventory,
fru, profiles) and adds full fixture/matcher/directive test coverage
including Dell, AMI, unknown-vendor fallback, and deterministic ordering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-03-18 08:48:58 +03:00
parent d8d3d8c524
commit d650a6ba1c
45 changed files with 5231 additions and 1011 deletions

View File

@@ -11,9 +11,14 @@ import (
"testing"
"time"
"git.mchus.pro/mchus/logpile/internal/collector/redfishprofile"
"git.mchus.pro/mchus/logpile/internal/models"
)
func testAnalysisPlan(d redfishprofile.AnalysisDirectives) redfishprofile.ResolvedAnalysisPlan {
return redfishprofile.ResolvedAnalysisPlan{Directives: d}
}
func TestRedfishConnectorCollect(t *testing.T) {
mux := http.NewServeMux()
register := func(path string, payload interface{}) {
@@ -1422,6 +1427,12 @@ func TestRecoverCriticalRedfishDocsPlanB_RetriesMembersFromExistingCollection(t
[]string{"/redfish/v1/Chassis/1/Drives"},
rawTree,
fetchErrs,
redfishprofile.AcquisitionTuning{
RecoveryPolicy: redfishprofile.AcquisitionRecoveryPolicy{
EnableCriticalCollectionMemberRetry: true,
EnableCriticalSlowProbe: true,
},
},
nil,
)
if recovered == 0 {
@@ -1474,7 +1485,12 @@ func TestRecoverCriticalRedfishDocsPlanB_RetriesMembersFromSystemMemoryCollectio
dimmPath: `Get "https://example/redfish/v1/Systems/1/Memory/CPU1_C1D1": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`,
}
criticalPaths := redfishCriticalEndpoints([]string{systemPath}, nil, nil)
plan := redfishprofile.BuildAcquisitionPlan(redfishprofile.MatchSignals{})
match := redfishprofile.MatchProfiles(redfishprofile.MatchSignals{})
resolved := redfishprofile.ResolveAcquisitionPlan(match, plan, redfishprofile.DiscoveredResources{
SystemPaths: []string{systemPath},
}, redfishprofile.MatchSignals{})
criticalPaths := resolved.CriticalPaths
hasMemoryPath := false
for _, p := range criticalPaths {
if p == memoryPath {
@@ -1495,6 +1511,12 @@ func TestRecoverCriticalRedfishDocsPlanB_RetriesMembersFromSystemMemoryCollectio
criticalPaths,
rawTree,
fetchErrs,
redfishprofile.AcquisitionTuning{
RecoveryPolicy: redfishprofile.AcquisitionRecoveryPolicy{
EnableCriticalCollectionMemberRetry: true,
EnableCriticalSlowProbe: true,
},
},
nil,
)
if recovered == 0 {
@@ -1508,6 +1530,50 @@ func TestRecoverCriticalRedfishDocsPlanB_RetriesMembersFromSystemMemoryCollectio
}
}
func TestRecoverCriticalRedfishDocsPlanB_SkipsMemberRetryWithoutRecoveryPolicy(t *testing.T) {
t.Setenv("LOGPILE_REDFISH_CRITICAL_COOLDOWN", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_SLOW_GAP", "0s")
t.Setenv("LOGPILE_REDFISH_CRITICAL_PLANB_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_RETRIES", "1")
t.Setenv("LOGPILE_REDFISH_CRITICAL_BACKOFF", "0s")
const memoryPath = "/redfish/v1/Systems/1/Memory"
const dimmPath = "/redfish/v1/Systems/1/Memory/CPU1_C1D1"
rawTree := map[string]interface{}{
memoryPath: map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": dimmPath},
},
},
}
fetchErrs := map[string]string{
dimmPath: `Get "https://example/redfish/v1/Systems/1/Memory/CPU1_C1D1": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`,
}
c := NewRedfishConnector()
recovered := c.recoverCriticalRedfishDocsPlanB(
context.Background(),
http.DefaultClient,
Request{},
"https://example",
[]string{memoryPath},
rawTree,
fetchErrs,
redfishprofile.AcquisitionTuning{},
nil,
)
if recovered != 0 {
t.Fatalf("expected no recovery without recovery policy, got %d", recovered)
}
if _, ok := rawTree[dimmPath]; ok {
t.Fatalf("did not expect recovered DIMM doc for %s", dimmPath)
}
if _, ok := fetchErrs[dimmPath]; !ok {
t.Fatalf("expected DIMM fetch error for %s to remain", dimmPath)
}
}
func TestReplayCollectStorage_ProbesSupermicroNVMeDiskBayWhenCollectionEmpty(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems": map[string]interface{}{
@@ -1551,7 +1617,7 @@ func TestReplayCollectStorage_ProbesSupermicroNVMeDiskBayWhenCollectionEmpty(t *
},
}}
got := r.collectStorage("/redfish/v1/Systems/1")
got := r.collectStorage("/redfish/v1/Systems/1", testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableSupermicroNVMeBackplane: true}))
if len(got) != 1 {
t.Fatalf("expected one drive from direct Disk.Bay probe, got %d", len(got))
}
@@ -1563,6 +1629,70 @@ func TestReplayCollectStorage_ProbesSupermicroNVMeDiskBayWhenCollectionEmpty(t *
}
}
func TestReplayCollectStorage_SkipsEnclosureRecoveryWhenDirectiveDisabled(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/Storage": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/1"},
},
},
"/redfish/v1/Systems/1/Storage/1": map[string]interface{}{
"Links": map[string]interface{}{
"Enclosures": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Enclosures/1"},
},
},
},
"/redfish/v1/Enclosures/1/Drives": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Enclosures/1/Drives/Drive1"},
},
},
"/redfish/v1/Enclosures/1/Drives/Drive1": map[string]interface{}{
"Id": "Drive1",
"Name": "Drive1",
"Model": "INTEL SSD",
"SerialNumber": "ENCLOSURE-DRIVE-001",
"Protocol": "SATA",
"MediaType": "SSD",
},
}}
got := r.collectStorage("/redfish/v1/Systems/1", testAnalysisPlan(redfishprofile.AnalysisDirectives{}))
if len(got) != 0 {
t.Fatalf("expected no enclosure recovery when directive is off, got %d", len(got))
}
}
func TestReplayCollectStorage_UsesKnownControllerRecoveryWhenEnabled(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Systems/1/Storage/IntelVROC/Drives": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Storage/IntelVROC/Drives/1"},
},
},
"/redfish/v1/Systems/1/Storage/IntelVROC/Drives/1": map[string]interface{}{
"Id": "1",
"Name": "Drive1",
"Model": "VROC SSD",
"SerialNumber": "VROC-001",
"Protocol": "NVMe",
"MediaType": "SSD",
},
}}
got := r.collectStorage("/redfish/v1/Systems/1", redfishprofile.ResolvedAnalysisPlan{
Directives: redfishprofile.AnalysisDirectives{EnableKnownStorageControllerRecovery: true},
KnownStorageDriveCollections: []string{"/Storage/IntelVROC/Drives"},
})
if len(got) != 1 {
t.Fatalf("expected one drive from known controller recovery, got %d", len(got))
}
if got[0].SerialNumber != "VROC-001" {
t.Fatalf("unexpected serial %q", got[0].SerialNumber)
}
}
func TestReplayCollectGPUs_DoesNotCollapseOnPlaceholderSerialAndSkipsNIC(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
@@ -1610,7 +1740,7 @@ func TestReplayCollectGPUs_DoesNotCollapseOnPlaceholderSerialAndSkipsNIC(t *test
},
}}
got := r.collectGPUs(nil, []string{"/redfish/v1/Chassis/1"})
got := r.collectGPUs(nil, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected 2 GPUs (two H200 cards), got %d", len(got))
}
@@ -1681,7 +1811,7 @@ func TestReplayCollectGPUs_FromGraphicsControllers(t *testing.T) {
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil)
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected 2 GPUs from GraphicsControllers, got %d", len(got))
}
@@ -1714,7 +1844,7 @@ func TestReplayCollectGPUs_DedupUsesRedfishPathBeforeHeuristics(t *testing.T) {
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil)
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected both GPUs to be kept by unique redfish path, got %d", len(got))
}
@@ -1834,6 +1964,83 @@ func TestReplayRedfishFromRawPayloads_AddsMissingServerModelWarning(t *testing.T
}
}
func TestReplayRedfishFromRawPayloads_StoresAnalysisProfilesMetadata(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
"/redfish/v1": map[string]interface{}{
"Vendor": "AMI",
"Product": "AMI Redfish",
"Systems": map[string]interface{}{"@odata.id": "/redfish/v1/Systems"},
"Chassis": map[string]interface{}{"@odata.id": "/redfish/v1/Chassis"},
"Managers": map[string]interface{}{"@odata.id": "/redfish/v1/Managers"},
},
"/redfish/v1/Systems": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1"},
},
},
"/redfish/v1/Systems/1": map[string]interface{}{
"Manufacturer": "Micro-Star International Co., Ltd.",
"Model": "CG290",
},
"/redfish/v1/Chassis": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1"},
},
},
"/redfish/v1/Chassis/1": map[string]interface{}{
"Manufacturer": "Micro-Star International Co., Ltd.",
"Model": "CG290",
},
"/redfish/v1/Managers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Managers/1"},
},
},
"/redfish/v1/Managers/1": map[string]interface{}{
"Id": "1",
},
},
}
got, err := ReplayRedfishFromRawPayloads(raw, nil)
if err != nil {
t.Fatalf("replay failed: %v", err)
}
meta, ok := got.RawPayloads["redfish_analysis_profiles"].(map[string]any)
if !ok {
t.Fatalf("expected redfish_analysis_profiles metadata")
}
if meta["mode"] != redfishprofile.ModeMatched {
t.Fatalf("expected matched mode, got %#v", meta["mode"])
}
profiles, ok := meta["profiles"].([]string)
if !ok {
t.Fatalf("expected []string profiles, got %T", meta["profiles"])
}
foundMSI := false
for _, profile := range profiles {
if profile == "msi" {
foundMSI = true
break
}
}
if !foundMSI {
t.Fatalf("expected msi in applied profiles, got %v", profiles)
}
planMeta, ok := got.RawPayloads["redfish_analysis_plan"].(map[string]any)
if !ok {
t.Fatalf("expected redfish_analysis_plan metadata")
}
directives, ok := planMeta["directives"].(map[string]any)
if !ok {
t.Fatalf("expected directives map in redfish_analysis_plan")
}
if directives["generic_graphics_controller_dedup"] != true {
t.Fatalf("expected generic_graphics_controller_dedup directive, got %#v", directives["generic_graphics_controller_dedup"])
}
}
func TestReplayRedfishFromRawPayloads_AddsDriveFetchWarning(t *testing.T) {
raw := map[string]any{
"redfish_tree": map[string]interface{}{
@@ -1934,7 +2141,7 @@ func TestReplayCollectGPUs_SkipsModelOnlyDuplicateFromGraphicsControllers(t *tes
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil)
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, nil, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 2 {
t.Fatalf("expected 2 GPUs without generic duplicate, got %d", len(got))
}
@@ -1945,6 +2152,48 @@ func TestReplayCollectGPUs_SkipsModelOnlyDuplicateFromGraphicsControllers(t *tes
}
}
func TestReplayCollectGPUs_KeepsModelOnlyGraphicsDuplicateWhenDirectiveDisabled(t *testing.T) {
r := redfishSnapshotReader{tree: map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/4"},
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/9"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/4": map[string]interface{}{
"Id": "4",
"Name": "PCIeCard4",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654225094493",
},
"/redfish/v1/Chassis/1/PCIeDevices/9": map[string]interface{}{
"Id": "9",
"Name": "PCIeCard9",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "1654425002635",
},
"/redfish/v1/Systems/1/GraphicsControllers": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/GraphicsControllers/GPU0"},
},
},
"/redfish/v1/Systems/1/GraphicsControllers/GPU0": map[string]interface{}{
"Id": "GPU0",
"Name": "H200-SXM5-141G",
"Model": "H200-SXM5-141G",
"Manufacturer": "NVIDIA",
"SerialNumber": "N/A",
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{}))
if len(got) != 3 {
t.Fatalf("expected model-only graphics duplicate to remain when directive is off, got %d", len(got))
}
}
func TestApplyBoardInfoFallbackFromDocs_SkipsComponentProductNames(t *testing.T) {
board := models.BoardInfo{
SerialNumber: "23E100051",
@@ -2129,7 +2378,7 @@ func TestReplayCollectGPUs_DropsModelOnlyPlaceholderWhenConcreteDiscoveredLater(
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"})
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 1 {
t.Fatalf("expected generic graphics placeholder to be dropped, got %d GPUs", len(got))
}
@@ -2169,7 +2418,7 @@ func TestReplayCollectGPUs_MergesGraphicsSerialIntoConcretePCIeGPU(t *testing.T)
},
}}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"})
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 1 {
t.Fatalf("expected merged single GPU row, got %d", len(got))
}
@@ -2227,7 +2476,7 @@ func TestReplayCollectGPUs_MergesAmbiguousSameModelByOrder(t *testing.T) {
}
r := redfishSnapshotReader{tree: tree}
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"})
got := r.collectGPUs([]string{"/redfish/v1/Systems/1"}, []string{"/redfish/v1/Chassis/1"}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != len(pcieIDs) {
t.Fatalf("expected %d merged GPUs, got %d", len(pcieIDs), len(got))
}
@@ -2358,8 +2607,8 @@ func TestCollectGPUsFromProcessors_SupermicroHGX(t *testing.T) {
}
systemPaths := []string{"/redfish/v1/Systems/HGX_Baseboard_0"}
gpus := r.collectGPUs(systemPaths, chassisPaths)
gpus = r.collectGPUsFromProcessors(systemPaths, chassisPaths, gpus)
gpus := r.collectGPUs(systemPaths, chassisPaths, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
gpus = r.collectGPUsFromProcessors(systemPaths, chassisPaths, gpus, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableProcessorGPUFallback: true}))
if len(gpus) != 2 {
var slots []string
@@ -2370,6 +2619,110 @@ func TestCollectGPUsFromProcessors_SupermicroHGX(t *testing.T) {
}
}
func TestCollectGPUsFromProcessors_SupermicroHGXUsesChassisAliasSerial(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/1/PCIeDevices": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1": map[string]interface{}{
"Id": "GPU1",
"Name": "GPU1",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
"SerialNumber": "SN-ALIAS-001",
"PCIeFunctions": map[string]interface{}{
"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions",
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1"},
},
},
"/redfish/v1/Chassis/1/PCIeDevices/GPU1/PCIeFunctions/1": map[string]interface{}{
"FunctionId": "1",
"ClassCode": "0x030200",
},
"/redfish/v1/Chassis/HGX_GPU_SXM_1": map[string]interface{}{
"Id": "HGX_GPU_SXM_1",
"SerialNumber": "SN-ALIAS-001",
},
"/redfish/v1/Systems/HGX_Baseboard_0/Processors": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1"},
},
},
"/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1": map[string]interface{}{
"Id": "GPU_SXM_1",
"Name": "Processor",
"ProcessorType": "GPU",
"Model": "NVIDIA H200",
"Manufacturer": "NVIDIA",
},
}
r := redfishSnapshotReader{tree: tree}
chassisPaths := []string{
"/redfish/v1/Chassis/1",
"/redfish/v1/Chassis/HGX_GPU_SXM_1",
}
systemPaths := []string{"/redfish/v1/Systems/HGX_Baseboard_0"}
gpus := r.collectGPUs(systemPaths, chassisPaths, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
gpus = r.collectGPUsFromProcessors(systemPaths, chassisPaths, gpus, redfishprofile.ResolvedAnalysisPlan{
Directives: redfishprofile.AnalysisDirectives{EnableProcessorGPUFallback: true, EnableProcessorGPUChassisAlias: true},
ProcessorGPUChassisLookupModes: []string{"hgx-alias"},
})
if len(gpus) != 1 {
t.Fatalf("expected alias serial dedupe to keep 1 gpu, got %d", len(gpus))
}
if gpus[0].SerialNumber != "SN-ALIAS-001" {
t.Fatalf("expected serial from aliased chassis, got %q", gpus[0].SerialNumber)
}
}
func TestCollectGPUsFromProcessors_MSIUsesIndexedChassisLookup(t *testing.T) {
tree := map[string]interface{}{
"/redfish/v1/Chassis/GPU1": map[string]interface{}{
"Id": "GPU1",
"SerialNumber": "MSI-SN-001",
},
"/redfish/v1/Systems/1/Processors": map[string]interface{}{
"Members": []interface{}{
map[string]interface{}{"@odata.id": "/redfish/v1/Systems/1/Processors/GPU_SXM_1"},
},
},
"/redfish/v1/Systems/1/Processors/GPU_SXM_1": map[string]interface{}{
"Id": "GPU_SXM_1",
"Name": "Processor",
"ProcessorType": "GPU",
"Model": "NVIDIA RTX PRO 6000 Blackwell",
"Manufacturer": "NVIDIA",
},
}
r := redfishSnapshotReader{tree: tree}
gpus := r.collectGPUsFromProcessors(
[]string{"/redfish/v1/Systems/1"},
[]string{"/redfish/v1/Chassis/GPU1"},
nil,
redfishprofile.ResolvedAnalysisPlan{
Directives: redfishprofile.AnalysisDirectives{EnableProcessorGPUFallback: true, EnableMSIProcessorGPUChassisLookup: true},
ProcessorGPUChassisLookupModes: []string{"msi-index"},
},
)
if len(gpus) != 1 {
t.Fatalf("expected one gpu, got %d", len(gpus))
}
if gpus[0].SerialNumber != "MSI-SN-001" {
t.Fatalf("expected serial from MSI indexed chassis lookup, got %q", gpus[0].SerialNumber)
}
}
// TestReplayCollectGPUs_DedupCrossChassisSerial verifies that the same GPU
// appearing under two Chassis PCIeDevice trees (e.g. Chassis/1/PCIeDevices/GPU1
// and Chassis/HGX_GPU_SXM_1/PCIeDevices/GPU_SXM_1) is deduplicated to one entry
@@ -2428,7 +2781,7 @@ func TestReplayCollectGPUs_DedupCrossChassisSerial(t *testing.T) {
got := r.collectGPUs(nil, []string{
"/redfish/v1/Chassis/1",
"/redfish/v1/Chassis/HGX_GPU_SXM_1",
})
}, testAnalysisPlan(redfishprofile.AnalysisDirectives{EnableGenericGraphicsControllerDedup: true}))
if len(got) != 1 {
var slots []string
for _, g := range got {
@@ -2565,32 +2918,42 @@ func TestRedfishSnapshotBranchKey(t *testing.T) {
}
func TestShouldPostProbeCollectionPath(t *testing.T) {
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Sensors") {
var tuning redfishprofile.AcquisitionTuning
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Sensors", tuning) {
t.Fatalf("expected sensors collection to be skipped by default")
}
if shouldPostProbeCollectionPath("/redfish/v1/Systems/1/Storage/RAID/Drives", tuning) {
t.Fatalf("expected drives collection to be skipped without profile policy")
}
tuning.PostProbePolicy.EnableNumericCollectionProbe = true
t.Setenv("LOGPILE_REDFISH_SENSOR_POSTPROBE", "1")
if !shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Sensors") {
if !shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Sensors", tuning) {
t.Fatalf("expected sensors collection to be post-probed when enabled")
}
if !shouldPostProbeCollectionPath("/redfish/v1/Systems/1/Storage/RAID/Drives") {
if !shouldPostProbeCollectionPath("/redfish/v1/Systems/1/Storage/RAID/Drives", tuning) {
t.Fatalf("expected drives collection to be post-probed")
}
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Boards/BOARD1") {
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Boards/BOARD1", tuning) {
t.Fatalf("expected board member resource to be skipped from post-probe")
}
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Assembly/Oem/COMMONb/COMMONbAssembly/1") {
if shouldPostProbeCollectionPath("/redfish/v1/Chassis/1/Assembly/Oem/COMMONb/COMMONbAssembly/1", tuning) {
t.Fatalf("expected assembly member resource to be skipped from post-probe")
}
}
func TestShouldAdaptivePostProbeCollectionPath(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PostProbePolicy: redfishprofile.AcquisitionPostProbePolicy{
EnableNumericCollectionProbe: true,
},
}
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) {
if shouldAdaptivePostProbeCollectionPath("/redfish/v1/Systems/1/EthernetInterfaces", withExplicitNamedMembers, tuning) {
t.Fatalf("expected explicit non-numeric members to skip adaptive post-probe")
}
@@ -2600,14 +2963,18 @@ func TestShouldAdaptivePostProbeCollectionPath(t *testing.T) {
map[string]interface{}{"@odata.id": "/redfish/v1/Chassis/1/PCIeDevices/2"},
},
}
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/PCIeDevices", withNumericMembers) {
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/PCIeDevices", withNumericMembers, tuning) {
t.Fatalf("expected numeric members to allow adaptive post-probe")
}
withoutMembers := map[string]interface{}{"Name": "Drives"}
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/Drives", withoutMembers) {
if !shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/Drives", withoutMembers, tuning) {
t.Fatalf("expected missing members to allow adaptive post-probe")
}
if shouldAdaptivePostProbeCollectionPath("/redfish/v1/Chassis/1/Drives", withoutMembers, redfishprofile.AcquisitionTuning{}) {
t.Fatalf("expected post-probe to stay disabled without profile policy")
}
}
func TestShouldAdaptiveNVMeProbe(t *testing.T) {
@@ -2627,6 +2994,15 @@ func TestShouldAdaptiveNVMeProbe(t *testing.T) {
}
func TestRedfishAdaptivePrefetchTargets(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PrefetchPolicy: redfishprofile.AcquisitionPrefetchPolicy{
IncludeSuffixes: []string{
"/Memory",
"/Processors",
"/Storage",
},
},
}
candidates := []string{
"/redfish/v1/Systems/1/Memory",
"/redfish/v1/Systems/1/Processors",
@@ -2651,7 +3027,7 @@ func TestRedfishAdaptivePrefetchTargets(t *testing.T) {
"/redfish/v1/Systems/1/Storage/Volumes": "status 404 from /redfish/v1/Systems/1/Storage/Volumes: not found",
}
got := redfishAdaptivePrefetchTargets(candidates, rawTree, fetchErrs)
got := redfishAdaptivePrefetchTargets(redfishPrefetchTargets(candidates, tuning), rawTree, fetchErrs)
joined := strings.Join(got, "\n")
for _, wanted := range []string{
"/redfish/v1/Systems/1/Memory",
@@ -2666,12 +3042,16 @@ func TestRedfishAdaptivePrefetchTargets(t *testing.T) {
}
}
func TestRedfishSnapshotPrioritySeeds_DefaultSkipsNoisyBranches(t *testing.T) {
seeds := redfishSnapshotPrioritySeeds(
[]string{"/redfish/v1/Systems/1"},
[]string{"/redfish/v1/Chassis/1"},
[]string{"/redfish/v1/Managers/1"},
)
func TestResolveAcquisitionPlan_DefaultSkipsNoisyBranches(t *testing.T) {
signals := redfishprofile.MatchSignals{}
match := redfishprofile.MatchProfiles(signals)
plan := redfishprofile.BuildAcquisitionPlan(signals)
resolved := redfishprofile.ResolveAcquisitionPlan(match, plan, redfishprofile.DiscoveredResources{
SystemPaths: []string{"/redfish/v1/Systems/1"},
ChassisPaths: []string{"/redfish/v1/Chassis/1"},
ManagerPaths: []string{"/redfish/v1/Managers/1"},
}, signals)
seeds := resolved.SeedPaths
joined := strings.Join(seeds, "\n")
for _, noisy := range []string{
"/redfish/v1/Fabrics",
@@ -2697,7 +3077,43 @@ func TestRedfishSnapshotPrioritySeeds_DefaultSkipsNoisyBranches(t *testing.T) {
}
}
func TestShouldPrefetchCriticalPath_UsesPrefetchPolicy(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PrefetchPolicy: redfishprofile.AcquisitionPrefetchPolicy{
IncludeSuffixes: []string{"/Storage", "/Oem/Public"},
ExcludeContains: []string{"/Assembly"},
},
}
if !shouldPrefetchCriticalPath("/redfish/v1/Systems/1/Storage", tuning) {
t.Fatal("expected storage path to be prefetched when included by policy")
}
if !shouldPrefetchCriticalPath("/redfish/v1/Systems/1/Oem/Public", tuning) {
t.Fatal("expected OEM public path to be prefetched when included by policy")
}
if shouldPrefetchCriticalPath("/redfish/v1/Chassis/1/Assembly", tuning) {
t.Fatal("expected excluded path to skip prefetch")
}
if shouldPrefetchCriticalPath("/redfish/v1/Chassis/1/Power", redfishprofile.AcquisitionTuning{}) {
t.Fatal("expected empty prefetch policy to disable suffix-based prefetch")
}
}
func TestRedfishPrefetchTargets_FilterNoisyBranches(t *testing.T) {
tuning := redfishprofile.AcquisitionTuning{
PrefetchPolicy: redfishprofile.AcquisitionPrefetchPolicy{
IncludeSuffixes: []string{
"/Memory",
"/Oem/Public/FRU",
"/Drives",
"/NetworkProtocol",
},
ExcludeContains: []string{
"/Backplanes",
"/Sensors",
"/LogServices",
},
},
}
critical := []string{
"/redfish/v1/Systems/1",
"/redfish/v1/Systems/1/Memory",
@@ -2708,7 +3124,7 @@ func TestRedfishPrefetchTargets_FilterNoisyBranches(t *testing.T) {
"/redfish/v1/Managers/1/LogServices",
"/redfish/v1/Managers/1/NetworkProtocol",
}
got := redfishPrefetchTargets(critical)
got := redfishPrefetchTargets(critical, tuning)
joined := strings.Join(got, "\n")
for _, wanted := range []string{
"/redfish/v1/Systems/1",