Pulse/pkg/fsfilters/filters.go
rcourtman 61bb124692 Extract filesystem filtering logic into pkg/fsfilters
Move the inline filesystem skip logic from pollVMsAndContainersEfficient
into a reusable ShouldSkipFilesystem function. This consolidates filtering
for virtual filesystems (tmpfs, cgroup, etc.), network mounts (nfs, cifs,
fuse), and special mountpoints (/dev, /proc, /snap, etc.) into one tested
location.

Reduces cyclomatic complexity of pollVMsAndContainersEfficient and adds
28 test cases covering virtual fs types, network mounts, special mounts,
Windows paths, and edge cases.
2025-11-29 16:38:08 +00:00

136 lines
4.3 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
}
// virtualFSTypes are filesystem types that represent virtual/pseudo filesystems
// which should not be counted toward disk usage.
var virtualFSTypes = map[string]bool{
"tmpfs": true,
"devtmpfs": true,
"cgroup": true,
"cgroup2": true,
"sysfs": true,
"proc": true,
"devpts": true,
"securityfs": true,
"debugfs": true,
"tracefs": true,
"fusectl": true,
"configfs": true,
"pstore": true,
"hugetlbfs": true,
"mqueue": true,
"bpf": true,
}
// networkFSPatterns are substrings that indicate network/remote filesystems.
var networkFSPatterns = []string{"fuse", "9p", "nfs", "cifs", "smb"}
// specialMountPrefixes are mountpoint prefixes that indicate system mounts.
var specialMountPrefixes = []string{
"/dev",
"/proc",
"/sys",
"/run",
"/var/lib/docker",
"/snap",
}
// ShouldSkipFilesystem determines if a filesystem should be excluded from disk
// usage aggregation. It checks for read-only filesystems, virtual/pseudo filesystems,
// network mounts, and special system mountpoints. Returns skip=true if the filesystem
// should be excluded, along with a list of reason strings.
func ShouldSkipFilesystem(fsType, mountpoint string, totalBytes, usedBytes uint64) (skip bool, reasons []string) {
fsTypeLower := strings.ToLower(strings.TrimSpace(fsType))
// Check read-only filesystems (existing logic)
if reason, isReadOnly := ReadOnlyFilesystemReason(fsType, totalBytes, usedBytes); isReadOnly {
reasons = append(reasons, "read-only-"+reason)
}
// Check virtual filesystem types
if virtualFSTypes[fsTypeLower] {
reasons = append(reasons, "special-fs-type")
}
// Check network filesystem patterns
for _, pattern := range networkFSPatterns {
if strings.Contains(fsTypeLower, pattern) {
reasons = append(reasons, "special-fs-type")
break
}
}
// Check special mountpoint prefixes
for _, prefix := range specialMountPrefixes {
if strings.HasPrefix(mountpoint, prefix) {
reasons = append(reasons, "special-mountpoint")
break
}
}
// Check specific special mountpoints
if mountpoint == "/boot/efi" {
reasons = append(reasons, "special-mountpoint")
}
// Windows System Reserved partition
if mountpoint == "System Reserved" || strings.Contains(mountpoint, "System Reserved") {
reasons = append(reasons, "special-mountpoint")
}
return len(reasons) > 0, reasons
}