149 lines
3.0 KiB
Go
149 lines
3.0 KiB
Go
package inspur
|
|
|
|
import (
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
"git.mchus.pro/mchus/logpile/internal/parser"
|
|
)
|
|
|
|
var bpHDDSerialTokenRegex = regexp.MustCompile(`[A-Za-z0-9]{8,32}`)
|
|
|
|
func enrichStorageFromSerialFallbackFiles(files []parser.ExtractedFile, hw *models.HardwareConfig) {
|
|
if hw == nil {
|
|
return
|
|
}
|
|
f := parser.FindFileByName(files, "BpHDDSerialNumber.info")
|
|
if f == nil {
|
|
return
|
|
}
|
|
serials := extractBPHDDSerials(f.Content)
|
|
if len(serials) == 0 {
|
|
return
|
|
}
|
|
applyStorageSerialFallback(hw, serials)
|
|
}
|
|
|
|
func extractBPHDDSerials(content []byte) []string {
|
|
if len(content) == 0 {
|
|
return nil
|
|
}
|
|
matches := bpHDDSerialTokenRegex.FindAllString(string(content), -1)
|
|
if len(matches) == 0 {
|
|
return nil
|
|
}
|
|
|
|
out := make([]string, 0, len(matches))
|
|
seen := make(map[string]struct{}, len(matches))
|
|
for _, m := range matches {
|
|
v := normalizeRedisValue(m)
|
|
if !looksLikeStorageSerial(v) {
|
|
continue
|
|
}
|
|
key := strings.ToLower(v)
|
|
if _, ok := seen[key]; ok {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
out = append(out, v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func looksLikeStorageSerial(v string) bool {
|
|
if len(v) < 8 {
|
|
return false
|
|
}
|
|
hasLetter := false
|
|
hasDigit := false
|
|
for _, r := range v {
|
|
switch {
|
|
case r >= 'A' && r <= 'Z':
|
|
hasLetter = true
|
|
case r >= 'a' && r <= 'z':
|
|
hasLetter = true
|
|
case r >= '0' && r <= '9':
|
|
hasDigit = true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
return hasLetter && hasDigit
|
|
}
|
|
|
|
func applyStorageSerialFallback(hw *models.HardwareConfig, serials []string) {
|
|
if hw == nil || len(hw.Storage) == 0 || len(serials) == 0 {
|
|
return
|
|
}
|
|
|
|
existing := make(map[string]struct{}, len(hw.Storage))
|
|
for _, dev := range hw.Storage {
|
|
if sn := normalizeRedisValue(dev.SerialNumber); sn != "" {
|
|
existing[strings.ToLower(sn)] = struct{}{}
|
|
}
|
|
}
|
|
|
|
filtered := make([]string, 0, len(serials))
|
|
for _, sn := range serials {
|
|
key := strings.ToLower(sn)
|
|
if _, ok := existing[key]; ok {
|
|
continue
|
|
}
|
|
filtered = append(filtered, sn)
|
|
}
|
|
if len(filtered) == 0 {
|
|
return
|
|
}
|
|
|
|
type target struct {
|
|
index int
|
|
rank int
|
|
slot string
|
|
}
|
|
targets := make([]target, 0, len(hw.Storage))
|
|
for i := range hw.Storage {
|
|
dev := hw.Storage[i]
|
|
if normalizeRedisValue(dev.SerialNumber) != "" {
|
|
continue
|
|
}
|
|
if !dev.Present && strings.TrimSpace(dev.Slot) == "" {
|
|
continue
|
|
}
|
|
rank := 0
|
|
if !dev.Present {
|
|
rank += 10
|
|
}
|
|
if strings.EqualFold(strings.TrimSpace(dev.Type), "NVMe") {
|
|
rank += 5
|
|
}
|
|
if strings.TrimSpace(dev.Slot) == "" {
|
|
rank += 4
|
|
}
|
|
targets = append(targets, target{
|
|
index: i,
|
|
rank: rank,
|
|
slot: strings.ToLower(strings.TrimSpace(dev.Slot)),
|
|
})
|
|
}
|
|
if len(targets) == 0 {
|
|
return
|
|
}
|
|
|
|
sort.Slice(targets, func(i, j int) bool {
|
|
if targets[i].rank != targets[j].rank {
|
|
return targets[i].rank < targets[j].rank
|
|
}
|
|
return targets[i].slot < targets[j].slot
|
|
})
|
|
|
|
for i := 0; i < len(targets) && i < len(filtered); i++ {
|
|
dev := &hw.Storage[targets[i].index]
|
|
dev.SerialNumber = filtered[i]
|
|
if !dev.Present {
|
|
dev.Present = true
|
|
}
|
|
}
|
|
}
|