Fix false ZFS log/cache warnings

This commit is contained in:
rcourtman 2025-10-14 20:57:43 +00:00
parent 5f5d746caf
commit 881b7f9a54
5 changed files with 67 additions and 26 deletions

View file

@ -1279,6 +1279,13 @@ const Storage: Component = () => {
W/{device.checksumErrors}C errors)
</span>
</Show>
<Show when={device.message?.trim()}>
{(message) => (
<span class="ml-1 text-gray-500 dark:text-gray-400">
{message()}
</span>
)}
</Show>
</span>
</div>
)}

View file

@ -250,6 +250,7 @@ export interface ZFSDevice {
readErrors: number;
writeErrors: number;
checksumErrors: number;
message?: string;
}
export interface PBSInstance {

View file

@ -240,6 +240,7 @@ type ZFSDevice struct {
ReadErrors int64 `json:"readErrors"`
WriteErrors int64 `json:"writeErrors"`
ChecksumErrors int64 `json:"checksumErrors"`
Message string `json:"message,omitempty"` // Additional message provided by Proxmox (if any)
}
// CephCluster represents the health and capacity information for a Ceph cluster

View file

@ -48,6 +48,7 @@ func convertPoolInfoToModel(poolInfo *proxmox.ZFSPoolInfo) *models.ZFSPool {
ReadErrors: dev.ReadErrors,
WriteErrors: dev.WriteErrors,
ChecksumErrors: dev.ChecksumErrors,
Message: dev.Message,
})
}

View file

@ -96,7 +96,7 @@ func (p *ZFSPoolInfo) ConvertToModelZFSPool() *ZFSPool {
// Extract error counts from devices if available
pool.Devices = make([]ZFSDevice, 0)
for _, dev := range p.Devices {
pool.Devices = append(pool.Devices, convertDeviceRecursive(dev)...)
pool.Devices = append(pool.Devices, convertDeviceRecursive(dev, "")...)
}
// Calculate total errors from all devices
@ -132,32 +132,25 @@ type ZFSDevice struct {
WriteErrors int64 `json:"writeErrors"`
ChecksumErrors int64 `json:"checksumErrors"`
IsLeaf bool `json:"isLeaf"`
Message string `json:"message,omitempty"`
}
// convertDeviceRecursive flattens the device tree into a list
func convertDeviceRecursive(dev ZFSPoolDevice) []ZFSDevice {
func convertDeviceRecursive(dev ZFSPoolDevice, parentRole string) []ZFSDevice {
var devices []ZFSDevice
// Determine device type based on name and structure
deviceType := "disk"
if dev.Leaf == 0 && len(dev.Children) > 0 {
// It's a vdev (mirror, raidz, etc.)
if dev.Name == "mirror" || (len(dev.Name) >= 6 && dev.Name[:6] == "mirror") {
deviceType = "mirror"
} else if len(dev.Name) >= 5 && dev.Name[:5] == "raidz" {
deviceType = dev.Name // raidz, raidz2, raidz3
} else {
deviceType = "vdev"
}
}
name := strings.TrimSpace(dev.Name)
lowerName := strings.ToLower(name)
lowerName := strings.ToLower(strings.TrimSpace(dev.Name))
isSpare := lowerName == "spares" || strings.HasPrefix(lowerName, "spare")
if isSpare {
if deviceType == "vdev" {
deviceType = "spare"
} else if dev.Leaf == 1 {
deviceType = "spare"
role := parentRole
if role == "" {
switch {
case lowerName == "logs" || lowerName == "log" || strings.HasPrefix(lowerName, "slog"):
role = "log"
case lowerName == "cache" || strings.HasPrefix(lowerName, "l2arc"):
role = "cache"
case lowerName == "spares" || strings.HasPrefix(lowerName, "spare"):
role = "spare"
}
}
@ -166,6 +159,39 @@ func convertDeviceRecursive(dev ZFSPoolDevice) []ZFSDevice {
state = "UNKNOWN"
}
isVdev := dev.Leaf == 0 && len(dev.Children) > 0
deviceType := "disk"
if isVdev {
deviceType = "vdev"
}
switch {
case isVdev && (lowerName == "mirror" || strings.HasPrefix(lowerName, "mirror")):
deviceType = "mirror"
case isVdev && strings.HasPrefix(lowerName, "raidz"):
deviceType = lowerName // raidz, raidz2, raidz3
case isVdev && role == "log":
deviceType = "log"
case isVdev && role == "cache":
deviceType = "cache"
case isVdev && role == "spare":
deviceType = "spare"
case role == "log" && dev.Leaf == 1:
deviceType = "log"
case role == "cache" && dev.Leaf == 1:
deviceType = "cache"
}
isSpare := lowerName == "spares" || strings.HasPrefix(lowerName, "spare")
if isSpare {
if dev.Leaf == 1 {
deviceType = "spare"
} else {
deviceType = "spare-group"
}
}
healthyStates := map[string]bool{
"ONLINE": true,
"SPARE": true,
@ -173,26 +199,31 @@ func convertDeviceRecursive(dev ZFSPoolDevice) []ZFSDevice {
"INUSE": true,
}
if state == "UNKNOWN" && isSpare {
healthyStates[state] = true
if state == "UNKNOWN" {
if role == "log" || role == "cache" || role == "spare" || isSpare {
healthyStates[state] = true
}
}
// Add this device if it has errors or is not healthy (but skip healthy spares)
if !healthyStates[state] || dev.Read > 0 || dev.Write > 0 || dev.Cksum > 0 {
message := strings.TrimSpace(dev.Msg)
devices = append(devices, ZFSDevice{
Name: dev.Name,
Name: name,
Type: deviceType,
State: dev.State,
State: state,
ReadErrors: dev.Read,
WriteErrors: dev.Write,
ChecksumErrors: dev.Cksum,
IsLeaf: dev.Leaf == 1,
Message: message,
})
}
// Process children
for _, child := range dev.Children {
devices = append(devices, convertDeviceRecursive(child)...)
devices = append(devices, convertDeviceRecursive(child, role)...)
}
return devices