963 lines
30 KiB
Go
963 lines
30 KiB
Go
package h3c
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
"git.mchus.pro/mchus/logpile/internal/parser"
|
|
)
|
|
|
|
func TestDetectH3C_GenerationRouting(t *testing.T) {
|
|
g5 := &G5Parser{}
|
|
g6 := &G6Parser{}
|
|
|
|
g5Files := []parser.ExtractedFile{
|
|
{Path: "bmc/pack.info", Content: []byte("STARTTIME:0")},
|
|
{Path: "static/FRUInfo.ini", Content: []byte("[Baseboard]\nBoard Manufacturer=H3C\n")},
|
|
{Path: "static/hardware_info.ini", Content: []byte("[Processors: Processor 1]\nModel: Intel Xeon\n")},
|
|
{Path: "static/hardware.info", Content: []byte("[Disk_0_Front_NA]\nSerialNumber=DISK-0\n")},
|
|
{Path: "static/firmware_version.ini", Content: []byte("[System board]\nBIOS Version: 5.59\n")},
|
|
{Path: "user/test1.csv", Content: []byte("Record Time Stamp,DescInfo\n2025-01-01 00:00:00,foo\n")},
|
|
}
|
|
if gotG5, gotG6 := g5.Detect(g5Files), g6.Detect(g5Files); gotG5 <= gotG6 {
|
|
t.Fatalf("expected G5 confidence > G6 for G5 sample, got g5=%d g6=%d", gotG5, gotG6)
|
|
}
|
|
|
|
g6Files := []parser.ExtractedFile{
|
|
{Path: "bmc/pack.info", Content: []byte("STARTTIME:0")},
|
|
{Path: "static/FRUInfo.ini", Content: []byte("[Baseboard]\nBoard Manufacturer=H3C\n")},
|
|
{Path: "static/board_info.ini", Content: []byte("[System board]\nBoardMfr=H3C\n")},
|
|
{Path: "static/firmware_version.json", Content: []byte(`{"BIOS":{"Firmware Name":"BIOS","Firmware Version":"6.10"}}`)},
|
|
{Path: "static/CPUDetailInfo.xml", Content: []byte("<Root><CPU1><Model>X</Model></CPU1></Root>")},
|
|
{Path: "static/MemoryDetailInfo.xml", Content: []byte("<Root><DIMM1><Name>A0</Name></DIMM1></Root>")},
|
|
{Path: "user/Sel.json", Content: []byte(`{"Id":1}`)},
|
|
}
|
|
if gotG5, gotG6 := g5.Detect(g6Files), g6.Detect(g6Files); gotG6 <= gotG5 {
|
|
t.Fatalf("expected G6 confidence > G5 for G6 sample, got g5=%d g6=%d", gotG5, gotG6)
|
|
}
|
|
}
|
|
|
|
func TestParseH3CG6_RaidAndNVMeEnrichment(t *testing.T) {
|
|
p := &G6Parser{}
|
|
files := []parser.ExtractedFile{
|
|
{
|
|
Path: "static/storage_disk.ini",
|
|
Content: []byte(`[Disk_000]
|
|
DiskSlotDesc=Front0
|
|
Present=YES
|
|
SerialNumber=SER-0
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/raid.json",
|
|
Content: []byte(`{
|
|
"RaidConfig": {
|
|
"CtrlInfo": [
|
|
{
|
|
"CtrlSlot": 1,
|
|
"CtrlName": "RAID-LSI-9560",
|
|
"LDInfo": [
|
|
{
|
|
"LDID": "0",
|
|
"LDName": "VD0",
|
|
"RAIDLevel": "1",
|
|
"CapacityBytes": 1000000000,
|
|
"Status": "Optimal"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}`),
|
|
},
|
|
{
|
|
Path: "static/Storage_RAID-LSI-9560-LP-8i-4GB[1].txt",
|
|
Content: []byte(`Controller Information
|
|
------------------------------------------------------------------------
|
|
AssetTag : RAID-LSI-9560
|
|
|
|
Logical Device Information
|
|
------------------------------------------------------------------------
|
|
LDID : 0
|
|
Name : VD0
|
|
RAID Level : 1
|
|
CapacityBytes : 1000000000
|
|
Status : Optimal
|
|
|
|
Physical Device Information
|
|
------------------------------------------------------------------------
|
|
ConnectionID : 0
|
|
Position : Front0
|
|
StatusIndicator : OK
|
|
Protocol : SATA
|
|
MediaType : SSD
|
|
Manufacturer : Samsung
|
|
Model : PM893
|
|
Revision : GDC1
|
|
SerialNumber : SER-0
|
|
CapacityBytes : 480000000000
|
|
|
|
ConnectionID : 1
|
|
Position : Front1
|
|
StatusIndicator : OK
|
|
Protocol : SATA
|
|
MediaType : SSD
|
|
Manufacturer : Samsung
|
|
Model : PM893
|
|
Revision : GDC1
|
|
SerialNumber : SER-1
|
|
CapacityBytes : 480000000000
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/NVMe_info.txt",
|
|
Content: []byte(`[NVMe_0]
|
|
Present=YES
|
|
DiskSlotDesc=Front2
|
|
Model=INTEL SSDPE2KX010T8
|
|
SerialNumber=NVME-1
|
|
Firmware=V100
|
|
CapacityBytes=1000204886016
|
|
Interface=NVMe
|
|
Status=OK
|
|
`),
|
|
},
|
|
}
|
|
|
|
result, err := p.Parse(files)
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
if result.Hardware == nil {
|
|
t.Fatalf("expected hardware section")
|
|
}
|
|
|
|
if len(result.Hardware.Volumes) != 1 {
|
|
t.Fatalf("expected 1 volume, got %d", len(result.Hardware.Volumes))
|
|
}
|
|
vol := result.Hardware.Volumes[0]
|
|
if vol.RAIDLevel != "RAID1" {
|
|
t.Fatalf("expected RAID1 level, got %q", vol.RAIDLevel)
|
|
}
|
|
if vol.SizeGB != 1 {
|
|
t.Fatalf("expected 1GB logical volume, got %d", vol.SizeGB)
|
|
}
|
|
|
|
if len(result.Hardware.Storage) != 3 {
|
|
t.Fatalf("expected 3 unique storage devices, got %d", len(result.Hardware.Storage))
|
|
}
|
|
|
|
var front0 *models.Storage
|
|
var nvme *models.Storage
|
|
for i := range result.Hardware.Storage {
|
|
s := &result.Hardware.Storage[i]
|
|
if strings.EqualFold(s.SerialNumber, "SER-0") {
|
|
front0 = s
|
|
}
|
|
if strings.EqualFold(s.SerialNumber, "NVME-1") {
|
|
nvme = s
|
|
}
|
|
}
|
|
if front0 == nil {
|
|
t.Fatalf("expected merged Front0 disk by serial SER-0")
|
|
}
|
|
if front0.Model != "PM893" {
|
|
t.Fatalf("expected Front0 model PM893, got %q", front0.Model)
|
|
}
|
|
if front0.SizeGB != 480 {
|
|
t.Fatalf("expected Front0 size 480GB, got %d", front0.SizeGB)
|
|
}
|
|
if nvme == nil {
|
|
t.Fatalf("expected NVMe disk by serial NVME-1")
|
|
}
|
|
if nvme.Type != "nvme" {
|
|
t.Fatalf("expected nvme type, got %q", nvme.Type)
|
|
}
|
|
}
|
|
|
|
func TestParseH3CG6(t *testing.T) {
|
|
p := &G6Parser{}
|
|
|
|
files := []parser.ExtractedFile{
|
|
{
|
|
Path: "static/FRUInfo.ini",
|
|
Content: []byte(`[Baseboard]
|
|
Board Manufacturer=H3C
|
|
Board Product Name=RS36M2C6SB
|
|
Product Product Name=H3C UniServer R4700 G6
|
|
Product Serial Number=210235A4FYH257000010
|
|
Product Part Number=0235A4FY
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/firmware_version.json",
|
|
Content: []byte(`{
|
|
"BMCP": {"Firmware Name":"HDM","Firmware Version":"1.83","Location":"bmc card","Part Model":"-"},
|
|
"BIOS": {"Firmware Name":"BIOS","Firmware Version":"6.10.53","Location":"system board","Part Model":"-"}
|
|
}`),
|
|
},
|
|
{
|
|
Path: "static/CPUDetailInfo.xml",
|
|
Content: []byte(`<Root>
|
|
<CPU1>
|
|
<Status>Presence</Status>
|
|
<Model>INTEL(R) XEON(R) GOLD 6542Y</Model>
|
|
<ProcessorSpeed>0xb54</ProcessorSpeed>
|
|
<ProcessorMaxSpeed>0x1004</ProcessorMaxSpeed>
|
|
<TotalCores>0x18</TotalCores>
|
|
<TotalThreads>0x30</TotalThreads>
|
|
<SerialNumber>68-5C-81-C1-0E-A3-4E-40</SerialNumber>
|
|
<PPIN>68-5C-81-C1-0E-A3-4E-40</PPIN>
|
|
</CPU1>
|
|
</Root>`),
|
|
},
|
|
{
|
|
Path: "static/MemoryDetailInfo.xml",
|
|
Content: []byte(`<Root>
|
|
<DIMM1>
|
|
<Status>Presence</Status>
|
|
<Name>CPU1_CH1_D0 (A0)</Name>
|
|
<PartNumber>M321R8GA0PB0-CWMXJ</PartNumber>
|
|
<DIMMTech>RDIMM</DIMMTech>
|
|
<SerialNumber>80CE032519135C82ED</SerialNumber>
|
|
<DIMMRanks>0x2</DIMMRanks>
|
|
<DIMMSize>0x10000</DIMMSize>
|
|
<CurFreq>0x1130</CurFreq>
|
|
<MaxFreq>0x15e0</MaxFreq>
|
|
<DIMMSilk>A0</DIMMSilk>
|
|
</DIMM1>
|
|
</Root>`),
|
|
},
|
|
{
|
|
Path: "static/storage_disk.ini",
|
|
Content: []byte(`[Disk_000]
|
|
SerialNumber=S6KLNN0Y516813
|
|
DiskSlotDesc=Front0
|
|
Present=YES
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/net_cfg.ini",
|
|
Content: []byte(`[Network Configuration]
|
|
eth0 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6
|
|
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
|
|
|
|
eth0.2 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6
|
|
inet6 addr: fe80::32c6:d7ff:fe94:54f6/64 Scope:Link
|
|
UP BROADCAST RUNNING MULTICAST MTU:1496 Metric:1
|
|
|
|
eth1 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F5
|
|
inet addr:10.201.129.0 Bcast:10.201.143.255 Mask:255.255.240.0
|
|
inet6 addr: fe80::32c6:d7ff:fe94:54f5/64 Scope:Link
|
|
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
|
|
|
|
lo Link encap:Local Loopback
|
|
inet addr:127.0.0.1 Mask:255.0.0.0
|
|
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/psu_cfg.ini",
|
|
Content: []byte(`[Psu0]
|
|
SN=210231AGUNH257001569
|
|
Max_Power(W)=1600
|
|
Manufacturer=Great Wall
|
|
Power Status=Input Normal, Output Normal
|
|
Present_Status=Present
|
|
Power_ID=1
|
|
Model=GW-CRPS1600D2
|
|
Version=03.02.00
|
|
|
|
[Psu1]
|
|
Manufacturer=Great Wall
|
|
Power_ID=2
|
|
Version=03.02.00
|
|
Power Status=Input Normal, Output Normal
|
|
SN=210231AGUNH257001570
|
|
Model=GW-CRPS1600D2
|
|
Present_Status=Present
|
|
Max_Power(W)=1600
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/hardware_info.ini",
|
|
Content: []byte(`[Ethernet adapters: Port 1]
|
|
Device Type : NIC
|
|
Network Port : Port 1
|
|
Location : PCIE-[1]
|
|
MAC Address : E4:3D:1A:6F:B0:30
|
|
Speed : 8.0GT/s
|
|
Product Name : NIC-BCM957414-F-B-25Gb-2P
|
|
[Ethernet adapters: Port 2]
|
|
Device Type : NIC
|
|
Network Port : Port 2
|
|
Location : PCIE-[1]
|
|
MAC Address : E4:3D:1A:6F:B0:31
|
|
Speed : 8.0GT/s
|
|
Product Name : NIC-BCM957414-F-B-25Gb-2P
|
|
|
|
[PCIe Card: PCIe 1]
|
|
Location : 1
|
|
Product Name : NIC-BCM957414-F-B-25Gb-2P
|
|
Status : Normal
|
|
Vendor ID : 0x14E4
|
|
Device ID : 0x16D7
|
|
Serial Number : NICSN-G6-001
|
|
Part Number : NICPN-G6-001
|
|
Firmware Version : 22.35.1010
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/sensor_info.ini",
|
|
Content: []byte(`Sensor Name | Reading | Unit | Status| Crit low
|
|
Inlet_Temp | 20.000 | degrees C | ok | na
|
|
CPU1_Status | 0x0 | discrete | 0x8080| na
|
|
`),
|
|
},
|
|
{
|
|
Path: "user/Sel.json",
|
|
Content: []byte(`
|
|
{
|
|
"Created": "2025-07-14 03:34:18 UTC+08:00",
|
|
"Severity": "Info",
|
|
"EntryCode": "Asserted",
|
|
"EntryType": "Event",
|
|
"Id": 1,
|
|
"Level": "Info",
|
|
"Message": "Processor Presence detected",
|
|
"SensorName": "CPU1_Status",
|
|
"SensorType": "Processor"
|
|
},
|
|
{
|
|
"Created": "2025-07-14 20:56:45 UTC+08:00",
|
|
"Severity": "Critical",
|
|
"EntryCode": "Asserted",
|
|
"EntryType": "Event",
|
|
"Id": 2,
|
|
"Level": "Critical",
|
|
"Message": "Power Supply AC lost",
|
|
"SensorName": "PSU1_Status",
|
|
"SensorType": "Power Supply"
|
|
}
|
|
`),
|
|
},
|
|
}
|
|
|
|
result, err := p.Parse(files)
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
|
|
if result.Hardware == nil {
|
|
t.Fatalf("expected hardware section")
|
|
}
|
|
if result.Hardware.BoardInfo.Manufacturer != "H3C" {
|
|
t.Fatalf("unexpected board manufacturer: %q", result.Hardware.BoardInfo.Manufacturer)
|
|
}
|
|
if result.Hardware.BoardInfo.ProductName != "H3C UniServer R4700 G6" {
|
|
t.Fatalf("unexpected board product: %q", result.Hardware.BoardInfo.ProductName)
|
|
}
|
|
if result.Hardware.BoardInfo.SerialNumber != "210235A4FYH257000010" {
|
|
t.Fatalf("unexpected board serial: %q", result.Hardware.BoardInfo.SerialNumber)
|
|
}
|
|
|
|
if len(result.Hardware.Firmware) < 2 {
|
|
t.Fatalf("expected firmware entries, got %d", len(result.Hardware.Firmware))
|
|
}
|
|
if len(result.Hardware.CPUs) != 1 {
|
|
t.Fatalf("expected 1 cpu, got %d", len(result.Hardware.CPUs))
|
|
}
|
|
if result.Hardware.CPUs[0].Cores != 24 {
|
|
t.Fatalf("expected 24 cores, got %d", result.Hardware.CPUs[0].Cores)
|
|
}
|
|
|
|
if len(result.Hardware.Memory) != 1 {
|
|
t.Fatalf("expected 1 dimm, got %d", len(result.Hardware.Memory))
|
|
}
|
|
if result.Hardware.Memory[0].SizeMB != 65536 {
|
|
t.Fatalf("expected 65536MB, got %d", result.Hardware.Memory[0].SizeMB)
|
|
}
|
|
|
|
if len(result.Hardware.Storage) != 1 {
|
|
t.Fatalf("expected 1 disk, got %d", len(result.Hardware.Storage))
|
|
}
|
|
if result.Hardware.Storage[0].SerialNumber != "S6KLNN0Y516813" {
|
|
t.Fatalf("unexpected disk serial: %q", result.Hardware.Storage[0].SerialNumber)
|
|
}
|
|
if len(result.Hardware.PowerSupply) != 2 {
|
|
t.Fatalf("expected 2 PSUs from psu_cfg.ini, got %d", len(result.Hardware.PowerSupply))
|
|
}
|
|
if result.Hardware.PowerSupply[0].WattageW == 0 {
|
|
t.Fatalf("expected PSU wattage parsed, got 0")
|
|
}
|
|
|
|
if len(result.Hardware.NetworkAdapters) != 1 {
|
|
t.Fatalf("expected 1 host network adapter from hardware_info.ini, got %d", len(result.Hardware.NetworkAdapters))
|
|
}
|
|
macs := make(map[string]struct{})
|
|
var hostNIC models.NetworkAdapter
|
|
var hostNICFound bool
|
|
for _, nic := range result.Hardware.NetworkAdapters {
|
|
if len(nic.MACAddresses) == 0 {
|
|
t.Fatalf("expected MAC on network adapter %+v", nic)
|
|
}
|
|
for _, mac := range nic.MACAddresses {
|
|
macs[strings.ToLower(mac)] = struct{}{}
|
|
}
|
|
if strings.EqualFold(nic.Slot, "PCIe 1") && strings.Contains(strings.ToLower(nic.Model), "bcm957414") {
|
|
hostNIC = nic
|
|
hostNICFound = true
|
|
}
|
|
}
|
|
if !hostNICFound {
|
|
t.Fatalf("expected host NIC from hardware_info.ini, got %+v", result.Hardware.NetworkAdapters)
|
|
}
|
|
if _, ok := macs["e4:3d:1a:6f:b0:30"]; !ok {
|
|
t.Fatalf("expected host NIC MAC e4:3d:1a:6f:b0:30 in adapters, got %+v", result.Hardware.NetworkAdapters)
|
|
}
|
|
if _, ok := macs["e4:3d:1a:6f:b0:31"]; !ok {
|
|
t.Fatalf("expected host NIC MAC e4:3d:1a:6f:b0:31 in adapters, got %+v", result.Hardware.NetworkAdapters)
|
|
}
|
|
if !strings.Contains(strings.ToLower(hostNIC.Vendor), "broadcom") {
|
|
t.Fatalf("expected host NIC vendor enrichment from Vendor ID, got %q", hostNIC.Vendor)
|
|
}
|
|
if hostNIC.SerialNumber != "NICSN-G6-001" {
|
|
t.Fatalf("expected host NIC serial from PCIe card section, got %q", hostNIC.SerialNumber)
|
|
}
|
|
if hostNIC.PartNumber != "NICPN-G6-001" {
|
|
t.Fatalf("expected host NIC part number from PCIe card section, got %q", hostNIC.PartNumber)
|
|
}
|
|
if hostNIC.Firmware != "22.35.1010" {
|
|
t.Fatalf("expected host NIC firmware from PCIe card section, got %q", hostNIC.Firmware)
|
|
}
|
|
|
|
if len(result.Sensors) != 2 {
|
|
t.Fatalf("expected 2 sensors, got %d", len(result.Sensors))
|
|
}
|
|
if result.Sensors[0].Name != "Inlet_Temp" {
|
|
t.Fatalf("unexpected first sensor: %q", result.Sensors[0].Name)
|
|
}
|
|
|
|
if len(result.Events) != 2 {
|
|
t.Fatalf("expected 2 events, got %d", len(result.Events))
|
|
}
|
|
if result.Events[0].Timestamp.Year() != 2025 || result.Events[0].Timestamp.Month() != 7 {
|
|
t.Fatalf("expected SEL timestamp from payload, got %s", result.Events[0].Timestamp)
|
|
}
|
|
if result.Events[1].Severity != models.SeverityCritical {
|
|
t.Fatalf("expected critical severity for AC lost event, got %q", result.Events[1].Severity)
|
|
}
|
|
}
|
|
|
|
func TestParseH3CG5_PCIeArgumentsEnrichesNonNVMeStorage(t *testing.T) {
|
|
p := &G5Parser{}
|
|
files := []parser.ExtractedFile{
|
|
{
|
|
Path: "static/storage_disk.ini",
|
|
Content: []byte(`[Disk_000]
|
|
DiskSlotDesc=Front slot 3
|
|
Present=YES
|
|
SerialNumber=SAT-03
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/NVMe_info.txt",
|
|
Content: []byte(`[NVMe_0]
|
|
Present=YES
|
|
DiskSlotDesc=Front slot 108
|
|
SerialNumber=NVME-108
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/PCIe_arguments_table.xml",
|
|
Content: []byte(`<root>
|
|
<PCIE100>
|
|
<base_args>
|
|
<type>SSD</type>
|
|
<name>SSD-SATA-960G</name>
|
|
</base_args>
|
|
<type_get_args>
|
|
<bios_args>
|
|
<vendor_id>0x144D</vendor_id>
|
|
</bios_args>
|
|
</type_get_args>
|
|
</PCIE100>
|
|
<PCIE200>
|
|
<base_args>
|
|
<type>SSD</type>
|
|
<name>SSD-3.84T-NVMe-SFF</name>
|
|
</base_args>
|
|
<type_get_args>
|
|
<bios_args>
|
|
<vendor_id>0x144D</vendor_id>
|
|
</bios_args>
|
|
</type_get_args>
|
|
</PCIE200>
|
|
</root>`),
|
|
},
|
|
}
|
|
|
|
result, err := p.Parse(files)
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
if result.Hardware == nil {
|
|
t.Fatalf("expected hardware section")
|
|
}
|
|
|
|
if len(result.Hardware.Storage) != 2 {
|
|
t.Fatalf("expected 2 storage devices, got %d", len(result.Hardware.Storage))
|
|
}
|
|
|
|
var sata *models.Storage
|
|
var nvme *models.Storage
|
|
for i := range result.Hardware.Storage {
|
|
s := &result.Hardware.Storage[i]
|
|
switch s.SerialNumber {
|
|
case "SAT-03":
|
|
sata = s
|
|
case "NVME-108":
|
|
nvme = s
|
|
}
|
|
}
|
|
|
|
if sata == nil {
|
|
t.Fatalf("expected SATA storage SAT-03")
|
|
}
|
|
if sata.Model != "SSD-SATA-960G" {
|
|
t.Fatalf("expected SATA model enrichment from PCIe table, got %q", sata.Model)
|
|
}
|
|
if !strings.Contains(strings.ToLower(sata.Manufacturer), "samsung") {
|
|
t.Fatalf("expected SATA vendor enrichment to Samsung, got %q", sata.Manufacturer)
|
|
}
|
|
|
|
if nvme == nil {
|
|
t.Fatalf("expected NVMe storage NVME-108")
|
|
}
|
|
if nvme.Model != "SSD-3.84T-NVMe-SFF" {
|
|
t.Fatalf("expected NVMe model enrichment from PCIe table, got %q", nvme.Model)
|
|
}
|
|
if !strings.Contains(strings.ToLower(nvme.Manufacturer), "samsung") {
|
|
t.Fatalf("expected NVMe vendor enrichment to Samsung, got %q", nvme.Manufacturer)
|
|
}
|
|
}
|
|
|
|
func TestParseH3CG5_VariantLayout(t *testing.T) {
|
|
p := &G5Parser{}
|
|
|
|
files := []parser.ExtractedFile{
|
|
{
|
|
Path: "static/FRUInfo.ini",
|
|
Content: []byte(`[Baseboard]
|
|
Board Manufacturer=H3C
|
|
Product Product Name=H3C UniServer R4900 G5
|
|
Product Serial Number=02A6AX5231C003VM
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/firmware_version.ini",
|
|
Content: []byte(`[System board]
|
|
BIOS Version : 5.59 V100R001B05D078
|
|
ME Version : 4.4.4.202
|
|
HDM Version : 3.34.01 HDM V100R001B05D078SP01
|
|
CPLD Version : V00C
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/board_cfg.ini",
|
|
Content: []byte(`[Board Type]
|
|
Board Type : R4900 G5
|
|
|
|
[Board Version]
|
|
Board Version : VER.D
|
|
|
|
[Customer ID]
|
|
CustomerID : 255
|
|
|
|
[OEM ID]
|
|
OEM Flag : 1
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/hardware_info.ini",
|
|
Content: []byte(`[Processors: Processor 1]
|
|
Model : Intel(R) Xeon(R) Gold 6342 CPU @ 2.80GHz
|
|
Status : Normal
|
|
Frequency : 2800 MHz
|
|
Cores : 24
|
|
Threads : 48
|
|
L1 Cache : 1920 KB
|
|
L2 Cache : 30720 KB
|
|
L3 Cache : 36864 KB
|
|
CPU PPIN : 49-A9-50-C0-15-9F-2D-DC
|
|
|
|
[Processors: Processor 2]
|
|
Model : Intel(R) Xeon(R) Gold 6342 CPU @ 2.80GHz
|
|
Status : Normal
|
|
Frequency : 2800 MHz
|
|
Cores : 24
|
|
Threads : 48
|
|
CPU PPIN : 49-AC-3D-BF-85-7F-17-58
|
|
|
|
[Memory Details: Dimm Index 0]
|
|
Location : Processor 1
|
|
Channel : 1
|
|
Socket ID : A0
|
|
Status : Normal
|
|
Size : 65536 MB
|
|
Maximum Frequency : 3200 MHz
|
|
Type : DDR4
|
|
Ranks : 2R DIMM
|
|
Technology : RDIMM
|
|
Part Number : M393A8G40AB2-CWE
|
|
Manufacture : Samsung
|
|
Serial Number : S02K0D0243351D7079
|
|
|
|
[Memory Details: Dimm Index 16]
|
|
Location : Processor 2
|
|
Channel : 1
|
|
Socket ID : A0
|
|
Status : Normal
|
|
Size : 65536 MB
|
|
Maximum Frequency : 3200 MHz
|
|
Type : DDR4
|
|
Ranks : 2R DIMM
|
|
Technology : RDIMM
|
|
Part Number : M393A8G40AB2-CWE
|
|
Manufacture : Samsung
|
|
Serial Number : S02K0D0243351D73F0
|
|
|
|
[Ethernet adapters: Port 1]
|
|
Device Type : NIC
|
|
Network Port : Port 1
|
|
Location : PCIE-[1]
|
|
MAC Address : E4:3D:1A:6F:B0:30
|
|
Speed : 8.0GT/s
|
|
Product Name : NIC-BCM957414-F-B-25Gb-2P
|
|
[Ethernet adapters: Port 2]
|
|
Device Type : NIC
|
|
Network Port : Port 2
|
|
Location : PCIE-[1]
|
|
MAC Address : E4:3D:1A:6F:B0:31
|
|
Speed : 8.0GT/s
|
|
Product Name : NIC-BCM957414-F-B-25Gb-2P
|
|
|
|
[Ethernet adapters: Port 1]
|
|
Device Type : NIC
|
|
Network Port : Port 1
|
|
Location : PCIE-[4]
|
|
MAC Address : E8:EB:D3:4F:2E:90
|
|
Speed : 8.0GT/s
|
|
Product Name : NIC-MCX512A-ACAT-2*25Gb-F
|
|
[Ethernet adapters: Port 2]
|
|
Device Type : NIC
|
|
Network Port : Port 2
|
|
Location : PCIE-[4]
|
|
MAC Address : E8:EB:D3:4F:2E:91
|
|
Speed : 8.0GT/s
|
|
Product Name : NIC-MCX512A-ACAT-2*25Gb-F
|
|
|
|
[PCIe Card: PCIe 1]
|
|
Location : 1
|
|
Product Name : NIC-BCM957414-F-B-25Gb-2P
|
|
Status : Normal
|
|
Vendor ID : 0x14E4
|
|
Device ID : 0x16D7
|
|
Serial Number : NICSN-G5-001
|
|
Part Number : NICPN-G5-001
|
|
Firmware Version : 21.80.1
|
|
|
|
[PCIe Card: PCIe 4]
|
|
Location : 4
|
|
Product Name : NIC-MCX512A-ACAT-2*25Gb-F
|
|
Status : Normal
|
|
Vendor ID : 0x15B3
|
|
Device ID : 0x1017
|
|
Serial Number : NICSN-G5-004
|
|
Part Number : NICPN-G5-004
|
|
Firmware Version : 28.33.15
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/hardware.info",
|
|
Content: []byte(`[Disk_0_Front_NA]
|
|
Present=YES
|
|
SlotNum=0
|
|
FrontOrRear=Front
|
|
SerialNumber=22443C4EE184
|
|
|
|
[Nvme_Front slot 21]
|
|
Present=YES
|
|
NvmePhySlot=Front slot 21
|
|
SlotNum=121
|
|
SerialNumber=NVME-21
|
|
|
|
[Nvme_255_121]
|
|
Present=YES
|
|
SlotNum=121
|
|
SerialNumber=NVME-21
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/raid.json",
|
|
Content: []byte(`{
|
|
"RAIDCONFIG": {
|
|
"Ctrl info": [
|
|
{
|
|
"CtrlDevice Slot": 3,
|
|
"CtrlDevice Name": "AVAGO MegaRAID SAS 9460-8i",
|
|
"LDInfo": [
|
|
{
|
|
"LD ID": 0,
|
|
"LD_name": "SystemRAID",
|
|
"RAID_level(RAID 0,RAID 1,RAID 5,RAID 6,RAID 00,RAID 10,RAID 50,RAID 60)": "RAID1",
|
|
"Logical_capicity(per 512byte)": 936640512
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"CtrlDevice Slot": 6,
|
|
"CtrlDevice Name": "MegaRAID 9560-16i 8GB",
|
|
"LDInfo": [
|
|
{
|
|
"LD ID": 0,
|
|
"LD_name": "DataRAID",
|
|
"RAID_level(RAID 0,RAID 1,RAID 5,RAID 6,RAID 00,RAID 10,RAID 50,RAID 60)": "RAID50",
|
|
"Logical_capicity(per 512byte)": 90004783104
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}`),
|
|
},
|
|
{
|
|
Path: "static/Raid_BP_Conf_Info.ini",
|
|
Content: []byte(`[BP Information]
|
|
Description | BP TYPE | I2cPort | BpConnectorNum | FrontOrRear | Node Num | DiskSlotRange |
|
|
8SFF SAS/SATA | BP_G5_8SFF | AUX_1 | ~ | ~ | ~ | ~ |
|
|
8SFF SAS/SATA | BP_G5_8SFF | AUX_2 | ~ | ~ | ~ | ~ |
|
|
8SFF SAS/SATA | BP_G5_8SFF | AUX_3 | ~ | ~ | ~ | ~ |
|
|
|
|
[RAID Information]
|
|
PCIE SLOT | RAID SAS_NUM |
|
|
3 | 2 |
|
|
6 | 4 |
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/PCIe_arguments_table.xml",
|
|
Content: []byte(`<root>
|
|
<PCIE100>
|
|
<base_args>
|
|
<type>SSD</type>
|
|
<name>SSD-1.92T/3.84T-NVMe-EV-SFF-sa</name>
|
|
</base_args>
|
|
<type_get_args>
|
|
<bios_args>
|
|
<vendor_id>0x144D</vendor_id>
|
|
</bios_args>
|
|
</type_get_args>
|
|
</PCIE100>
|
|
</root>`),
|
|
},
|
|
{
|
|
Path: "static/psu_cfg.ini",
|
|
Content: []byte(`[Active / Standby configuration]
|
|
Power ID : 1
|
|
Present Status : Present
|
|
Cold Status : Active Power
|
|
Model : DPS-1300AB-6 R
|
|
SN : 210231ACT9H232000080
|
|
Max Power(W) : 1300
|
|
|
|
Power ID : 2
|
|
Present Status : Present
|
|
Cold Status : Active Power
|
|
Model : DPS-1300AB-6 R
|
|
SN : 210231ACT9H232000079
|
|
Max Power(W) : 1300
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/net_cfg.ini",
|
|
Content: []byte(`[Network Configuration]
|
|
eth0 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6
|
|
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
|
|
|
|
eth0.2 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F6
|
|
inet6 addr: fe80::32c6:d7ff:fe94:54f6/64 Scope:Link
|
|
UP BROADCAST RUNNING MULTICAST MTU:1496 Metric:1
|
|
|
|
eth1 Link encap:Ethernet HWaddr 30:C6:D7:94:54:F5
|
|
inet addr:10.201.129.0 Bcast:10.201.143.255 Mask:255.255.240.0
|
|
inet6 addr: fe80::32c6:d7ff:fe94:54f5/64 Scope:Link
|
|
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
|
|
|
|
lo Link encap:Local Loopback
|
|
inet addr:127.0.0.1 Mask:255.0.0.0
|
|
UP LOOPBACK RUNNING MTU:65536 Metric:1
|
|
`),
|
|
},
|
|
{
|
|
Path: "static/smartdata/Front0/first_date_analysis.txt",
|
|
Content: []byte(`The Current System Time Is 2023_09_22_14_19_39
|
|
Model Info: ATA Micron_5300_MTFD
|
|
Serial Number: 22443C4EE184
|
|
`),
|
|
},
|
|
{
|
|
Path: "user/test1.csv",
|
|
Content: []byte(`Record Time Stamp,Severity Level,Severity Level ID,SensorTypeStr,SensorName,Event Dir,Event Occurred Time,DescInfo,Explanation,Suggestion
|
|
2025-04-01 08:50:13,Minor,0x1,NA,NA,NA,2025-04-01 08:50:13,"SSH login failed from IP: 10.200.10.121 user: admin"," "," "
|
|
Pre-Init,Info,0x0,Management Subsystem Health,Health,Assertion event,Pre-Init,"Management controller off-line"," "," "
|
|
2025-04-01 08:51:10,Major,0x2,Power Supply,PSU1_Status,Assertion event,2025-04-01 08:51:10,"Power Supply AC lost"," "," "
|
|
`),
|
|
},
|
|
}
|
|
|
|
result, err := p.Parse(files)
|
|
if err != nil {
|
|
t.Fatalf("parse failed: %v", err)
|
|
}
|
|
if result.Hardware == nil {
|
|
t.Fatalf("expected hardware section")
|
|
}
|
|
|
|
if len(result.Hardware.CPUs) != 2 {
|
|
t.Fatalf("expected 2 CPUs from hardware_info.ini, got %d", len(result.Hardware.CPUs))
|
|
}
|
|
if result.Hardware.CPUs[0].FrequencyMHz != 2800 {
|
|
t.Fatalf("expected CPU frequency 2800MHz, got %d", result.Hardware.CPUs[0].FrequencyMHz)
|
|
}
|
|
|
|
if len(result.Hardware.Memory) != 2 {
|
|
t.Fatalf("expected 2 DIMMs from hardware_info.ini, got %d", len(result.Hardware.Memory))
|
|
}
|
|
if result.Hardware.Memory[0].SizeMB != 65536 {
|
|
t.Fatalf("expected DIMM size 65536MB, got %d", result.Hardware.Memory[0].SizeMB)
|
|
}
|
|
|
|
if len(result.Hardware.Firmware) < 4 {
|
|
t.Fatalf("expected firmware entries from firmware_version.ini, got %d", len(result.Hardware.Firmware))
|
|
}
|
|
if result.Hardware.BoardInfo.Version == "" {
|
|
t.Fatalf("expected board version from board_cfg.ini")
|
|
}
|
|
if !strings.Contains(result.Hardware.BoardInfo.Description, "CustomerID: 255") {
|
|
t.Fatalf("expected board description enrichment from board_cfg.ini, got %q", result.Hardware.BoardInfo.Description)
|
|
}
|
|
|
|
if len(result.Hardware.Storage) != 2 {
|
|
t.Fatalf("expected 2 unique storage devices from hardware.info, got %d", len(result.Hardware.Storage))
|
|
}
|
|
var nvmeFound bool
|
|
var diskModelEnriched bool
|
|
for _, s := range result.Hardware.Storage {
|
|
if s.SerialNumber == "NVME-21" {
|
|
nvmeFound = true
|
|
if s.Type != "nvme" {
|
|
t.Fatalf("expected NVME-21 type nvme, got %q", s.Type)
|
|
}
|
|
if !strings.Contains(strings.ToLower(s.Manufacturer), "samsung") {
|
|
t.Fatalf("expected NVME vendor enrichment to Samsung, got %q", s.Manufacturer)
|
|
}
|
|
if s.Model != "SSD-1.92T/3.84T-NVMe-EV-SFF-sa" {
|
|
t.Fatalf("expected NVME model enrichment from PCIe table, got %q", s.Model)
|
|
}
|
|
}
|
|
if s.SerialNumber == "22443C4EE184" && strings.Contains(s.Model, "Micron") {
|
|
diskModelEnriched = true
|
|
}
|
|
}
|
|
if !nvmeFound {
|
|
t.Fatalf("expected deduped NVME storage by serial NVME-21")
|
|
}
|
|
if !diskModelEnriched {
|
|
t.Fatalf("expected disk model enrichment from smartdata by serial")
|
|
}
|
|
|
|
if len(result.Hardware.PowerSupply) != 2 {
|
|
t.Fatalf("expected 2 PSUs from psu_cfg.ini, got %d", len(result.Hardware.PowerSupply))
|
|
}
|
|
if result.Hardware.PowerSupply[0].WattageW == 0 {
|
|
t.Fatalf("expected PSU wattage parsed, got 0")
|
|
}
|
|
if len(result.Hardware.NetworkAdapters) != 2 {
|
|
t.Fatalf("expected 2 host network adapters from hardware_info.ini, got %d", len(result.Hardware.NetworkAdapters))
|
|
}
|
|
if len(result.Hardware.NetworkCards) != 2 {
|
|
t.Fatalf("expected 2 network cards synthesized from adapters, got %d", len(result.Hardware.NetworkCards))
|
|
}
|
|
var g5NIC models.NetworkAdapter
|
|
var g5NICFound bool
|
|
for _, nic := range result.Hardware.NetworkAdapters {
|
|
if strings.EqualFold(nic.Slot, "PCIe 1") && strings.Contains(strings.ToLower(nic.Model), "bcm957414") {
|
|
g5NIC = nic
|
|
g5NICFound = true
|
|
break
|
|
}
|
|
}
|
|
if !g5NICFound {
|
|
t.Fatalf("expected host NIC PCIe 1 from hardware_info.ini, got %+v", result.Hardware.NetworkAdapters)
|
|
}
|
|
if !strings.Contains(strings.ToLower(g5NIC.Vendor), "broadcom") {
|
|
t.Fatalf("expected G5 NIC vendor from Vendor ID, got %q", g5NIC.Vendor)
|
|
}
|
|
if g5NIC.SerialNumber != "NICSN-G5-001" {
|
|
t.Fatalf("expected G5 NIC serial from PCIe card section, got %q", g5NIC.SerialNumber)
|
|
}
|
|
if g5NIC.PartNumber != "NICPN-G5-001" {
|
|
t.Fatalf("expected G5 NIC part number from PCIe card section, got %q", g5NIC.PartNumber)
|
|
}
|
|
if g5NIC.Firmware != "21.80.1" {
|
|
t.Fatalf("expected G5 NIC firmware from PCIe card section, got %q", g5NIC.Firmware)
|
|
}
|
|
|
|
if len(result.Hardware.Devices) != 5 {
|
|
t.Fatalf("expected 5 topology devices from Raid_BP_Conf_Info.ini (3 BP + 2 RAID), got %d", len(result.Hardware.Devices))
|
|
}
|
|
var bpFound bool
|
|
var raidFound bool
|
|
for _, d := range result.Hardware.Devices {
|
|
if strings.Contains(d.ID, "h3c-bp-") && strings.Contains(d.Model, "BP_G5_8SFF") {
|
|
bpFound = true
|
|
}
|
|
desc, _ := d.Details["description"].(string)
|
|
if strings.Contains(d.ID, "h3c-raid-slot-3") && strings.Contains(desc, "SAS ports: 2") {
|
|
raidFound = true
|
|
}
|
|
}
|
|
if !bpFound || !raidFound {
|
|
t.Fatalf("expected parsed backplane and RAID topology devices, got %+v", result.Hardware.Devices)
|
|
}
|
|
|
|
if len(result.Hardware.Volumes) != 2 {
|
|
t.Fatalf("expected 2 RAID volumes (same LD ID on different controllers), got %d", len(result.Hardware.Volumes))
|
|
}
|
|
var raid1Found bool
|
|
var raid50Found bool
|
|
for _, v := range result.Hardware.Volumes {
|
|
if strings.Contains(v.Controller, "slot 3") {
|
|
raid1Found = v.RAIDLevel == "RAID1" && v.CapacityBytes > 0
|
|
}
|
|
if strings.Contains(v.Controller, "slot 6") {
|
|
raid50Found = v.RAIDLevel == "RAID50" && v.CapacityBytes > 0
|
|
}
|
|
}
|
|
if !raid1Found || !raid50Found {
|
|
t.Fatalf("expected RAID1 and RAID50 volumes with parsed capacities, got %+v", result.Hardware.Volumes)
|
|
}
|
|
|
|
if len(result.Events) != 2 {
|
|
t.Fatalf("expected 2 CSV events (Pre-Init skipped), got %d", len(result.Events))
|
|
}
|
|
if result.Events[0].Severity != models.SeverityWarning {
|
|
t.Fatalf("expected Minor CSV severity mapped to warning, got %q", result.Events[0].Severity)
|
|
}
|
|
if result.Events[1].Severity != models.SeverityCritical {
|
|
t.Fatalf("expected Major CSV severity mapped to critical, got %q", result.Events[1].Severity)
|
|
}
|
|
}
|