fix(inspur): read RESTful FRU info and float fans_power from component.log
Diffing an NF5280M6 BMC dump against its BEE-SP live-CD bundle found two blind spots in the combined-component.log onekeylog layout (no devicefrusdr.log / asset.json): - board manufacturer/product/part/uuid empty and stats.fru 0: the "RESTful FRU info:" JSON block was never parsed. New component_fru.go (ParseComponentLogFRU) flattens it to []models.FRUInfo, prefers the product-area system serial over the board PCB serial, and sets BoardInfo.UUID from system_uuid. Wired as a fallback only when result.FRU is still empty. - zero fan sensors: FanRESTInfo.FansPower was int but this firmware writes "fans_power": 12.000000, so json.Unmarshal of the whole fan block failed. Changed to float64. Also included: SOL smartd SCSI/SAS device-line parsing and diagnose.go gofmt from concurrent work on the same live-CD-diff task. See ADL-064. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011LffAvostt3uMkiUbVUiyM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ab8636da04
commit
2fa0f78f94
+129
@@ -109,6 +109,101 @@ RESTful fan`
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkAdapterInfo_PerFunctionFromBIOSPCIeTable(t *testing.T) {
|
||||
text := `RESTful Network Adapter info:
|
||||
{
|
||||
"sys_adapters": [
|
||||
{
|
||||
"id": 0, "present": 1, "slot": 13,
|
||||
"pcie_bus": 152, "pcie_dev": 0, "pcie_func": 0,
|
||||
"vendor_id": 32902, "device_id": 5409,
|
||||
"vendor": "Intel Corporation", "model": "ENFI1100-T4",
|
||||
"status": "OK", "port_num": 4,
|
||||
"ports": [
|
||||
{ "id": 1, "mac_addr": "9C:C2:C4:65:5A:99" },
|
||||
{ "id": 2, "mac_addr": "9C:C2:C4:65:5A:9A" },
|
||||
{ "id": 3, "mac_addr": "9C:C2:C4:65:5A:9B" },
|
||||
{ "id": 4, "mac_addr": "9C:C2:C4:65:5A:9C" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
RESTful fan
|
||||
PCIE_2_INFO: Device B.D.F=0x98.0x0.0x0, RootPort B.D.F=0x97.0x2.0x0, VendorID:0x8086, DevieID:0x1521
|
||||
PCIE_2_INFO: Device B.D.F=0x98.0x0.0x1, RootPort B.D.F=0x97.0x2.0x0, VendorID:0x8086, DevieID:0x1521
|
||||
PCIE_2_INFO: Device B.D.F=0x98.0x0.0x2, RootPort B.D.F=0x97.0x2.0x0, VendorID:0x8086, DevieID:0x1521
|
||||
PCIE_2_INFO: Device B.D.F=0x98.0x0.0x3, RootPort B.D.F=0x97.0x2.0x0, VendorID:0x8086, DevieID:0x1521
|
||||
`
|
||||
|
||||
hw := &models.HardwareConfig{}
|
||||
parseNetworkAdapterInfo(text, hw)
|
||||
|
||||
if len(hw.NetworkAdapters) != 4 {
|
||||
t.Fatalf("expected 4 per-function NIC records, got %d: %+v", len(hw.NetworkAdapters), hw.NetworkAdapters)
|
||||
}
|
||||
want := map[string]string{
|
||||
"0000:98:00.0": "9C:C2:C4:65:5A:99",
|
||||
"0000:98:00.1": "9C:C2:C4:65:5A:9A",
|
||||
"0000:98:00.2": "9C:C2:C4:65:5A:9B",
|
||||
"0000:98:00.3": "9C:C2:C4:65:5A:9C",
|
||||
}
|
||||
for _, na := range hw.NetworkAdapters {
|
||||
mac, ok := want[na.Slot]
|
||||
if !ok {
|
||||
t.Fatalf("unexpected slot %q", na.Slot)
|
||||
}
|
||||
if na.BDF != na.Slot {
|
||||
t.Errorf("slot %q: BDF should equal slot, got %q", na.Slot, na.BDF)
|
||||
}
|
||||
if len(na.MACAddresses) != 1 || na.MACAddresses[0] != mac {
|
||||
t.Errorf("slot %q: want MAC %s, got %v", na.Slot, mac, na.MACAddresses)
|
||||
}
|
||||
if na.DeviceID != 5409 {
|
||||
t.Errorf("slot %q: device id not carried, got %d", na.Slot, na.DeviceID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkAdapterInfo_EnrichesExistingPCIeRecords(t *testing.T) {
|
||||
text := `RESTful Network Adapter info:
|
||||
{
|
||||
"sys_adapters": [
|
||||
{
|
||||
"id": 0, "present": 1, "slot": 13,
|
||||
"pcie_bus": 101, "pcie_dev": 0, "pcie_func": 0,
|
||||
"vendor_id": 5555, "device_id": 4119,
|
||||
"vendor": "Mellanox Technologies", "model": "MCX512A-ACAT",
|
||||
"fw_ver": "16.35.3006", "status": "OK", "port_num": 2,
|
||||
"ports": [
|
||||
{ "id": 1, "mac_addr": "58:A2:E1:7D:49:D4" },
|
||||
{ "id": 2, "mac_addr": "58:A2:E1:7D:49:D5" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
RESTful fan`
|
||||
|
||||
hw := &models.HardwareConfig{
|
||||
PCIeDevices: []models.PCIeDevice{
|
||||
{BDF: "0000:65:00.0", VendorID: 5555, DeviceID: 4119, DeviceClass: "NetworkController"},
|
||||
{BDF: "0000:65:00.1", VendorID: 5555, DeviceID: 4119, DeviceClass: "NetworkController"},
|
||||
},
|
||||
}
|
||||
parseNetworkAdapterInfo(text, hw)
|
||||
|
||||
if len(hw.NetworkAdapters) != 0 {
|
||||
t.Fatalf("expected no new NIC records (existing PCIe enriched in place), got %d", len(hw.NetworkAdapters))
|
||||
}
|
||||
for _, d := range hw.PCIeDevices {
|
||||
if d.Model != "MCX512A-ACAT" {
|
||||
t.Errorf("%s: model not enriched, got %q", d.BDF, d.Model)
|
||||
}
|
||||
if d.Firmware != "16.35.3006" {
|
||||
t.Errorf("%s: firmware not enriched, got %q", d.BDF, d.Firmware)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseComponentLogSensors_ExtractsFanBackplaneAndPSUSummary(t *testing.T) {
|
||||
text := `RESTful PSU info:
|
||||
{
|
||||
@@ -181,6 +276,40 @@ BMC`
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseComponentLogSensors_FloatFansPower guards a regression where a
|
||||
// float "fans_power" ("12.000000") made json.Unmarshal of the whole fan block
|
||||
// fail, dropping every fan reading (0 fans vs the live-CD's 8 for the same host).
|
||||
func TestParseComponentLogSensors_FloatFansPower(t *testing.T) {
|
||||
text := `RESTful fan info:
|
||||
{ "fans": [
|
||||
{ "id": 0, "fan_name": "System Fan0 Front", "present": "OK", "status": "OK", "status_str": "OK", "speed_rpm": 2947, "speed_percent": 23, "max_speed_rpm": 20000, "fan_model": "8056" },
|
||||
{ "id": 1, "fan_name": "System Fan0 Rear", "present": "OK", "status": "OK", "status_str": "OK", "speed_rpm": 2520, "speed_percent": 23, "max_speed_rpm": 20000, "fan_model": "8056" }
|
||||
], "fans_power": 12.000000 }
|
||||
RESTful diskbackplane info:
|
||||
[]
|
||||
BMC`
|
||||
|
||||
sensors := ParseComponentLogSensors([]byte(text))
|
||||
var fans, fanPower int
|
||||
for _, s := range sensors {
|
||||
switch s.Name {
|
||||
case "System Fan0 Front", "System Fan0 Rear":
|
||||
fans++
|
||||
case "Fans_Power":
|
||||
fanPower++
|
||||
if s.Value != 12 {
|
||||
t.Errorf("Fans_Power value = %v, want 12", s.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if fans != 2 {
|
||||
t.Fatalf("expected 2 fan sensors, got %d (float fans_power broke the parse)", fans)
|
||||
}
|
||||
if fanPower != 1 {
|
||||
t.Errorf("expected 1 Fans_Power sensor, got %d", fanPower)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseHDDInfo_MergesIntoExistingStorage(t *testing.T) {
|
||||
text := `RESTful HDD info:
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user