IPMI hang fix (Lenovo XCC SR650 V3): - Add pluggable ipmi_profile system with per-vendor timeouts and fruEarlyExit flag - Lenovo profile: 90s FRU timeout, streaming early-exit stops after PSU blocks found - collectFRUEarlyExit streams ipmitool fru print and kills process once PSU blocks are followed by a non-PSU header (~6s instead of ~108s on 54-device FRU list) - collectBMCFirmware and collectPSUs accept manufacturer and apply profile timeouts VROC license detection: - Detect VMD/VROC controller in PCIe list, run mdadm --detail-platform - Parse "License:" line; store as snap.VROCLicense in HardwareSnapshot Blackbox service fix: - bee-blackbox.service was missing from systemctl enable list in ISO build hook - Service never started on boot; state file never written; UI button stayed "Enable" Drop qrencode: - Remove from package list, standardTools API check, and runtime-flows doc Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
93 lines
3.0 KiB
Go
93 lines
3.0 KiB
Go
package collector
|
|
|
|
// Package-level IPMI tuning profiles.
|
|
//
|
|
// Each profile is matched by board manufacturer (already known before PSU
|
|
// collection runs). The profile drives two things:
|
|
// - Per-command timeouts — prevents infinite hangs on slow BMCs.
|
|
// - FRU early-exit — streaming parser stops reading once all PSU entries
|
|
// are found, avoiding the tail of non-PSU FRU records.
|
|
//
|
|
// To add a new vendor: append to ipmiProfiles. The first matching entry wins.
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ipmiProfile holds tuning parameters for one or more board manufacturers.
|
|
type ipmiProfile struct {
|
|
// name is shown in log messages.
|
|
name string
|
|
// manufacturers is a list of lowercase substrings matched against the
|
|
// board manufacturer string from dmidecode type 1.
|
|
manufacturers []string
|
|
// fruTimeout is the hard deadline for the entire `ipmitool fru print`
|
|
// command. Zero means no timeout (not recommended).
|
|
fruTimeout time.Duration
|
|
// sdrTimeout is the hard deadline for `ipmitool sdr`.
|
|
sdrTimeout time.Duration
|
|
// mcInfoTimeout is the hard deadline for `ipmitool mc info`.
|
|
mcInfoTimeout time.Duration
|
|
// fruEarlyExit instructs the streaming FRU parser to stop reading
|
|
// after it has found at least one PSU entry and the current block is
|
|
// complete. Useful on servers with many non-PSU FRU devices.
|
|
fruEarlyExit bool
|
|
}
|
|
|
|
// ipmiProfiles is the ordered list of profiles. First match wins.
|
|
var ipmiProfiles = []ipmiProfile{
|
|
{
|
|
// Lenovo XCC-based servers (ThinkSystem SR6xx / SR8xx / ST series).
|
|
// SR650 V3 has 54 FRU devices; each IPMI read takes ~2 s, so the
|
|
// full `fru print` scan takes ~108 s on a loaded BMC. Enable early
|
|
// exit so collection stops once PSU records are found.
|
|
name: "lenovo",
|
|
manufacturers: []string{"lenovo"},
|
|
fruTimeout: 90 * time.Second,
|
|
sdrTimeout: 45 * time.Second,
|
|
mcInfoTimeout: 15 * time.Second,
|
|
fruEarlyExit: true,
|
|
},
|
|
{
|
|
// HPE iLO-based servers (ProLiant DL/ML/BL).
|
|
name: "hpe",
|
|
manufacturers: []string{"hp", "hewlett packard"},
|
|
fruTimeout: 60 * time.Second,
|
|
sdrTimeout: 30 * time.Second,
|
|
mcInfoTimeout: 10 * time.Second,
|
|
fruEarlyExit: false,
|
|
},
|
|
{
|
|
// Dell iDRAC-based servers.
|
|
name: "dell",
|
|
manufacturers: []string{"dell"},
|
|
fruTimeout: 60 * time.Second,
|
|
sdrTimeout: 30 * time.Second,
|
|
mcInfoTimeout: 10 * time.Second,
|
|
fruEarlyExit: false,
|
|
},
|
|
}
|
|
|
|
// defaultIPMIProfile is used when no vendor profile matches.
|
|
var defaultIPMIProfile = ipmiProfile{
|
|
name: "default",
|
|
fruTimeout: 60 * time.Second,
|
|
sdrTimeout: 30 * time.Second,
|
|
mcInfoTimeout: 10 * time.Second,
|
|
fruEarlyExit: false,
|
|
}
|
|
|
|
// selectIPMIProfile returns the profile for the given board manufacturer.
|
|
func selectIPMIProfile(manufacturer string) ipmiProfile {
|
|
mfgLower := strings.ToLower(strings.TrimSpace(manufacturer))
|
|
for _, p := range ipmiProfiles {
|
|
for _, m := range p.manufacturers {
|
|
if strings.Contains(mfgLower, m) {
|
|
return p
|
|
}
|
|
}
|
|
}
|
|
return defaultIPMIProfile
|
|
}
|