From c77b8f2e77f02180f964230b5b938499c765c9e2 Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Fri, 25 Aug 2017 21:57:35 +0200 Subject: [PATCH] Don't fail parsing of zpool stats if pool health is UNAVAIL on FreeBSD (#3149) --- plugins/inputs/zfs/zfs_freebsd.go | 65 ++++++++++++++------------ plugins/inputs/zfs/zfs_freebsd_test.go | 50 ++++++++++++++++++++ 2 files changed, 86 insertions(+), 29 deletions(-) diff --git a/plugins/inputs/zfs/zfs_freebsd.go b/plugins/inputs/zfs/zfs_freebsd.go index 7ee72a140..63bbdd6e6 100644 --- a/plugins/inputs/zfs/zfs_freebsd.go +++ b/plugins/inputs/zfs/zfs_freebsd.go @@ -33,41 +33,48 @@ func (z *Zfs) gatherPoolStats(acc telegraf.Accumulator) (string, error) { tags := map[string]string{"pool": col[0], "health": col[8]} fields := map[string]interface{}{} - size, err := strconv.ParseInt(col[1], 10, 64) - if err != nil { - return "", fmt.Errorf("Error parsing size: %s", err) - } - fields["size"] = size + if tags["health"] == "UNAVAIL" { - alloc, err := strconv.ParseInt(col[2], 10, 64) - if err != nil { - return "", fmt.Errorf("Error parsing allocation: %s", err) - } - fields["allocated"] = alloc + fields["size"] = int64(0) - free, err := strconv.ParseInt(col[3], 10, 64) - if err != nil { - return "", fmt.Errorf("Error parsing free: %s", err) - } - fields["free"] = free + } else { - frag, err := strconv.ParseInt(strings.TrimSuffix(col[5], "%"), 10, 0) - if err != nil { // This might be - for RO devs - frag = 0 - } - fields["fragmentation"] = frag + size, err := strconv.ParseInt(col[1], 10, 64) + if err != nil { + return "", fmt.Errorf("Error parsing size: %s", err) + } + fields["size"] = size - capval, err := strconv.ParseInt(col[6], 10, 0) - if err != nil { - return "", fmt.Errorf("Error parsing capacity: %s", err) - } - fields["capacity"] = capval + alloc, err := strconv.ParseInt(col[2], 10, 64) + if err != nil { + return "", fmt.Errorf("Error parsing allocation: %s", err) + } + fields["allocated"] = alloc - dedup, err := strconv.ParseFloat(strings.TrimSuffix(col[7], "x"), 32) - if err != nil { - return "", fmt.Errorf("Error parsing dedupratio: %s", err) + free, err := strconv.ParseInt(col[3], 10, 64) + if err != nil { + return "", fmt.Errorf("Error parsing free: %s", err) + } + fields["free"] = free + + frag, err := strconv.ParseInt(strings.TrimSuffix(col[5], "%"), 10, 0) + if err != nil { // This might be - for RO devs + frag = 0 + } + fields["fragmentation"] = frag + + capval, err := strconv.ParseInt(col[6], 10, 0) + if err != nil { + return "", fmt.Errorf("Error parsing capacity: %s", err) + } + fields["capacity"] = capval + + dedup, err := strconv.ParseFloat(strings.TrimSuffix(col[7], "x"), 32) + if err != nil { + return "", fmt.Errorf("Error parsing dedupratio: %s", err) + } + fields["dedupratio"] = dedup } - fields["dedupratio"] = dedup acc.AddFields("zfs_pool", fields, tags) } diff --git a/plugins/inputs/zfs/zfs_freebsd_test.go b/plugins/inputs/zfs/zfs_freebsd_test.go index 193c2816f..60b95a39d 100644 --- a/plugins/inputs/zfs/zfs_freebsd_test.go +++ b/plugins/inputs/zfs/zfs_freebsd_test.go @@ -22,6 +22,15 @@ func mock_zpool() ([]string, error) { return zpool_output, nil } +// $ zpool list -Hp +var zpool_output_unavail = []string{ + "temp2 - - - - - - - UNAVAIL -", +} + +func mock_zpool_unavail() ([]string, error) { + return zpool_output_unavail, nil +} + // sysctl -q kstat.zfs.misc.arcstats // sysctl -q kstat.zfs.misc.vdev_cache_stats @@ -82,6 +91,41 @@ func TestZfsPoolMetrics(t *testing.T) { acc.AssertContainsTaggedFields(t, "zfs_pool", poolMetrics, tags) } +func TestZfsPoolMetrics_unavail(t *testing.T) { + + var acc testutil.Accumulator + + z := &Zfs{ + KstatMetrics: []string{"vdev_cache_stats"}, + sysctl: mock_sysctl, + zpool: mock_zpool_unavail, + } + err := z.Gather(&acc) + require.NoError(t, err) + + require.False(t, acc.HasMeasurement("zfs_pool")) + acc.Metrics = nil + + z = &Zfs{ + KstatMetrics: []string{"vdev_cache_stats"}, + PoolMetrics: true, + sysctl: mock_sysctl, + zpool: mock_zpool_unavail, + } + err = z.Gather(&acc) + require.NoError(t, err) + + //one pool, UNAVAIL + tags := map[string]string{ + "pool": "temp2", + "health": "UNAVAIL", + } + + poolMetrics := getTemp2PoolMetrics() + + acc.AssertContainsTaggedFields(t, "zfs_pool", poolMetrics, tags) +} + func TestZfsGeneratesMetrics(t *testing.T) { var acc testutil.Accumulator @@ -128,6 +172,12 @@ func getFreeNasBootPoolMetrics() map[string]interface{} { } } +func getTemp2PoolMetrics() map[string]interface{} { + return map[string]interface{}{ + "size": int64(0), + } +} + func getKstatMetricsVdevOnly() map[string]interface{} { return map[string]interface{}{ "vdev_cache_stats_misses": int64(87789),