diff --git a/collector/filesystem_linux.go b/collector/filesystem_linux.go index 59e909e252..86f0f1016b 100644 --- a/collector/filesystem_linux.go +++ b/collector/filesystem_linux.go @@ -18,7 +18,6 @@ package collector import ( "bufio" - "errors" "fmt" "io" "os" @@ -43,6 +42,9 @@ var mountTimeout = kingpin.Flag("collector.filesystem.mount-timeout", var statWorkerCount = kingpin.Flag("collector.filesystem.stat-workers", "how many stat calls to process simultaneously"). Hidden().Default("4").Int() +var procMountsPath = kingpin.Flag("collector.filesystem.proc-mounts-path", + "Override absolute path to mounts file. If set, disables the default /proc/1/mounts fallback logic."). + Default("").String() var stuckMounts = make(map[string]struct{}) var stuckMountsMtx = &sync.Mutex{} @@ -178,8 +180,13 @@ func stuckMountWatcher(mountPoint string, success chan struct{}, logger log.Logg } func mountPointDetails(logger log.Logger) ([]filesystemLabels, error) { - file, err := os.Open(procFilePath("1/mounts")) - if errors.Is(err, os.ErrNotExist) { + path := procFilePath("1/mounts") + if *procMountsPath != "" { + path = *procMountsPath + } + + file, err := os.Open(path) + if err != nil && *procMountsPath == "" { // Fallback to `/proc/mounts` if `/proc/1/mounts` is missing due hidepid. level.Debug(logger).Log("msg", "Reading root mounts failed, falling back to system mounts", "err", err) file, err = os.Open(procFilePath("mounts")) diff --git a/collector/filesystem_linux_test.go b/collector/filesystem_linux_test.go index 325ffc87b2..756456cde9 100644 --- a/collector/filesystem_linux_test.go +++ b/collector/filesystem_linux_test.go @@ -142,3 +142,43 @@ func TestPathRootfs(t *testing.T) { } } } + +func TestProcMountsPathOverride(t *testing.T) { + // Save and restore flag values so changes don't leak into other tests. + priorProcMountsPath := *procMountsPath + priorProcPath := *procPath + t.Cleanup(func() { + _, _ = kingpin.CommandLine.Parse([]string{ + "--path.procfs", priorProcPath, + "--collector.filesystem.proc-mounts-path", priorProcMountsPath, + }) + }) + + // --path.procfs points to fixtures with 25+ mount points, + // but --collector.filesystem.proc-mounts-path overrides to a file with only 1 mount. + _, err := kingpin.CommandLine.Parse([]string{ + "--path.procfs", "./fixtures/proc", + "--collector.filesystem.proc-mounts-path", "./fixtures_hidepid/proc/mounts", + }) + if err != nil { + t.Fatal(err) + } + + expected := map[string]string{ + "/": "", + } + + filesystems, err := mountPointDetails(log.NewNopLogger()) + if err != nil { + t.Fatal(err) + } + + if len(filesystems) != len(expected) { + t.Errorf("expected %d mounts, got %d", len(expected), len(filesystems)) + } + for _, fs := range filesystems { + if _, ok := expected[fs.mountPoint]; !ok { + t.Errorf("Got unexpected %s", fs.mountPoint) + } + } +}