feat(hpe): improve inventory extraction and export fidelity

This commit is contained in:
Mikhail Chusavitin
2026-03-30 15:04:17 +03:00
parent d8c3256e41
commit c47c34fd11
12 changed files with 989 additions and 59 deletions

View File

@@ -25,12 +25,17 @@ const (
)
var (
partNumberPattern = regexp.MustCompile(`(?i)^[a-z0-9]{1,4}\d{4,6}-[a-z0-9]{2,4}$`)
serverSerialRE = regexp.MustCompile(`(?i)(?:^|[_-])([a-z0-9]{10})(?:[_-]|\.)`)
dimmSlotRE = regexp.MustCompile(`^PROC\s+(\d+)\s+DIMM\s+(\d+)$`)
procSlotRE = regexp.MustCompile(`^Proc\s+(\d+)$`)
psuSlotRE = regexp.MustCompile(`^Power Supply\s+(\d+)$`)
eventTimeRE = regexp.MustCompile(`^\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}$`)
partNumberPattern = regexp.MustCompile(`(?i)^[a-z0-9]{1,4}\d{4,6}-[a-z0-9]{2,4}$`)
serverSerialRE = regexp.MustCompile(`(?i)(?:^|[_-])([a-z0-9]{10})(?:[_-]|\.)`)
dimmSlotRE = regexp.MustCompile(`^PROC\s+(\d+)\s+DIMM\s+(\d+)$`)
procSlotRE = regexp.MustCompile(`^Proc\s+(\d+)$`)
psuSlotRE = regexp.MustCompile(`^Power Supply\s+(\d+)$`)
eventTimeRE = regexp.MustCompile(`^\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}$`)
psuXMLRE = regexp.MustCompile(`(?s)<PowerSupplySlot id="(\d+)">(.*?)</PowerSupplySlot>`)
firmwareLockdownRE = regexp.MustCompile(`(?s)<FirmwareLockdown>(.*?)</FirmwareLockdown>`)
xmlFieldRE = regexp.MustCompile(`(?s)<([A-Za-z0-9_-]+)>([^<]*)</[A-Za-z0-9_-]+>`)
psuLogRE = regexp.MustCompile(`Update bay (\d+) (SPN|Serial Number|Model Number|fw ver\.), value = ([A-Za-z0-9._-]+)`)
versionFragmentRE = regexp.MustCompile(`\d+(?:\.\d+)+`)
)
func init() {
@@ -129,6 +134,13 @@ func (p *Parser) Parse(files []parser.ExtractedFile) (*models.AnalysisResult, er
result.Hardware.NetworkAdapters = dedupeNetworkAdapters(parseNetworkAdapters(tokens))
result.Hardware.Firmware = dedupeFirmware(parseFirmware(tokens))
psuSupplements := parsePSUSupplements(entries)
result.Hardware.PowerSupply = dedupePSUs(mergePSUs(result.Hardware.PowerSupply, psuSupplements))
lockdownFW, nicFirmwareByVendor := parseBCertFirmware(entries)
result.Hardware.NetworkAdapters = dedupeNetworkAdapters(enrichNetworkAdapters(result.Hardware.NetworkAdapters, nicFirmwareByVendor))
result.Hardware.Firmware = dedupeFirmware(append(result.Hardware.Firmware, lockdownFW...))
storage, volumes, controllerDevices, controllerFW := parseRedfishStorage(redfishDocs)
result.Hardware.Storage = dedupeStorage(storage)
result.Hardware.Volumes = volumes
@@ -446,22 +458,37 @@ func parseDIMMs(tokens []string) []models.MemoryDIMM {
func parsePSUs(tokens []string) []models.PSU {
out := make([]models.PSU, 0, 4)
for i := 0; i+2 < len(tokens); i++ {
for i := 0; i < len(tokens); i++ {
match := psuSlotRE.FindStringSubmatch(tokens[i])
if len(match) != 2 {
continue
}
slot := "PSU " + match[1]
serial := tokens[i+1]
partNumber := tokens[i+2]
if isUnavailable(serial) && isUnavailable(partNumber) {
vendor := ""
serial := ""
partNumber := ""
for j := i + 1; j < len(tokens) && j <= i+5; j++ {
field := strings.TrimSpace(tokens[j])
if strings.HasPrefix(field, "PciRoot(") || psuSlotRE.MatchString(field) || dimmSlotRE.MatchString(field) || procSlotRE.MatchString(field) || eventTimeRE.MatchString(field) {
break
}
switch {
case vendor == "" && looksLikePSUVendor(field):
vendor = field
case partNumber == "" && looksLikePartNumber(field):
partNumber = field
case serial == "" && isLikelySerial(field):
serial = field
}
}
if serial == "" && partNumber == "" {
continue
}
psu := models.PSU{
Slot: slot,
Present: true,
Model: valueOr(partNumber, "Power Supply"),
Vendor: "HPE",
Vendor: valueOr(cleanUnavailable(vendor), "HPE"),
SerialNumber: cleanUnavailable(serial),
PartNumber: cleanUnavailable(partNumber),
Status: "ok",
@@ -471,6 +498,80 @@ func parsePSUs(tokens []string) []models.PSU {
return out
}
func parsePSUSupplements(entries []ahsEntry) []models.PSU {
bySlot := make(map[string]models.PSU)
for _, entry := range entries {
text := string(entry.Content)
if text == "" {
continue
}
if strings.EqualFold(entry.Name, "bcert.pkg") {
for _, match := range psuXMLRE.FindAllStringSubmatch(text, -1) {
slotNum, _ := strconv.Atoi(match[1])
slot := fmt.Sprintf("PSU %d", slotNum+1)
fields := parseXMLFields(match[2])
item := bySlot[slot]
item.Slot = slot
item.Present = strings.EqualFold(fields["Present"], "Yes") || item.Present
if serial := strings.TrimSpace(fields["SerialNumber"]); serial != "" {
item.SerialNumber = serial
}
if fw := strings.TrimSpace(fields["FirmwareVersion"]); fw != "" {
item.Firmware = fw
}
if spare := strings.TrimSpace(fields["SparePartNumber"]); spare != "" {
if item.Details == nil {
item.Details = make(map[string]any)
}
item.Details["spare_part_number"] = spare
}
bySlot[slot] = item
}
}
for _, match := range psuLogRE.FindAllStringSubmatch(text, -1) {
slotNum, _ := strconv.Atoi(match[1])
slot := fmt.Sprintf("PSU %d", slotNum+1)
item := bySlot[slot]
item.Slot = slot
item.Present = true
value := strings.TrimSpace(match[3])
switch match[2] {
case "SPN":
if item.Details == nil {
item.Details = make(map[string]any)
}
item.Details["spare_part_number"] = value
case "Serial Number":
item.SerialNumber = value
case "Model Number":
item.Model = value
item.PartNumber = value
case "fw ver.":
item.Firmware = normalizeLooseVersion(value)
}
bySlot[slot] = item
}
}
out := make([]models.PSU, 0, len(bySlot))
for _, item := range bySlot {
if item.Slot == "" {
continue
}
item.Vendor = valueOr(item.Vendor, "HPE")
item.Status = valueOr(item.Status, "ok")
if item.Model == "" {
item.Model = valueOr(item.PartNumber, "Power Supply")
}
out = append(out, item)
}
sort.Slice(out, func(i, j int) bool { return out[i].Slot < out[j].Slot })
return out
}
type pcieSequence struct {
UEFIPath string
Code string
@@ -621,13 +722,53 @@ func parseRedfishStorage(docs map[string]map[string]any) ([]models.Storage, []mo
storage := make([]models.Storage, 0, 8)
volumes := make([]models.StorageVolume, 0, 4)
devices := make([]models.HardwareDevice, 0, 4)
firmware := make([]models.FirmwareInfo, 0, 4)
devices := make([]models.HardwareDevice, 0, 6)
firmware := make([]models.FirmwareInfo, 0, 8)
fabricNames := make(map[string]string)
fabricTypes := make(map[string]string)
for _, path := range paths {
doc := docs[path]
docType := asString(doc["@odata.type"])
switch {
case strings.Contains(docType, "#Fabric."):
fabricID := redfishID(path)
fabricNames[fabricID] = strings.TrimSpace(asString(doc["Name"]))
fabricTypes[fabricID] = strings.TrimSpace(asString(doc["FabricType"]))
case strings.Contains(docType, "#Switch."):
fabricID := fabricIDFromPath(path)
name := valueOr(fabricNames[fabricID], strings.TrimSpace(asString(doc["Name"])))
model := strings.TrimSpace(asString(doc["Model"]))
fw := strings.TrimSpace(asString(doc["FirmwareVersion"]))
device := models.HardwareDevice{
ID: "hpe-fabric-" + redfishID(path),
Kind: models.DeviceKindStorage,
Source: "redfish",
Slot: valueOr(fabricID, redfishID(path)),
DeviceClass: "storage_backplane",
Model: valueOr(name, model),
PartNumber: model,
Firmware: fw,
Status: redfishStatus(doc["Status"]),
Details: map[string]any{
"odata_id": path,
"fabric_type": valueOr(fabricTypes[fabricID], strings.TrimSpace(asString(doc["FabricType"]))),
"switch_type": strings.TrimSpace(asString(doc["SwitchType"])),
"supported_protocols": stringSlice(doc["SupportedProtocols"]),
"domain_id": asInt64(doc["DomainID"]),
"fabric_name": fabricNames[fabricID],
"connected_chassis_id": asString(nested(doc, "Links", "Chassis", "@odata.id")),
},
}
devices = append(devices, device)
if fw != "" {
firmware = append(firmware, models.FirmwareInfo{
DeviceName: valueOr(name, model),
Version: fw,
})
}
case strings.Contains(docType, "#StorageController."):
slot := redfishServiceLabel(doc, "Location", "PartLocation", "ServiceLabel")
model := valueOr(asString(doc["Model"]), asString(doc["Name"]))
@@ -649,9 +790,16 @@ func parseRedfishStorage(docs map[string]map[string]any) ([]models.Storage, []mo
Firmware: fw,
Status: redfishStatus(doc["Status"]),
Details: map[string]any{
"odata_id": path,
"part_number": partNumber,
"sku": sku,
"odata_id": path,
"part_number": partNumber,
"sku": sku,
"speed_gbps": asFloat64(doc["SpeedGbps"]),
"supported_controller_protocols": stringSlice(doc["SupportedControllerProtocols"]),
"supported_device_protocols": stringSlice(doc["SupportedDeviceProtocols"]),
"supported_raid_types": stringSlice(doc["SupportedRAIDTypes"]),
"cache_total_mib": asInt64(nested(doc, "CacheSummary", "TotalCacheSizeMiB")),
"persistent_cache_mib": asInt64(nested(doc, "CacheSummary", "PersistentCacheSizeMiB")),
"durable_name": firstDurableName(doc),
},
}
if width := asInt(doc, "PCIeInterface", "LanesInUse"); width > 0 {
@@ -692,8 +840,12 @@ func parseRedfishStorage(docs map[string]map[string]any) ([]models.Storage, []mo
RemainingEndurancePct: endurance,
Status: redfishStatus(doc["Status"]),
Details: map[string]any{
"odata_id": path,
"capacity_bytes": capacity,
"odata_id": path,
"capacity_bytes": capacity,
"failure_predicted": asBool(doc["FailurePredicted"]),
"negotiated_speed_gbps": asFloat64(doc["NegotiatedSpeedGbs"]),
"capable_speed_gbps": asFloat64(doc["CapableSpeedGbs"]),
"location_indicator_active": asBool(doc["LocationIndicatorActive"]),
},
}
storage = append(storage, entry)
@@ -1005,6 +1157,16 @@ func isHPEManufacturer(v string) bool {
return v == "HPE" || v == "HP"
}
func looksLikePSUVendor(v string) bool {
v = strings.TrimSpace(strings.ToUpper(v))
switch v {
case "HPE", "HP", "DELTA", "LITEON", "LTEON":
return true
default:
return false
}
}
func looksLikeServerModel(v string) bool {
v = sanitizeModel(v)
if v == "" {
@@ -1115,6 +1277,163 @@ func inferVendor(model string) string {
}
}
func mergePSUs(base, extra []models.PSU) []models.PSU {
merged := make(map[string]models.PSU)
order := make([]string, 0, len(base)+len(extra))
mergeOne := func(item models.PSU) {
key := strings.ToLower(strings.TrimSpace(item.Slot))
if key == "" {
key = strings.ToLower(strings.TrimSpace(valueOr(item.SerialNumber, item.Model+"|"+item.PartNumber)))
}
if key == "" {
return
}
current, exists := merged[key]
if !exists {
merged[key] = item
order = append(order, key)
return
}
if current.Slot == "" {
current.Slot = item.Slot
}
current.Present = current.Present || item.Present
current.Model = valueOr(current.Model, item.Model)
current.Description = valueOr(current.Description, item.Description)
current.Vendor = valueOr(current.Vendor, item.Vendor)
if current.WattageW == 0 {
current.WattageW = item.WattageW
}
current.SerialNumber = valueOr(current.SerialNumber, item.SerialNumber)
current.PartNumber = valueOr(current.PartNumber, item.PartNumber)
current.Firmware = valueOr(current.Firmware, item.Firmware)
current.Status = valueOr(current.Status, item.Status)
current.InputType = valueOr(current.InputType, item.InputType)
if current.InputPowerW == 0 {
current.InputPowerW = item.InputPowerW
}
if current.OutputPowerW == 0 {
current.OutputPowerW = item.OutputPowerW
}
if current.InputVoltage == 0 {
current.InputVoltage = item.InputVoltage
}
if current.OutputVoltage == 0 {
current.OutputVoltage = item.OutputVoltage
}
if current.TemperatureC == 0 {
current.TemperatureC = item.TemperatureC
}
current.Details = mergeDetailMaps(current.Details, item.Details)
merged[key] = current
}
for _, item := range base {
mergeOne(item)
}
for _, item := range extra {
mergeOne(item)
}
out := make([]models.PSU, 0, len(order))
for _, key := range order {
out = append(out, merged[key])
}
return out
}
func enrichNetworkAdapters(items []models.NetworkAdapter, firmwareByVendor map[string]string) []models.NetworkAdapter {
out := make([]models.NetworkAdapter, 0, len(items))
for _, item := range items {
if item.Firmware == "" {
if fw := firmwareByVendor[strings.ToLower(strings.TrimSpace(item.Vendor))]; fw != "" {
item.Firmware = fw
}
}
out = append(out, item)
}
return out
}
func parseBCertFirmware(entries []ahsEntry) ([]models.FirmwareInfo, map[string]string) {
out := make([]models.FirmwareInfo, 0, 8)
nicFirmwareByVendor := make(map[string]string)
seen := make(map[string]bool)
tagNames := map[string]string{
"SystemProgrammableLogicDevice": "System Programmable Logic Device",
"ServerPlatformServicesSPSFirmware": "Server Platform Services (SPS) Firmware",
"STMicroGen11TPM": "TPM Firmware",
"PrimaryR012U3x16slotsriserx8-x16-x8": "PCIe Riser 1 Programmable Logic Device",
"HPEMR408i-oGen11": "HPE MR408i-o Gen11",
"UBM3": "8 SFF 24G x1NVMe/SAS UBM3 BC BP",
"BCM57191Gb4pBASE-T": "BCM 5719 1Gb 4p BASE-T OCP Adptr",
"BCM57191Gb4pBASE-TOCP3": "BCM 5719 1Gb 4p BASE-T OCP Adptr",
}
for _, entry := range entries {
if !strings.EqualFold(entry.Name, "bcert.pkg") {
continue
}
text := string(entry.Content)
for _, match := range firmwareLockdownRE.FindAllStringSubmatch(text, -1) {
fields := parseXMLFields(match[1])
for tag, value := range fields {
name := tagNames[tag]
if name == "" {
continue
}
version := normalizeBCertVersion(tag, value)
if version == "" {
continue
}
appendFirmware(&out, seen, models.FirmwareInfo{
DeviceName: name,
Version: version,
})
if strings.Contains(name, "BCM 5719") {
nicFirmwareByVendor["broadcom"] = version
}
}
}
}
return out, nicFirmwareByVendor
}
func parseXMLFields(block string) map[string]string {
out := make(map[string]string)
for _, match := range xmlFieldRE.FindAllStringSubmatch(block, -1) {
out[match[1]] = strings.TrimSpace(match[2])
}
return out
}
func normalizeBCertVersion(tag, value string) string {
value = strings.TrimSpace(value)
if value == "" || strings.EqualFold(value, "NA") {
return ""
}
switch tag {
case "UBM3":
if idx := strings.LastIndex(value, "/"); idx >= 0 && idx+1 < len(value) {
return strings.TrimSpace(value[idx+1:])
}
case "IntegratedLights-OutVI":
if idx := strings.Index(value, " - "); idx > 0 {
return strings.TrimSpace(value[:idx])
}
case "U54":
return value
}
return value
}
func normalizeLooseVersion(value string) string {
if match := versionFragmentRE.FindString(strings.TrimSpace(value)); match != "" {
return match
}
return strings.TrimSpace(value)
}
func slotLabelFromCode(code string) string {
parts := strings.Split(code, ".")
if len(parts) < 3 {
@@ -1132,6 +1451,16 @@ func slotLabelFromCode(code string) string {
}
}
func fabricIDFromPath(path string) string {
parts := strings.Split(strings.Trim(path, "/"), "/")
for i := 0; i+1 < len(parts); i++ {
if parts[i] == "Fabrics" {
return parts[i+1]
}
}
return ""
}
func inferSeverity(message string) models.Severity {
lower := strings.ToLower(message)
switch {
@@ -1261,6 +1590,24 @@ func asInt64(v any) int64 {
}
}
func asFloat64(v any) float64 {
switch t := v.(type) {
case float64:
return t
case float32:
return float64(t)
case int:
return float64(t)
case int64:
return float64(t)
case json.Number:
f, _ := t.Float64()
return f
default:
return 0
}
}
func asOptionalInt(v any) *int {
switch value := v.(type) {
case float64:
@@ -1274,6 +1621,11 @@ func asOptionalInt(v any) *int {
}
}
func asBool(v any) bool {
b, ok := v.(bool)
return ok && b
}
func valueOr(v, fallback string) string {
if strings.TrimSpace(v) != "" {
return strings.TrimSpace(v)
@@ -1281,6 +1633,73 @@ func valueOr(v, fallback string) string {
return strings.TrimSpace(fallback)
}
func stringSlice(v any) []string {
items, ok := v.([]any)
if !ok {
return nil
}
out := make([]string, 0, len(items))
for _, item := range items {
value := strings.TrimSpace(asString(item))
if value == "" {
continue
}
out = append(out, value)
}
return out
}
func firstDurableName(doc map[string]any) string {
items, ok := doc["Identifiers"].([]any)
if !ok {
return ""
}
for _, item := range items {
entry, ok := item.(map[string]any)
if !ok {
continue
}
if value := strings.TrimSpace(asString(entry["DurableName"])); value != "" {
return value
}
}
return ""
}
func mergeDetailMaps(base, extra map[string]any) map[string]any {
if len(extra) == 0 {
return base
}
if base == nil {
base = make(map[string]any, len(extra))
}
for key, value := range extra {
if _, exists := base[key]; !exists || isZeroValue(base[key]) {
base[key] = value
}
}
return base
}
func isZeroValue(v any) bool {
switch t := v.(type) {
case nil:
return true
case string:
return strings.TrimSpace(t) == ""
case int:
return t == 0
case int64:
return t == 0
case float64:
return t == 0
case bool:
return !t
default:
return false
}
}
func boolPtr(v bool) *bool {
out := v
return &out

View File

@@ -27,6 +27,7 @@ func TestParseAHSInventory(t *testing.T) {
content := makeAHSArchive(t, []ahsTestEntry{
{Name: "CUST_INFO.DAT", Payload: make([]byte, 16)},
{Name: "0000088-2026-03-30.zbb", Payload: gzipBytes(t, []byte(sampleInventoryBlob()))},
{Name: "bcert.pkg", Payload: []byte(sampleBCertBlob())},
})
result, err := p.Parse([]parser.ExtractedFile{{
@@ -73,6 +74,9 @@ func TestParseAHSInventory(t *testing.T) {
if result.Hardware.PowerSupply[0].SerialNumber != "5XUWB0C4DJG4BV" {
t.Fatalf("unexpected PSU serial: %q", result.Hardware.PowerSupply[0].SerialNumber)
}
if result.Hardware.PowerSupply[0].Firmware != "2.00" {
t.Fatalf("unexpected PSU firmware: %q", result.Hardware.PowerSupply[0].Firmware)
}
if len(result.Hardware.Storage) != 1 {
t.Fatalf("expected one physical drive, got %d", len(result.Hardware.Storage))
@@ -93,6 +97,8 @@ func TestParseAHSInventory(t *testing.T) {
}
foundILO := false
foundControllerFW := false
foundNICFW := false
foundBackplaneFW := false
for _, item := range result.Hardware.Firmware {
if item.DeviceName == "iLO 6" && item.Version == "v1.63p20" {
foundILO = true
@@ -100,6 +106,12 @@ func TestParseAHSInventory(t *testing.T) {
if item.DeviceName == "HPE MR408i-o Gen11" && item.Version == "52.26.3-5379" {
foundControllerFW = true
}
if item.DeviceName == "BCM 5719 1Gb 4p BASE-T OCP Adptr" && item.Version == "20.28.41" {
foundNICFW = true
}
if item.DeviceName == "8 SFF 24G x1NVMe/SAS UBM3 BC BP" && item.Version == "1.24" {
foundBackplaneFW = true
}
}
if !foundILO {
t.Fatalf("expected iLO firmware entry")
@@ -107,6 +119,31 @@ func TestParseAHSInventory(t *testing.T) {
if !foundControllerFW {
t.Fatalf("expected controller firmware entry")
}
if !foundNICFW {
t.Fatalf("expected broadcom firmware entry")
}
if !foundBackplaneFW {
t.Fatalf("expected backplane firmware entry")
}
broadcomFound := false
backplaneFound := false
for _, nic := range result.Hardware.NetworkAdapters {
if nic.SerialNumber == "1CH0150001" && nic.Firmware == "20.28.41" {
broadcomFound = true
}
}
for _, dev := range result.Hardware.Devices {
if dev.DeviceClass == "storage_backplane" && dev.Firmware == "1.24" {
backplaneFound = true
}
}
if !broadcomFound {
t.Fatalf("expected broadcom adapter firmware to be enriched")
}
if !backplaneFound {
t.Fatalf("expected backplane canonical device")
}
if len(result.Hardware.Devices) < 6 {
t.Fatalf("expected canonical devices, got %d", len(result.Hardware.Devices))
@@ -146,17 +183,35 @@ func TestParseExampleAHS(t *testing.T) {
if len(result.Hardware.Storage) < 2 {
t.Fatalf("expected at least two drives, got %d", len(result.Hardware.Storage))
}
if len(result.Hardware.PowerSupply) != 2 {
t.Fatalf("expected exactly two PSUs, got %d: %+v", len(result.Hardware.PowerSupply), result.Hardware.PowerSupply)
}
foundController := false
foundBackplaneFW := false
foundNICFW := false
for _, device := range result.Hardware.Devices {
if device.Model == "HPE MR408i-o Gen11" && device.SerialNumber == "PXSFQ0BBIJY3B3" {
foundController = true
break
}
if device.DeviceClass == "storage_backplane" && device.Firmware == "1.24" {
foundBackplaneFW = true
}
}
if !foundController {
t.Fatalf("expected MR408i-o controller in canonical devices")
}
for _, fw := range result.Hardware.Firmware {
if fw.DeviceName == "BCM 5719 1Gb 4p BASE-T OCP Adptr" && fw.Version == "20.28.41" {
foundNICFW = true
}
}
if !foundBackplaneFW {
t.Fatalf("expected backplane device in canonical devices")
}
if !foundNICFW {
t.Fatalf("expected broadcom firmware from bcert/pkg lockdown")
}
}
type ahsTestEntry struct {
@@ -239,11 +294,17 @@ func sampleInventoryBlob() string {
"03/30/2026 09:47:33",
"iLO network link down.",
`{"@odata.id":"/redfish/v1/Systems/1/Storage/DE00A000/Controllers/0","@odata.type":"#StorageController.v1_7_0.StorageController","Id":"0","Name":"HPE MR408i-o Gen11","FirmwareVersion":"52.26.3-5379","Manufacturer":"HPE","Model":"HPE MR408i-o Gen11","PartNumber":"P58543-001","SKU":"P58335-B21","SerialNumber":"PXSFQ0BBIJY3B3","Status":{"State":"Enabled","Health":"OK"},"Location":{"PartLocation":{"ServiceLabel":"Slot=14","LocationType":"Slot","LocationOrdinalValue":14}},"PCIeInterface":{"PCIeType":"Gen4","LanesInUse":8}}`,
`{"@odata.id":"/redfish/v1/Fabrics/DE00A000","@odata.type":"#Fabric.v1_3_0.Fabric","Id":"DE00A000","Name":"8 SFF 24G x1NVMe/SAS UBM3 BC BP","FabricType":"MultiProtocol"}`,
`{"@odata.id":"/redfish/v1/Fabrics/DE00A000/Switches/1","@odata.type":"#Switch.v1_9_1.Switch","Id":"1","Name":"Direct Attached","Model":"UBM3","FirmwareVersion":"1.24","SupportedProtocols":["SAS","SATA","NVMe"],"SwitchType":"MultiProtocol","Status":{"State":"Enabled","Health":"OK"}}`,
`{"@odata.id":"/redfish/v1/Chassis/DE00A000/Drives/0","@odata.type":"#Drive.v1_17_0.Drive","Id":"0","Name":"480GB 6G SATA SSD","Status":{"State":"StandbyOffline","Health":"OK"},"PhysicalLocation":{"PartLocation":{"ServiceLabel":"Slot=14:Port=1:Box=3:Bay=1","LocationType":"Bay","LocationOrdinalValue":1}},"CapacityBytes":480103981056,"MediaType":"SSD","Model":"SAMSUNGMZ7L3480HCHQ-00A07","Protocol":"SATA","Revision":"JXTC604Q","SerialNumber":"S664NC0Y502720","PredictedMediaLifeLeftPercent":100}`,
`{"@odata.id":"/redfish/v1/Chassis/DE00A000/Drives/64515","@odata.type":"#Drive.v1_17_0.Drive","Id":"64515","Name":"Empty Bay","Status":{"State":"Absent","Health":"OK"}}`,
)
}
func sampleBCertBlob() string {
return `<BC><MfgRecord><PowerSupplySlot id="0"><Present>Yes</Present><SerialNumber>5XUWB0C4DJG4BV</SerialNumber><FirmwareVersion>2.00</FirmwareVersion><SparePartNumber>P44412-001</SparePartNumber></PowerSupplySlot><FirmwareLockdown><SystemProgrammableLogicDevice>0x12</SystemProgrammableLogicDevice><ServerPlatformServicesSPSFirmware>6.1.4.47</ServerPlatformServicesSPSFirmware><STMicroGen11TPM>1.512</STMicroGen11TPM><HPEMR408i-oGen11>52.26.3-5379</HPEMR408i-oGen11><UBM3>UBM3/1.24</UBM3><BCM57191Gb4pBASE-TOCP3>20.28.41</BCM57191Gb4pBASE-TOCP3></FirmwareLockdown></MfgRecord></BC>`
}
func stringsJoin(parts ...string) string {
return string(bytes.Join(func() [][]byte {
out := make([][]byte, 0, len(parts))