From e1a896ca12f6f34ba6c946f93e58f80e68b50cff Mon Sep 17 00:00:00 2001 From: Niels Huylebroeck Date: Fri, 26 Feb 2021 16:42:46 +0100 Subject: [PATCH] Non systemd support with unittest (#8785) --- plugins/inputs/diskio/diskio_linux.go | 38 +++++++++++++++------- plugins/inputs/diskio/diskio_linux_test.go | 37 +++++++++++++-------- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/plugins/inputs/diskio/diskio_linux.go b/plugins/inputs/diskio/diskio_linux.go index 59822a277..bb11429f1 100644 --- a/plugins/inputs/diskio/diskio_linux.go +++ b/plugins/inputs/diskio/diskio_linux.go @@ -16,8 +16,6 @@ type diskInfoCache struct { values map[string]string } -var udevPath = "/run/udev/data" - func (d *DiskIO) diskInfo(devName string) (map[string]string, error) { var err error var stat unix.Stat_t @@ -37,9 +35,33 @@ func (d *DiskIO) diskInfo(devName string) (map[string]string, error) { return ic.values, nil } - major := unix.Major(uint64(stat.Rdev)) - minor := unix.Minor(uint64(stat.Rdev)) - udevDataPath := fmt.Sprintf("%s/b%d:%d", udevPath, major, minor) + var udevDataPath string + if ok && len(ic.udevDataPath) > 0 { + // We can reuse the udev data path from a "previous" entry. + // This allows us to also "poison" it during test scenarios + udevDataPath = ic.udevDataPath + } else { + major := unix.Major(uint64(stat.Rdev)) + minor := unix.Minor(uint64(stat.Rdev)) + udevDataPath = fmt.Sprintf("/run/udev/data/b%d:%d", major, minor) + + _, err := os.Stat(udevDataPath) + if err != nil { + // This path failed, try the fallback .udev style (non-systemd) + udevDataPath = fmt.Sprintf("/dev/.udev/db/block:%s", devName) + _, err := os.Stat(udevDataPath) + if err != nil { + // Giving up, cannot retrieve disk info + return nil, err + } + } + } + // Final open of the confirmed (or the previously detected/used) udev file + f, err := os.Open(udevDataPath) + defer f.Close() + if err != nil { + return nil, err + } di := map[string]string{} @@ -49,12 +71,6 @@ func (d *DiskIO) diskInfo(devName string) (map[string]string, error) { values: di, } - f, err := os.Open(udevDataPath) - if err != nil { - return nil, err - } - defer f.Close() - scnr := bufio.NewScanner(f) var devlinks bytes.Buffer for scnr.Scan() { diff --git a/plugins/inputs/diskio/diskio_linux_test.go b/plugins/inputs/diskio/diskio_linux_test.go index 1cb031bdc..4d7dc5c82 100644 --- a/plugins/inputs/diskio/diskio_linux_test.go +++ b/plugins/inputs/diskio/diskio_linux_test.go @@ -19,19 +19,31 @@ S:foo/bar/devlink1 `) // setupNullDisk sets up fake udev info as if /dev/null were a disk. -func setupNullDisk(t *testing.T) func() error { - td, err := ioutil.TempDir("", ".telegraf.TestDiskInfo") +func setupNullDisk(t *testing.T, s *DiskIO, devName string) func() error { + td, err := ioutil.TempFile("", ".telegraf.DiskInfoTest") require.NoError(t, err) - origUdevPath := udevPath + if s.infoCache == nil { + s.infoCache = make(map[string]diskInfoCache, 0) + } + ic, ok := s.infoCache[devName] + if !ok { + // No previous calls for the device were done, easy to poison the cache + s.infoCache[devName] = diskInfoCache{ + modifiedAt: 0, + udevDataPath: td.Name(), + values: map[string]string{}, + } + } + origUdevPath := ic.udevDataPath cleanFunc := func() error { - udevPath = origUdevPath - return os.RemoveAll(td) + ic.udevDataPath = origUdevPath + return os.Remove(td.Name()) } - udevPath = td - err = ioutil.WriteFile(td+"/b1:3", nullDiskInfo, 0644) // 1:3 is the 'null' device + ic.udevDataPath = td.Name() + _, err = td.Write(nullDiskInfo) if err != nil { cleanFunc() t.Fatal(err) @@ -41,10 +53,9 @@ func setupNullDisk(t *testing.T) func() error { } func TestDiskInfo(t *testing.T) { - clean := setupNullDisk(t) - defer clean() - s := &DiskIO{} + clean := setupNullDisk(t, s, "null") + defer clean() di, err := s.diskInfo("null") require.NoError(t, err) assert.Equal(t, "myval1", di["MY_PARAM_1"]) @@ -67,8 +78,6 @@ func TestDiskInfo(t *testing.T) { // DiskIOStats.diskName isn't a linux specific function, but dependent // functions are a no-op on non-Linux. func TestDiskIOStats_diskName(t *testing.T) { - defer setupNullDisk(t)() - tests := []struct { templates []string expected string @@ -88,6 +97,7 @@ func TestDiskIOStats_diskName(t *testing.T) { s := DiskIO{ NameTemplates: tc.templates, } + defer setupNullDisk(t, &s, "null")() name, _ := s.diskName("null") assert.Equal(t, tc.expected, name, "Templates: %#v", tc.templates) } @@ -96,11 +106,10 @@ func TestDiskIOStats_diskName(t *testing.T) { // DiskIOStats.diskTags isn't a linux specific function, but dependent // functions are a no-op on non-Linux. func TestDiskIOStats_diskTags(t *testing.T) { - defer setupNullDisk(t)() - s := &DiskIO{ DeviceTags: []string{"MY_PARAM_2"}, } + defer setupNullDisk(t, s, "null")() dt := s.diskTags("null") assert.Equal(t, map[string]string{"MY_PARAM_2": "myval2"}, dt) }