c97975c1df
Consumes the agent v0.94.0 smart payload (MinAgent floor unchanged; feature-detect by presence). One pure verdict fn agentapi.DiskVerdictFor shared by the dashboard card and the 6h check. Card via a 60s /disks TTL cache (anti-smartctl-storm); unreachable agent -> Nincs adat, page never blocks. disk-health-check (6h) emits disk_health_degraded on a degradation only vs an in-memory baseline (first run silent, recovery/UNKNOWN never notify, multi-attr -> one event). No global banner (deliberate). Pairs with the hub allowlist bump. Tests: verdict table (>=90 red-proof), notifier emit, check first-run-silent (red-proof), degradation-once, recovery-silent, UNKNOWN-excluded, FAILING-critical, nil-smart card, TTL cache.
88 lines
3.3 KiB
Go
88 lines
3.3 KiB
Go
package agentapi
|
|
|
|
// DiskVerdict is the customer-facing disk-health verdict derived from a SmartSummary (v0.169.0).
|
|
// It is the SHARED source of truth for both the "Lemezek állapota" dashboard card and the 6-hourly
|
|
// degradation check — one pure function so the chip and the alert can never disagree.
|
|
type DiskVerdict int
|
|
|
|
const (
|
|
// DiskVerdictUnknown — no SMART data (nil / UNKNOWN / old agent). Renders "Nincs adat"; NEVER
|
|
// alarms and NEVER participates in degradation transitions (excluded both directions).
|
|
DiskVerdictUnknown DiskVerdict = iota
|
|
DiskVerdictOK // "Rendben" — PASSED, all counters clean
|
|
DiskVerdictWarn // "Figyelmeztetés" — PASSED but a wear/relocation counter is non-zero (or NVMe ≥90%)
|
|
DiskVerdictFail // "Hiba" — FAILING
|
|
)
|
|
|
|
// percentageUsedWarn is the NVMe wear threshold (inclusive) at which a still-PASSED disk warns.
|
|
const percentageUsedWarn = 90
|
|
|
|
// DiskVerdictFor maps a SmartSummary to a verdict per the v0.169.0 rules:
|
|
//
|
|
// FAILING → Hiba
|
|
// PASSED + any(reallocated>0, pending>0, offline_unc>0,
|
|
// critical_warning>0, media_errors>0,
|
|
// percentage_used >= 90) → Figyelmeztetés
|
|
// PASSED otherwise → Rendben
|
|
// nil / UNKNOWN / empty → Nincs adat
|
|
func DiskVerdictFor(s *SmartSummary) DiskVerdict {
|
|
if s == nil || s.Health == "" || s.Health == SmartUnknown {
|
|
return DiskVerdictUnknown
|
|
}
|
|
if s.Health == SmartFailing {
|
|
return DiskVerdictFail
|
|
}
|
|
// Health == PASSED (or any non-empty non-FAILING value we treat as passing): inspect the counters.
|
|
if positive(s.ReallocatedSectors) || positive(s.PendingSectors) || positive(s.OfflineUncorrectable) ||
|
|
positive(s.CriticalWarning) || positive(s.MediaErrors) || atLeast(s.PercentageUsed, percentageUsedWarn) {
|
|
return DiskVerdictWarn
|
|
}
|
|
return DiskVerdictOK
|
|
}
|
|
|
|
// Label is the exact Hungarian customer copy for the verdict (shared by the card chip and the email).
|
|
func (v DiskVerdict) Label() string {
|
|
switch v {
|
|
case DiskVerdictOK:
|
|
return "Rendben"
|
|
case DiskVerdictWarn:
|
|
return "Figyelmeztetés"
|
|
case DiskVerdictFail:
|
|
return "Hiba"
|
|
default:
|
|
return "Nincs adat"
|
|
}
|
|
}
|
|
|
|
// DegradedAttributes returns the human-readable Hungarian names of the attribute(s) that pushed a
|
|
// PASSED disk to Figyelmeztetés (empty for OK/Fail/Unknown) — for the alert body. FAILING is a
|
|
// whole-disk verdict with no single triggering counter, so it returns nil there.
|
|
func DegradedAttributes(s *SmartSummary) []string {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
var out []string
|
|
if positive(s.ReallocatedSectors) {
|
|
out = append(out, "áthelyezett szektorok")
|
|
}
|
|
if positive(s.PendingSectors) {
|
|
out = append(out, "függőben lévő szektorok")
|
|
}
|
|
if positive(s.OfflineUncorrectable) {
|
|
out = append(out, "javíthatatlan szektorok")
|
|
}
|
|
if positive(s.CriticalWarning) {
|
|
out = append(out, "kritikus figyelmeztetés")
|
|
}
|
|
if positive(s.MediaErrors) {
|
|
out = append(out, "adathordozó-hibák")
|
|
}
|
|
if atLeast(s.PercentageUsed, percentageUsedWarn) {
|
|
out = append(out, "elhasználódás")
|
|
}
|
|
return out
|
|
}
|
|
|
|
func positive(p *int) bool { return p != nil && *p > 0 }
|
|
func atLeast(p *int, n int) bool { return p != nil && *p >= n }
|