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.
136 lines
4.3 KiB
Go
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
|
|
}
|