Files
pulse/pkg/diskinventory/identity.go
T
2026-07-23 22:05:09 +01:00

81 lines
2.5 KiB
Go

package diskinventory
import (
"fmt"
"strings"
)
// DeviceToken returns the kernel block-device token from either a canonical
// /dev path or a legacy smartctl display label such as "sda [scsi]".
func DeviceToken(device string) string {
device = strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(device), "/dev/"))
if fields := strings.Fields(device); len(fields) > 0 {
device = fields[0]
}
return strings.TrimSpace(device)
}
// PreferredID selects stable hardware identity first and scopes topology
// fallbacks to the reporting host. Controller and target are included only
// when present, preserving legacy direct-device IDs for SATA/NVMe disks.
func PreferredID(serial, wwn, scope, device, controller, target string) string {
if serial = strings.TrimSpace(serial); IsUsableHardwareID(serial) {
return serial
}
if wwn = strings.TrimSpace(wwn); IsUsableHardwareID(wwn) {
return wwn
}
scope = strings.TrimSpace(scope)
device = DeviceToken(device)
controller = strings.TrimSpace(controller)
target = strings.TrimSpace(target)
if scope == "" || device == "" {
return ""
}
if !IsControllerMemberTarget(target) {
return fmt.Sprintf("%s:%s", scope, device)
}
return fmt.Sprintf("%s:%s@%s/%s", scope, device, controller, target)
}
// IsUsableHardwareID rejects controller placeholders that are not unique disk
// identities. Treating these as real serials collapses different disks and
// sends their SMART history to the same metric key.
func IsUsableHardwareID(value string) bool {
value = strings.TrimSpace(value)
if value == "" {
return false
}
upper := strings.ToUpper(value)
switch upper {
case "UNKNOWN", "N/A", "NA", "NONE", "NULL", "DEFAULT", "DEFAULT-SERIAL",
"TO BE FILLED BY O.E.M.", "0123456789":
return false
}
compact := strings.NewReplacer("-", "", ":", "", ".", "", " ", "").Replace(upper)
if compact == "" {
return false
}
allZero := true
allF := true
for _, char := range compact {
allZero = allZero && char == '0'
allF = allF && char == 'F'
}
return !allZero && !allF
}
// IsControllerMemberTarget reports whether target addresses one member behind
// a shared controller block path. Controller grammars vary after the numeric
// member prefix (for example megaraid,7, areca,1/1, and sssraid,0,1).
func IsControllerMemberTarget(target string) bool {
target = strings.TrimSpace(target)
index := strings.IndexByte(target, ',')
if index < 0 || index+1 >= len(target) {
return false
}
next := target[index+1]
return next >= '0' && next <= '9'
}