mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
Apply Unraid empty-slot semantics in storage health
Use the reviewed placeholder-filesystem rule when storage health assesses structured Unraid state, while retaining explicit DISK_NP_MISSING members as critical evidence. Change-source: pulse-maintainer Contract-Neutral: Unraid fsType=auto placeholder normalization is applied consistently at storage-health assessment without changing contracts
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
||||
unraidstatus "github.com/rcourtman/pulse-go-rewrite/internal/unraid"
|
||||
)
|
||||
|
||||
func AssessHostRAIDArray(array models.HostRAIDArray) Assessment {
|
||||
@@ -346,13 +347,16 @@ func unraidDiskStateCounts(storage models.HostUnraidStorage) (disabled, invalid,
|
||||
func isUnraidEmptySlot(disk models.HostUnraidDisk) bool {
|
||||
rawStatus := strings.ToUpper(strings.TrimSpace(disk.RawStatus))
|
||||
status := strings.ToLower(strings.TrimSpace(disk.Status))
|
||||
if unraidstatus.IsExplicitMissingMember(rawStatus) {
|
||||
return false
|
||||
}
|
||||
if !strings.Contains(rawStatus, "DISK_NP") && status != "missing" {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(disk.Device) == "" &&
|
||||
strings.TrimSpace(disk.Model) == "" &&
|
||||
strings.TrimSpace(disk.Serial) == "" &&
|
||||
strings.TrimSpace(disk.Filesystem) == "" &&
|
||||
!unraidstatus.HasMeaningfulFilesystem(disk.Filesystem) &&
|
||||
disk.SizeBytes == 0
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,8 @@ func TestAssessUnraidStorageTreatsEmptyNoPresentSlotsAsUnprotected(t *testing.T)
|
||||
{Name: "parity", Role: "parity", Status: "missing", RawStatus: "DISK_NP_DSBL"},
|
||||
{Name: "md1p1", Device: "/dev/sde", Status: "online", RawStatus: "DISK_OK", SizeBytes: 5860522532},
|
||||
{Name: "disk5", Role: "data", Status: "missing", RawStatus: "DISK_NP", Slot: 5},
|
||||
{Name: "parity2", Role: "parity", Status: "missing", RawStatus: "DISK_NP_DSBL", Slot: 29},
|
||||
{Name: "disk6", Role: "data", Status: "missing", RawStatus: "DISK_NP", Filesystem: "auto", Slot: 6},
|
||||
{Name: "parity2", Role: "parity", Status: "missing", RawStatus: "DISK_NP_DSBL", Filesystem: "auto", Slot: 29},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -281,6 +282,27 @@ func TestAssessUnraidStorageUsesDiskStatusesOverAggregateCounters(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssessUnraidStoragePreservesExplicitMissingMemberWithoutIdentity(t *testing.T) {
|
||||
assessment := AssessUnraidStorage(models.HostUnraidStorage{
|
||||
ArrayStarted: true,
|
||||
Disks: []models.HostUnraidDisk{
|
||||
{Name: "parity", Role: "parity", Status: "online"},
|
||||
{Name: "disk1", Role: "data", Status: "online"},
|
||||
{Name: "disk2", Role: "data", Status: "missing", RawStatus: "DISK_NP_MISSING", Filesystem: "auto"},
|
||||
},
|
||||
})
|
||||
|
||||
if assessment.Level != RiskCritical {
|
||||
t.Fatalf("Level = %q, want %q", assessment.Level, RiskCritical)
|
||||
}
|
||||
for _, reason := range assessment.Reasons {
|
||||
if reason.Code == "unraid_missing_disks" {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("explicit missing member without identity was not preserved: %+v", assessment.Reasons)
|
||||
}
|
||||
|
||||
func TestAssessUnraidStoragePreservesGenuineStructuredMissingDisk(t *testing.T) {
|
||||
assessment := AssessUnraidStorage(models.HostUnraidStorage{
|
||||
ArrayStarted: true,
|
||||
|
||||
Reference in New Issue
Block a user