unraid: parse dimm/nic/pcie and annotate duplicate serials

This commit is contained in:
2026-03-01 18:14:45 +03:00
parent 7d1a02cb72
commit 206496efae
4 changed files with 653 additions and 10 deletions

View File

@@ -300,7 +300,7 @@ func BuildHardwareDevices(hw *models.HardwareConfig) []models.HardwareDevice {
})
}
return dedupeDevices(all)
return annotateDuplicateSerials(dedupeDevices(all))
}
func isEmptyPCIeDevice(p models.PCIeDevice) bool {
@@ -443,9 +443,22 @@ func shouldMergeDevices(a, b models.HardwareDevice) bool {
bSN := strings.ToLower(normalizedSerial(b.SerialNumber))
aBDF := strings.ToLower(strings.TrimSpace(a.BDF))
bBDF := strings.ToLower(strings.TrimSpace(b.BDF))
aSlot := normalizeSlot(a.Slot)
bSlot := normalizeSlot(b.Slot)
// Memory DIMMs can legitimately share serial number in some dumps.
// Never merge DIMMs with different slots.
if a.Kind == models.DeviceKindMemory && b.Kind == models.DeviceKindMemory {
if aSlot != "" && bSlot != "" && aSlot != bSlot {
return false
}
}
// Hard conflicts.
if aSN != "" && bSN != "" && aSN == bSN {
if a.Kind == models.DeviceKindMemory && b.Kind == models.DeviceKindMemory {
return aSlot != "" && bSlot != "" && aSlot == bSlot
}
return true
}
if aSN != "" && bSN != "" && aSN != bSN {
@@ -465,7 +478,7 @@ func shouldMergeDevices(a, b models.HardwareDevice) bool {
if hasMACOverlap(a.MACAddresses, b.MACAddresses) {
return true
}
if normalizeSlot(a.Slot) != "" && normalizeSlot(a.Slot) == normalizeSlot(b.Slot) {
if aSlot != "" && aSlot == bSlot {
return true
}
return false
@@ -481,7 +494,7 @@ func shouldMergeDevices(a, b models.HardwareDevice) bool {
if sameManufacturer(a, b) {
score += 2
}
if normalizeSlot(a.Slot) != "" && normalizeSlot(a.Slot) == normalizeSlot(b.Slot) {
if aSlot != "" && aSlot == bSlot {
score += 2
}
if hasMACOverlap(a.MACAddresses, b.MACAddresses) {
@@ -732,3 +745,35 @@ func buildFirmwareBySlot(firmware []models.FirmwareInfo) map[string]slotFirmware
func normalizeSlotKey(slot string) string {
return strings.ToLower(strings.TrimSpace(slot))
}
func annotateDuplicateSerials(items []models.HardwareDevice) []models.HardwareDevice {
if len(items) < 2 {
return items
}
countByKindSerial := make(map[string]int)
for _, d := range items {
serial := normalizedSerial(d.SerialNumber)
if serial == "" {
continue
}
key := d.Kind + "|" + strings.ToLower(serial)
countByKindSerial[key]++
}
seenByKindSerial := make(map[string]int)
for i := range items {
serial := normalizedSerial(items[i].SerialNumber)
if serial == "" {
continue
}
key := items[i].Kind + "|" + strings.ToLower(serial)
if countByKindSerial[key] < 2 {
continue
}
seenByKindSerial[key]++
items[i].SerialNumber = serial + " (DUP#" + strconv.Itoa(seenByKindSerial[key]) + ")"
}
return items
}