feat(inspur): source-PRI timezone timeline, PPIN serial, NVMe fault storage status
Event ingestion now uses the source syslog PRI and an explicit-offset timezone timeline instead of assuming host-local time. CPU PPIN is exported as the source-backed CPU serial, and an active NVMe fault SEL event promotes the matching drive's storage status. See ADL-056, ADL-057. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
07c270cda2
commit
e7b8a8badc
@@ -0,0 +1,71 @@
|
||||
package inspur
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.mchus.pro/mchus/logpile/internal/models"
|
||||
)
|
||||
|
||||
func TestApplyStorageStatusFromEventsMarksOnlyFaultyNVMeCritical(t *testing.T) {
|
||||
hw := &models.HardwareConfig{}
|
||||
for i := 1; i <= 7; i++ {
|
||||
hw.Storage = append(hw.Storage, models.Storage{Slot: fmt.Sprintf("OB%02d", i), Type: "NVMe", Present: true})
|
||||
}
|
||||
ts := time.Date(2026, 7, 23, 23, 20, 32, 0, time.UTC)
|
||||
fault := models.Event{
|
||||
ID: "0DFF0702",
|
||||
Timestamp: ts,
|
||||
Source: "BMC",
|
||||
EventType: "Assert",
|
||||
Severity: models.SeverityCritical,
|
||||
Description: "NVME BP:Front0 NvmeIndex:6 drive fault: Status_Flags error.",
|
||||
}
|
||||
|
||||
applyStorageStatusFromEvents(hw, []models.Event{fault}, []models.Event{fault}, true)
|
||||
|
||||
for i := range hw.Storage {
|
||||
if hw.Storage[i].Slot == "OB07" {
|
||||
if hw.Storage[i].Status != "Critical" || hw.Storage[i].ErrorDescription == "" {
|
||||
t.Fatalf("expected OB07 critical with details, got %+v", hw.Storage[i])
|
||||
}
|
||||
if len(hw.Storage[i].StatusHistory) != 1 || hw.Storage[i].StatusChangedAt == nil {
|
||||
t.Fatalf("expected one source-backed status transition, got %+v", hw.Storage[i])
|
||||
}
|
||||
continue
|
||||
}
|
||||
if hw.Storage[i].Status != "" {
|
||||
t.Fatalf("unaffected %s must remain unknown/unset, got %q", hw.Storage[i].Slot, hw.Storage[i].Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyStorageStatusFromEventsDeassertClearsCriticalToUnknown(t *testing.T) {
|
||||
hw := &models.HardwareConfig{Storage: []models.Storage{{Slot: "OB07", Type: "NVMe", Present: true}}}
|
||||
asserted := models.Event{
|
||||
ID: "0DFF0702", Timestamp: time.Date(2026, 7, 23, 23, 20, 32, 0, time.UTC),
|
||||
EventType: "Assert", Severity: models.SeverityCritical,
|
||||
Description: "NVME BP:Front0 NvmeIndex:6 drive fault: Status_Flags error.",
|
||||
}
|
||||
deasserted := asserted
|
||||
deasserted.Timestamp = asserted.Timestamp.Add(time.Hour)
|
||||
deasserted.EventType = "Deassert"
|
||||
deasserted.Severity = models.SeverityInfo
|
||||
|
||||
applyStorageStatusFromEvents(hw, []models.Event{asserted, deasserted}, nil, true)
|
||||
|
||||
if hw.Storage[0].Status != "Unknown" || hw.Storage[0].ErrorDescription != "" {
|
||||
t.Fatalf("expected cleared drive fault to become Unknown, got %+v", hw.Storage[0])
|
||||
}
|
||||
if len(hw.Storage[0].StatusHistory) != 2 {
|
||||
t.Fatalf("expected assert/deassert history, got %+v", hw.Storage[0].StatusHistory)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorageFaultIndexIgnoresNVMeInventoryChange(t *testing.T) {
|
||||
event := models.Event{Description: "PCIE Device #NVME6 Device ID changed; Vendor ID changed"}
|
||||
if _, ok := storageFaultIndex(event); ok {
|
||||
t.Fatalf("inventory change must not be treated as an active drive fault")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user