feat(exporter): collect and export storage.vendor_id/device_id (contract v2.13)
Add PCI Vendor ID / Device ID to hardware.storage[] per the updated Reanimator ingest contract, mirroring the existing pcie_devices[] fields. Populated for Redfish-collected NVMe drives (live + TSR replay, via linked PCIeFunctions) and for Inspur (from asset.json's own PcieInfo[], joined by PcieSlot). Also fixes canonicalDevicesForExport dropping the fields when converting Storage into the canonical HardwareDevice list used by the actual export path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
063587958e
commit
399eca5f49
+19
@@ -162,6 +162,23 @@ func ParseAssetJSON(content []byte, pcieSlotDeviceNames map[int]string, pcieSlot
|
||||
}
|
||||
}
|
||||
|
||||
// Build a PcieSlot -> (VendorId, DeviceId) map from asset.json's own PcieInfo section,
|
||||
// used below to enrich NVMe HddInfo entries (BMC does not populate vendor/device IDs
|
||||
// directly on HddInfo).
|
||||
pcieSlotVendorID := make(map[int]int, len(asset.PcieInfo))
|
||||
pcieSlotDeviceID := make(map[int]int, len(asset.PcieInfo))
|
||||
for _, pcie := range asset.PcieInfo {
|
||||
if pcie.PcieSlot <= 0 {
|
||||
continue
|
||||
}
|
||||
if pcie.VendorId > 0 {
|
||||
pcieSlotVendorID[pcie.PcieSlot] = pcie.VendorId
|
||||
}
|
||||
if pcie.DeviceId > 0 {
|
||||
pcieSlotDeviceID[pcie.PcieSlot] = pcie.DeviceId
|
||||
}
|
||||
}
|
||||
|
||||
// Parse storage info
|
||||
for _, hdd := range asset.HddInfo {
|
||||
slot := normalizeAssetHDDSlot(hdd.LocationString, hdd.Location, hdd.DiskInterfaceType)
|
||||
@@ -207,6 +224,8 @@ func ParseAssetJSON(content []byte, pcieSlotDeviceNames map[int]string, pcieSlot
|
||||
Slot: slot,
|
||||
Type: storageType,
|
||||
Model: modelName,
|
||||
VendorID: pcieSlotVendorID[hdd.PcieSlot],
|
||||
DeviceID: pcieSlotDeviceID[hdd.PcieSlot],
|
||||
SizeGB: hdd.Capacity,
|
||||
SerialNumber: serial,
|
||||
Manufacturer: manufacturer,
|
||||
|
||||
@@ -44,6 +44,45 @@ func TestParseAssetJSON_HddSlotFallbackAndPresence(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAssetJSON_HddEnrichedWithPcieVendorDeviceID(t *testing.T) {
|
||||
content := []byte(`{
|
||||
"HddInfo": [
|
||||
{
|
||||
"PresentBitmap": [1],
|
||||
"SerialNumber": "NVME-SN-1",
|
||||
"Manufacturer": "",
|
||||
"ModelName": "",
|
||||
"FirmwareVersion": "",
|
||||
"Capacity": 7680,
|
||||
"Location": 1,
|
||||
"DiskInterfaceType": 5,
|
||||
"MediaType": 1,
|
||||
"LocationString": "OB01",
|
||||
"PcieSlot": 12
|
||||
}
|
||||
],
|
||||
"PcieInfo": [
|
||||
{
|
||||
"VendorId": 32902,
|
||||
"DeviceId": 62305,
|
||||
"PcieSlot": 12,
|
||||
"LocString": "OB01"
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
hw, err := ParseAssetJSON(content, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseAssetJSON failed: %v", err)
|
||||
}
|
||||
if len(hw.Storage) != 1 {
|
||||
t.Fatalf("expected 1 storage entry, got %d", len(hw.Storage))
|
||||
}
|
||||
if hw.Storage[0].VendorID != 32902 || hw.Storage[0].DeviceID != 62305 {
|
||||
t.Fatalf("expected vendor_id/device_id enriched from PcieInfo, got vendor=%d device=%d", hw.Storage[0].VendorID, hw.Storage[0].DeviceID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDiskBackplaneInfo_PopulatesOnlyMissingPresentDrives(t *testing.T) {
|
||||
text := `RESTful diskbackplane info:
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user