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
@@ -143,6 +143,45 @@ func (r redfishSnapshotReader) collectStorage(systemPath string, plan redfishpro
return dedupeStorage(out)
}
// collectStorageControllers surfaces RAID/HBA controller cards from the
// Storage.StorageControllers[] embedded array as PCIeDevice inventory
// entries. Some BMCs (e.g. xFusion) never expose the controller as its own
// PCIeDevice or Board resource -- the Board link can even 404 on IDs
// containing parentheses -- so without reading this array the RAID
// controller never appears in inventory even though its model/firmware/BDF
// identity is fully present here.
func (r redfishSnapshotReader) collectStorageControllers(systemPath string) []models.PCIeDevice {
var out []models.PCIeDevice
storageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/Storage"))
seen := make(map[string]struct{})
for _, member := range storageMembers {
controllers, ok := member["StorageControllers"].([]interface{})
if !ok {
continue
}
for _, ctrlAny := range controllers {
ctrl, ok := ctrlAny.(map[string]interface{})
if !ok {
continue
}
dev := parseStorageControllerPCIeDevice(ctrl)
if isUnidentifiablePCIeDevice(dev) {
continue
}
key := firstNonEmpty(dev.SerialNumber, dev.BDF, dev.Slot)
if key == "" {
continue
}
if _, dup := seen[key]; dup {
continue
}
seen[key] = struct{}{}
out = append(out, dev)
}
}
return out
}
func (r redfishSnapshotReader) collectStorageVolumes(systemPath string, plan redfishprofile.ResolvedAnalysisPlan) []models.StorageVolume {
var out []models.StorageVolume
storageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/Storage"))