Fix false ZFS log/cache warnings
This commit is contained in:
parent
5f5d746caf
commit
881b7f9a54
5 changed files with 67 additions and 26 deletions
|
|
@ -1279,6 +1279,13 @@ const Storage: Component = () => {
|
||||||
W/{device.checksumErrors}C errors)
|
W/{device.checksumErrors}C errors)
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
|
<Show when={device.message?.trim()}>
|
||||||
|
{(message) => (
|
||||||
|
<span class="ml-1 text-gray-500 dark:text-gray-400">
|
||||||
|
{message()}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Show>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -250,6 +250,7 @@ export interface ZFSDevice {
|
||||||
readErrors: number;
|
readErrors: number;
|
||||||
writeErrors: number;
|
writeErrors: number;
|
||||||
checksumErrors: number;
|
checksumErrors: number;
|
||||||
|
message?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PBSInstance {
|
export interface PBSInstance {
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,7 @@ type ZFSDevice struct {
|
||||||
ReadErrors int64 `json:"readErrors"`
|
ReadErrors int64 `json:"readErrors"`
|
||||||
WriteErrors int64 `json:"writeErrors"`
|
WriteErrors int64 `json:"writeErrors"`
|
||||||
ChecksumErrors int64 `json:"checksumErrors"`
|
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
|
// CephCluster represents the health and capacity information for a Ceph cluster
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ func convertPoolInfoToModel(poolInfo *proxmox.ZFSPoolInfo) *models.ZFSPool {
|
||||||
ReadErrors: dev.ReadErrors,
|
ReadErrors: dev.ReadErrors,
|
||||||
WriteErrors: dev.WriteErrors,
|
WriteErrors: dev.WriteErrors,
|
||||||
ChecksumErrors: dev.ChecksumErrors,
|
ChecksumErrors: dev.ChecksumErrors,
|
||||||
|
Message: dev.Message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func (p *ZFSPoolInfo) ConvertToModelZFSPool() *ZFSPool {
|
||||||
// Extract error counts from devices if available
|
// Extract error counts from devices if available
|
||||||
pool.Devices = make([]ZFSDevice, 0)
|
pool.Devices = make([]ZFSDevice, 0)
|
||||||
for _, dev := range p.Devices {
|
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
|
// Calculate total errors from all devices
|
||||||
|
|
@ -132,32 +132,25 @@ type ZFSDevice struct {
|
||||||
WriteErrors int64 `json:"writeErrors"`
|
WriteErrors int64 `json:"writeErrors"`
|
||||||
ChecksumErrors int64 `json:"checksumErrors"`
|
ChecksumErrors int64 `json:"checksumErrors"`
|
||||||
IsLeaf bool `json:"isLeaf"`
|
IsLeaf bool `json:"isLeaf"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertDeviceRecursive flattens the device tree into a list
|
// convertDeviceRecursive flattens the device tree into a list
|
||||||
func convertDeviceRecursive(dev ZFSPoolDevice) []ZFSDevice {
|
func convertDeviceRecursive(dev ZFSPoolDevice, parentRole string) []ZFSDevice {
|
||||||
var devices []ZFSDevice
|
var devices []ZFSDevice
|
||||||
|
|
||||||
// Determine device type based on name and structure
|
name := strings.TrimSpace(dev.Name)
|
||||||
deviceType := "disk"
|
lowerName := strings.ToLower(name)
|
||||||
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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lowerName := strings.ToLower(strings.TrimSpace(dev.Name))
|
role := parentRole
|
||||||
isSpare := lowerName == "spares" || strings.HasPrefix(lowerName, "spare")
|
if role == "" {
|
||||||
if isSpare {
|
switch {
|
||||||
if deviceType == "vdev" {
|
case lowerName == "logs" || lowerName == "log" || strings.HasPrefix(lowerName, "slog"):
|
||||||
deviceType = "spare"
|
role = "log"
|
||||||
} else if dev.Leaf == 1 {
|
case lowerName == "cache" || strings.HasPrefix(lowerName, "l2arc"):
|
||||||
deviceType = "spare"
|
role = "cache"
|
||||||
|
case lowerName == "spares" || strings.HasPrefix(lowerName, "spare"):
|
||||||
|
role = "spare"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,6 +159,39 @@ func convertDeviceRecursive(dev ZFSPoolDevice) []ZFSDevice {
|
||||||
state = "UNKNOWN"
|
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{
|
healthyStates := map[string]bool{
|
||||||
"ONLINE": true,
|
"ONLINE": true,
|
||||||
"SPARE": true,
|
"SPARE": true,
|
||||||
|
|
@ -173,26 +199,31 @@ func convertDeviceRecursive(dev ZFSPoolDevice) []ZFSDevice {
|
||||||
"INUSE": true,
|
"INUSE": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if state == "UNKNOWN" && isSpare {
|
if state == "UNKNOWN" {
|
||||||
healthyStates[state] = true
|
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)
|
// 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 {
|
if !healthyStates[state] || dev.Read > 0 || dev.Write > 0 || dev.Cksum > 0 {
|
||||||
|
message := strings.TrimSpace(dev.Msg)
|
||||||
|
|
||||||
devices = append(devices, ZFSDevice{
|
devices = append(devices, ZFSDevice{
|
||||||
Name: dev.Name,
|
Name: name,
|
||||||
Type: deviceType,
|
Type: deviceType,
|
||||||
State: dev.State,
|
State: state,
|
||||||
ReadErrors: dev.Read,
|
ReadErrors: dev.Read,
|
||||||
WriteErrors: dev.Write,
|
WriteErrors: dev.Write,
|
||||||
ChecksumErrors: dev.Cksum,
|
ChecksumErrors: dev.Cksum,
|
||||||
IsLeaf: dev.Leaf == 1,
|
IsLeaf: dev.Leaf == 1,
|
||||||
|
Message: message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process children
|
// Process children
|
||||||
for _, child := range dev.Children {
|
for _, child := range dev.Children {
|
||||||
devices = append(devices, convertDeviceRecursive(child)...)
|
devices = append(devices, convertDeviceRecursive(child, role)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return devices
|
return devices
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue