fix(collector): surface RAID/HBA controller cards from Storage.StorageControllers[]

The RAID controller (XFusion XC170-M-8i / Broadcom SAS3808) never appeared
in inventory at all: it isn't listed in any Chassis/Systems PCIeDevices
collection on this BMC, and its dedicated Board resource link 404s (id
contains parentheses, same class of bug as the OCP NIC fixed earlier). Its
full identity -- model, firmware, BDF, vendor/device IDs -- was sitting
unread in the Storage resource's embedded StorageControllers[] array the
whole time.

Added parseStorageControllerPCIeDevice + collectStorageControllers to read
that array and surface the controller as a PCIeDevice entry, merged into
the existing pcie_devices list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-08-18 14:30:56 +03:00
co-authored by Claude Sonnet 5
parent 1e4ec513e1
commit 6599ab49c2
4 changed files with 176 additions and 0 deletions
+90
View File
@@ -3978,6 +3978,96 @@ func TestParseGPUWithSupplementalDocs_ResolvesModelWhenOnlySlotLabelPresent(t *t
}
}
// TestParseStorageControllerPCIeDevice_XFusionRAIDCard reproduces the G5500
// V7 case: the RAID/HBA controller card is never exposed as its own
// PCIeDevice or Board resource (the Board link 404s on an id containing
// parentheses), but its full identity is embedded in
// Storage.StorageControllers[]. Without reading that array, the RAID
// controller never appears in inventory at all.
func TestParseStorageControllerPCIeDevice_XFusionRAIDCard(t *testing.T) {
ctrl := map[string]interface{}{
"CardManufacturer": "XFUSION",
"CardModel": "XC170-M-8i",
"Manufacturer": "Broadcom",
"Model": nil,
"Name": "RAID Card1(XC170-M-8i) Controller",
"FirmwareVersion": "5.340.01-4227",
"PartNumber": "0302Y204",
"SerialNumber": nil,
"Status": map[string]interface{}{"State": "Enabled"},
"Oem": map[string]interface{}{
"xFusion": map[string]interface{}{
"BDF": "0000:25:02.0",
"VenderID": "0x1000",
"DeviceID": "0x10e6",
"Type": "SAS3808iMR",
},
},
}
dev := parseStorageControllerPCIeDevice(ctrl)
if dev.Slot != "XC170-M-8i" {
t.Errorf("expected slot XC170-M-8i, got %q", dev.Slot)
}
if dev.Manufacturer != "Broadcom" {
t.Errorf("expected manufacturer Broadcom, got %q", dev.Manufacturer)
}
if dev.Model != "XC170-M-8i" {
t.Errorf("expected model XC170-M-8i, got %q", dev.Model)
}
if dev.BDF != "0000:25:02.0" {
t.Errorf("expected BDF 0000:25:02.0, got %q", dev.BDF)
}
if dev.VendorID != 0x1000 || dev.DeviceID != 0x10e6 {
t.Errorf("expected vendor/device 0x1000/0x10e6, got %#x/%#x", dev.VendorID, dev.DeviceID)
}
if dev.PartNumber != "0302Y204" {
t.Errorf("expected part number 0302Y204, got %q", dev.PartNumber)
}
if dev.DeviceClass != "RAIDController" {
t.Errorf("expected device class RAIDController, got %q", dev.DeviceClass)
}
}
// TestReplayCollectStorageControllers_SurfacesRAIDCardMissingFromPCIeTree
// covers the end-to-end replay path: the RAID controller is only reachable
// via Systems/1/Storage's embedded StorageControllers[] array, never via
// Chassis/Systems PCIeDevices collections (those don't list it on this BMC).
func TestReplayCollectStorageControllers_SurfacesRAIDCardMissingFromPCIeTree(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/Storages/RAIDStorage0"},
},
},
"/redfish/v1/Systems/1/Storages/RAIDStorage0": map[string]interface{}{
"Id": "RAIDStorage0",
"StorageControllers": []interface{}{
map[string]interface{}{
"CardManufacturer": "XFUSION",
"CardModel": "XC170-M-8i",
"Manufacturer": "Broadcom",
"PartNumber": "0302Y204",
"Oem": map[string]interface{}{
"xFusion": map[string]interface{}{
"BDF": "0000:25:02.0",
"VenderID": "0x1000",
"DeviceID": "0x10e6",
},
},
},
},
},
}}
got := r.collectStorageControllers("/redfish/v1/Systems/1")
if len(got) != 1 {
t.Fatalf("expected exactly 1 RAID controller, got %+v", got)
}
if got[0].Model != "XC170-M-8i" {
t.Fatalf("expected XC170-M-8i, got %+v", got[0])
}
}
func TestFirmwareInventoryDeviceName_PrefersIDForGenericSoftwareInventory(t *testing.T) {
doc := map[string]interface{}{
"Id": "HGX_FW_NVSwitch_0",