122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
package collector
|
|
|
|
import (
|
|
"bee/audit/internal/schema"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func enrichPSUsWithTelemetry(psus []schema.HardwarePowerSupply, doc sensorsDoc) []schema.HardwarePowerSupply {
|
|
if len(psus) == 0 || len(doc) == 0 {
|
|
return psus
|
|
}
|
|
|
|
tempBySlot := psuTempsFromSensors(doc)
|
|
healthBySlot := psuHealthFromSensors(doc)
|
|
for i := range psus {
|
|
slot := derefPSUSlot(psus[i].Slot)
|
|
if slot == "" {
|
|
continue
|
|
}
|
|
if psus[i].TemperatureC == nil {
|
|
if value, ok := tempBySlot[slot]; ok {
|
|
psus[i].TemperatureC = &value
|
|
}
|
|
}
|
|
if psus[i].LifeRemainingPct == nil {
|
|
if value, ok := healthBySlot[slot]; ok {
|
|
psus[i].LifeRemainingPct = &value
|
|
used := 100 - value
|
|
psus[i].LifeUsedPct = &used
|
|
}
|
|
}
|
|
}
|
|
return psus
|
|
}
|
|
|
|
func psuHealthFromSensors(doc sensorsDoc) map[string]float64 {
|
|
out := map[string]float64{}
|
|
for chip, features := range doc {
|
|
for featureName, raw := range features {
|
|
feature, ok := raw.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if !isLikelyPSUHealth(chip, featureName) {
|
|
continue
|
|
}
|
|
value, ok := firstFeaturePercent(feature)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if slot, ok := detectPSUSlot(chip, featureName); ok {
|
|
if _, exists := out[slot]; !exists {
|
|
out[slot] = value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func firstFeaturePercent(feature map[string]any) (float64, bool) {
|
|
keys := sortedFeatureKeys(feature)
|
|
for _, key := range keys {
|
|
lower := strings.ToLower(key)
|
|
if strings.HasSuffix(lower, "_alarm") {
|
|
continue
|
|
}
|
|
if strings.Contains(lower, "health") || strings.Contains(lower, "life") || strings.Contains(lower, "remain") {
|
|
if value, ok := floatFromAny(feature[key]); ok {
|
|
return value, true
|
|
}
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func isLikelyPSUHealth(chip, feature string) bool {
|
|
value := strings.ToLower(chip + " " + feature)
|
|
return (strings.Contains(value, "psu") || strings.Contains(value, "power supply")) &&
|
|
(strings.Contains(value, "health") || strings.Contains(value, "life") || strings.Contains(value, "remain"))
|
|
}
|
|
|
|
func psuTempsFromSensors(doc sensorsDoc) map[string]float64 {
|
|
out := map[string]float64{}
|
|
for chip, features := range doc {
|
|
for featureName, raw := range features {
|
|
feature, ok := raw.(map[string]any)
|
|
if !ok || classifySensorFeature(feature) != "temp" {
|
|
continue
|
|
}
|
|
if !isLikelyPSUTemp(chip, featureName) {
|
|
continue
|
|
}
|
|
temp, ok := firstFeatureFloat(feature, "_input")
|
|
if !ok {
|
|
continue
|
|
}
|
|
if slot, ok := detectPSUSlot(chip, featureName); ok {
|
|
if _, exists := out[slot]; !exists {
|
|
out[slot] = temp
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func isLikelyPSUTemp(chip, feature string) bool {
|
|
value := strings.ToLower(chip + " " + feature)
|
|
return strings.Contains(value, "psu") || strings.Contains(value, "power supply")
|
|
}
|
|
|
|
func detectPSUSlot(parts ...string) (string, bool) {
|
|
for _, part := range parts {
|
|
if value, ok := parsePSUSlot(part); ok && value > 0 {
|
|
return strconv.Itoa(value - 1), true
|
|
}
|
|
}
|
|
return "", false
|
|
}
|