Pulse/pkg/fsfilters/filters.go
rcourtman db35ad7c88 Filter read-only filesystems from host agent disk metrics (related to #690)
Squashfs snap mounts on Ubuntu (and similar read-only filesystems like
erofs on Home Assistant OS) always report near-full usage and trigger
false disk alerts. The filter logic existed in Proxmox monitoring but
wasn't applied to host agents.

Changes:
- Extract read-only filesystem filter to shared pkg/fsfilters package
- Apply filter in hostmetrics.collectDisks() for host/docker agents
- Apply filter in monitor.ApplyHostReport() for backward compatibility
- Convert internal/monitoring/fs_filters.go to wrapper functions

This prevents squashfs, erofs, iso9660, cdfs, udf, cramfs, romfs, and
saturated overlay filesystems from generating alerts. Filtering happens
at both collection time (agents) and ingestion time (server) to ensure
older agents don't cause false alerts until they're updated.
2025-11-12 09:47:02 +00:00

56 lines
2 KiB
Go

package fsfilters
import "strings"
var readOnlyFilesystemPatterns = []struct {
reason string
substrings []string
}{
{reason: "erofs", substrings: []string{"erofs"}},
{reason: "squashfs", substrings: []string{"squashfs", "squash-fs"}},
{reason: "iso9660", substrings: []string{"iso9660"}},
{reason: "cdfs", substrings: []string{"cdfs"}},
{reason: "udf", substrings: []string{"udf"}},
{reason: "cramfs", substrings: []string{"cramfs"}},
{reason: "romfs", substrings: []string{"romfs"}},
}
// ReadOnlyFilesystemReason returns a label explaining why a filesystem should be
// ignored for usage calculations, along with a boolean indicating whether it is
// a read-only filesystem that always reports full usage. This helps us avoid
// false positives from immutable root images (overlay/squashfs/erofs) that ship
// with Home Assistant OS and similar appliances, as well as snap mounts on Ubuntu
// systems (see issues #505, #690).
func ReadOnlyFilesystemReason(fsType string, totalBytes, usedBytes uint64) (string, bool) {
ft := strings.ToLower(strings.TrimSpace(fsType))
if ft == "" {
return "", false
}
// Common read-only filesystem types used for immutable system partitions.
for _, pattern := range readOnlyFilesystemPatterns {
for _, needle := range pattern.substrings {
if strings.Contains(ft, needle) {
return pattern.reason, true
}
}
}
// Overlay-style filesystems can report 100% usage even though writes are
// redirected elsewhere. Treat them as read-only when the reported usage is
// saturated so we fall back to the writable layer metrics instead.
if strings.Contains(ft, "overlay") || strings.Contains(ft, "overlayfs") {
if totalBytes > 0 && usedBytes >= totalBytes {
return "overlay", true
}
}
return "", false
}
// ShouldIgnoreReadOnlyFilesystem reports whether the filesystem should be
// skipped from usage aggregation.
func ShouldIgnoreReadOnlyFilesystem(fsType string, totalBytes, usedBytes uint64) bool {
_, skip := ReadOnlyFilesystemReason(fsType, totalBytes, usedBytes)
return skip
}