From 881b7f9a54b906471df198a9452043650eaa0ff8 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 14 Oct 2025 20:57:43 +0000 Subject: [PATCH] Fix false ZFS log/cache warnings --- .../src/components/Storage/Storage.tsx | 7 ++ frontend-modern/src/types/api.ts | 1 + internal/models/models.go | 1 + internal/monitoring/monitor_optimized.go | 1 + pkg/proxmox/zfs.go | 83 +++++++++++++------ 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/frontend-modern/src/components/Storage/Storage.tsx b/frontend-modern/src/components/Storage/Storage.tsx index 07d3711..4ba6047 100644 --- a/frontend-modern/src/components/Storage/Storage.tsx +++ b/frontend-modern/src/components/Storage/Storage.tsx @@ -1279,6 +1279,13 @@ const Storage: Component = () => { W/{device.checksumErrors}C errors) + + {(message) => ( + + {message()} + + )} + )} diff --git a/frontend-modern/src/types/api.ts b/frontend-modern/src/types/api.ts index 2b9f627..5ef9781 100644 --- a/frontend-modern/src/types/api.ts +++ b/frontend-modern/src/types/api.ts @@ -250,6 +250,7 @@ export interface ZFSDevice { readErrors: number; writeErrors: number; checksumErrors: number; + message?: string; } export interface PBSInstance { diff --git a/internal/models/models.go b/internal/models/models.go index 4e029b8..ca12a16 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -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 diff --git a/internal/monitoring/monitor_optimized.go b/internal/monitoring/monitor_optimized.go index 2e4c998..c89d583 100644 --- a/internal/monitoring/monitor_optimized.go +++ b/internal/monitoring/monitor_optimized.go @@ -48,6 +48,7 @@ func convertPoolInfoToModel(poolInfo *proxmox.ZFSPoolInfo) *models.ZFSPool { ReadErrors: dev.ReadErrors, WriteErrors: dev.WriteErrors, ChecksumErrors: dev.ChecksumErrors, + Message: dev.Message, }) } diff --git a/pkg/proxmox/zfs.go b/pkg/proxmox/zfs.go index 5629387..841f42e 100644 --- a/pkg/proxmox/zfs.go +++ b/pkg/proxmox/zfs.go @@ -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