feat: add mount option filtering to disk plugin (#11039)
This commit is contained in:
parent
fa723355f5
commit
62922de631
|
|
@ -17,6 +17,11 @@ Note that `used_percent` is calculated by doing `used / (used + free)`, _not_
|
|||
|
||||
## Ignore mount points by filesystem type.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
|
||||
|
||||
## Ignore mount points by mount options.
|
||||
## The 'mount' command reports options of all mounts in parathesis.
|
||||
## Bind mounts can be ignored with the special 'bind' option.
|
||||
# ignore_mount_opts = []
|
||||
```
|
||||
|
||||
### Docker container
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ type DiskStats struct {
|
|||
|
||||
LegacyMountPoints []string `toml:"mountpoints" deprecated:"0.10.2;2.0.0;use 'mount_points' instead"`
|
||||
|
||||
MountPoints []string `toml:"mount_points"`
|
||||
IgnoreFS []string `toml:"ignore_fs"`
|
||||
MountPoints []string `toml:"mount_points"`
|
||||
IgnoreFS []string `toml:"ignore_fs"`
|
||||
IgnoreMountOpts []string `toml:"ignore_mount_opts"`
|
||||
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
}
|
||||
|
|
@ -34,7 +35,7 @@ func (ds *DiskStats) Init() error {
|
|||
}
|
||||
|
||||
func (ds *DiskStats) Gather(acc telegraf.Accumulator) error {
|
||||
disks, partitions, err := ds.ps.DiskUsage(ds.MountPoints, ds.IgnoreFS)
|
||||
disks, partitions, err := ds.ps.DiskUsage(ds.MountPoints, ds.IgnoreMountOpts, ds.IgnoreFS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting disk usage info: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ func TestDiskUsage(t *testing.T) {
|
|||
Fstype: "ext4",
|
||||
Opts: []string{"rw", "noatime", "nodiratime", "errors=remount-ro"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime", "bind"},
|
||||
},
|
||||
}
|
||||
duAll := []diskUtil.UsageStat{
|
||||
{
|
||||
|
|
@ -65,18 +71,29 @@ func TestDiskUsage(t *testing.T) {
|
|||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
{
|
||||
Path: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("Partitions", true).Return(psAll, nil)
|
||||
mps.On("OSGetenv", "HOST_MOUNT_PREFIX").Return("")
|
||||
mps.On("PSDiskUsage", "/").Return(&duAll[0], nil)
|
||||
mps.On("PSDiskUsage", "/home").Return(&duAll[1], nil)
|
||||
mps.On("PSDiskUsage", "/var/rootbind").Return(&duAll[2], nil)
|
||||
|
||||
err = (&DiskStats{ps: mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
numDiskMetrics := acc.NFields()
|
||||
expectedAllDiskMetrics := 14
|
||||
expectedAllDiskMetrics := 21
|
||||
require.Equal(t, expectedAllDiskMetrics, numDiskMetrics)
|
||||
|
||||
tags1 := map[string]string{
|
||||
|
|
@ -91,6 +108,12 @@ func TestDiskUsage(t *testing.T) {
|
|||
"device": "sdb",
|
||||
"mode": "rw",
|
||||
}
|
||||
tags3 := map[string]string{
|
||||
"path": fmt.Sprintf("%cvar%crootbind", os.PathSeparator, os.PathSeparator),
|
||||
"fstype": "ext4",
|
||||
"device": "sda",
|
||||
"mode": "ro",
|
||||
}
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
|
|
@ -110,20 +133,35 @@ func TestDiskUsage(t *testing.T) {
|
|||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
}
|
||||
fields3 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
"used": uint64(100),
|
||||
"free": uint64(23),
|
||||
"inodes_total": uint64(1234),
|
||||
"inodes_free": uint64(234),
|
||||
"inodes_used": uint64(1000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields3, tags3)
|
||||
|
||||
// We expect 6 more DiskMetrics to show up with an explicit match on "/"
|
||||
// We expect 7 more DiskMetrics to show up with an explicit match on "/"
|
||||
// and /home not matching the /dev in MountPoints
|
||||
err = (&DiskStats{ps: &mps, MountPoints: []string{"/", "/dev"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+7, acc.NFields())
|
||||
|
||||
// We should see all the diskpoints as MountPoints includes both
|
||||
// / and /home
|
||||
err = (&DiskStats{ps: &mps, MountPoints: []string{"/", "/home"}}).Gather(&acc)
|
||||
// /, /home, and /var/rootbind
|
||||
err = (&DiskStats{ps: &mps, MountPoints: []string{"/", "/home", "/var/rootbind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2*expectedAllDiskMetrics+7, acc.NFields())
|
||||
require.Equal(t, expectedAllDiskMetrics+7*4, acc.NFields())
|
||||
|
||||
// We should see all the mounts as MountPoints except the bind mound
|
||||
err = (&DiskStats{ps: &mps, IgnoreMountOpts: []string{"bind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+7*6, acc.NFields())
|
||||
}
|
||||
|
||||
func TestDiskUsageHostMountPrefix(t *testing.T) {
|
||||
|
|
@ -287,8 +325,18 @@ func TestDiskStats(t *testing.T) {
|
|||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
{
|
||||
Path: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
duFiltered := []*diskUtil.UsageStat{
|
||||
duMountFiltered := []*diskUtil.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
|
|
@ -300,6 +348,28 @@ func TestDiskStats(t *testing.T) {
|
|||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
duOptFiltered := []*diskUtil.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
{
|
||||
Path: "/home",
|
||||
Fstype: "ext4",
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
}
|
||||
|
||||
psAll := []*diskUtil.PartitionStat{
|
||||
{
|
||||
|
|
@ -314,9 +384,15 @@ func TestDiskStats(t *testing.T) {
|
|||
Fstype: "ext4",
|
||||
Opts: []string{"rw", "noatime", "nodiratime", "errors=remount-ro"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime", "bind"},
|
||||
},
|
||||
}
|
||||
|
||||
psFiltered := []*diskUtil.PartitionStat{
|
||||
psMountFiltered := []*diskUtil.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
|
|
@ -324,16 +400,31 @@ func TestDiskStats(t *testing.T) {
|
|||
Opts: []string{"ro", "noatime", "nodiratime"},
|
||||
},
|
||||
}
|
||||
psOptFiltered := []*diskUtil.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sdb",
|
||||
Mountpoint: "/home",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"rw", "noatime", "nodiratime", "errors=remount-ro"},
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("DiskUsage", []string(nil), []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/dev"}, []string(nil)).Return(duFiltered, psFiltered, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/home"}, []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string(nil), []string(nil), []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/dev"}, []string(nil), []string(nil)).Return(duMountFiltered, psMountFiltered, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/home", "/var/rootbind"}, []string(nil), []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string(nil), []string{"bind"}, []string(nil)).Return(duOptFiltered, psOptFiltered, nil)
|
||||
|
||||
err = (&DiskStats{ps: &mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
numDiskMetrics := acc.NFields()
|
||||
expectedAllDiskMetrics := 14
|
||||
expectedAllDiskMetrics := 21
|
||||
require.Equal(t, expectedAllDiskMetrics, numDiskMetrics)
|
||||
|
||||
tags1 := map[string]string{
|
||||
|
|
@ -370,17 +461,22 @@ func TestDiskStats(t *testing.T) {
|
|||
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
|
||||
|
||||
// We expect 6 more DiskMetrics to show up with an explicit match on "/"
|
||||
// and /home not matching the /dev in MountPoints
|
||||
// We expect 7 more DiskMetrics to show up with an explicit match on "/"
|
||||
// and /home and /var/rootbind not matching the /dev in MountPoints
|
||||
err = (&DiskStats{ps: &mps, MountPoints: []string{"/", "/dev"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+7, acc.NFields())
|
||||
|
||||
// We should see all the diskpoints as MountPoints includes both
|
||||
// / and /home
|
||||
err = (&DiskStats{ps: &mps, MountPoints: []string{"/", "/home"}}).Gather(&acc)
|
||||
// /, /home, and /var/rootbind
|
||||
err = (&DiskStats{ps: &mps, MountPoints: []string{"/", "/home", "/var/rootbind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2*expectedAllDiskMetrics+7, acc.NFields())
|
||||
require.Equal(t, expectedAllDiskMetrics+7*4, acc.NFields())
|
||||
|
||||
// We should see all the mounts as MountPoints except the bind mound
|
||||
err = (&DiskStats{ps: &mps, IgnoreMountOpts: []string{"bind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+7*6, acc.NFields())
|
||||
}
|
||||
|
||||
func TestDiskUsageIssues(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ func (m *MockPS) CPUTimes(_, _ bool) ([]cpu.TimesStat, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
func (m *MockPS) DiskUsage(mountPointFilter []string, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error) {
|
||||
ret := m.Called(mountPointFilter, fstypeExclude)
|
||||
func (m *MockPS) DiskUsage(mountPointFilter []string, mountOptsExclude []string, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error) {
|
||||
ret := m.Called(mountPointFilter, mountOptsExclude, fstypeExclude)
|
||||
|
||||
r0 := ret.Get(0).([]*disk.UsageStat)
|
||||
r1 := ret.Get(1).([]*disk.PartitionStat)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
type PS interface {
|
||||
CPUTimes(perCPU, totalCPU bool) ([]cpu.TimesStat, error)
|
||||
DiskUsage(mountPointFilter []string, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error)
|
||||
DiskUsage(mountPointFilter []string, mountOptsExclude []string, fstypeExclude []string) ([]*disk.UsageStat, []*disk.PartitionStat, error)
|
||||
NetIO() ([]net.IOCountersStat, error)
|
||||
NetProto() ([]net.ProtoCountersStat, error)
|
||||
DiskIO(names []string) (map[string]disk.IOCountersStat, error)
|
||||
|
|
@ -91,6 +91,7 @@ func newSet() *set {
|
|||
|
||||
func (s *SystemPS) DiskUsage(
|
||||
mountPointFilter []string,
|
||||
mountOptsExclude []string,
|
||||
fstypeExclude []string,
|
||||
) ([]*disk.UsageStat, []*disk.PartitionStat, error) {
|
||||
parts, err := s.Partitions(true)
|
||||
|
|
@ -102,6 +103,10 @@ func (s *SystemPS) DiskUsage(
|
|||
for _, filter := range mountPointFilter {
|
||||
mountPointFilterSet.add(filter)
|
||||
}
|
||||
mountOptFilterSet := newSet()
|
||||
for _, filter := range mountOptsExclude {
|
||||
mountOptFilterSet.add(filter)
|
||||
}
|
||||
fstypeExcludeSet := newSet()
|
||||
for _, filter := range fstypeExclude {
|
||||
fstypeExcludeSet.add(filter)
|
||||
|
|
@ -120,9 +125,15 @@ func (s *SystemPS) DiskUsage(
|
|||
var partitions []*disk.PartitionStat
|
||||
hostMountPrefix := s.OSGetenv("HOST_MOUNT_PREFIX")
|
||||
|
||||
partitionRange:
|
||||
for i := range parts {
|
||||
p := parts[i]
|
||||
|
||||
for _, o := range p.Opts {
|
||||
if !mountOptFilterSet.empty() && mountOptFilterSet.has(o) {
|
||||
continue partitionRange
|
||||
}
|
||||
}
|
||||
// If there is a filter set and if the mount point is not a
|
||||
// member of the filter set, don't gather info on it.
|
||||
if !mountPointFilterSet.empty() && !mountPointFilterSet.has(p.Mountpoint) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue