summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/zfspool/collect.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/collectors/go.d.plugin/modules/zfspool/collect.go')
-rw-r--r--src/go/collectors/go.d.plugin/modules/zfspool/collect.go177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/zfspool/collect.go b/src/go/collectors/go.d.plugin/modules/zfspool/collect.go
new file mode 100644
index 0000000000..43994bfc1b
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/zfspool/collect.go
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package zfspool
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+var zpoolHealthStates = []string{
+ "online",
+ "degraded",
+ "faulted",
+ "offline",
+ "removed",
+ "unavail",
+ "suspended",
+}
+
+type zpoolStats struct {
+ name string
+ sizeBytes string
+ allocBytes string
+ freeBytes string
+ fragPerc string
+ capPerc string
+ dedupRatio string
+ health string
+}
+
+func (z *ZFSPool) collect() (map[string]int64, error) {
+ bs, err := z.exec.list()
+ if err != nil {
+ return nil, err
+ }
+
+ zpools, err := parseZpoolListOutput(bs)
+ if err != nil {
+ return nil, err
+ }
+
+ mx := make(map[string]int64)
+
+ z.collectZpoolListStats(mx, zpools)
+
+ return mx, nil
+}
+
+func (z *ZFSPool) collectZpoolListStats(mx map[string]int64, zpools []zpoolStats) {
+ seen := make(map[string]bool)
+
+ for _, zpool := range zpools {
+ seen[zpool.name] = true
+
+ if !z.zpools[zpool.name] {
+ z.addZpoolCharts(zpool.name)
+ z.zpools[zpool.name] = true
+ }
+
+ px := "zpool_" + zpool.name + "_"
+
+ if v, ok := parseInt(zpool.sizeBytes); ok {
+ mx[px+"size"] = v
+ }
+ if v, ok := parseInt(zpool.freeBytes); ok {
+ mx[px+"free"] = v
+ }
+ if v, ok := parseInt(zpool.allocBytes); ok {
+ mx[px+"alloc"] = v
+ }
+ if v, ok := parseFloat(zpool.capPerc); ok {
+ mx[px+"cap"] = int64(v)
+ }
+ if v, ok := parseFloat(zpool.fragPerc); ok {
+ mx[px+"frag"] = int64(v)
+ }
+ for _, s := range zpoolHealthStates {
+ mx[px+"health_state_"+s] = 0
+ }
+ mx[px+"health_state_"+zpool.health] = 1
+ }
+
+ for name := range z.zpools {
+ if !seen[name] {
+ z.removeZpoolCharts(name)
+ delete(z.zpools, name)
+ }
+ }
+}
+
+func parseZpoolListOutput(bs []byte) ([]zpoolStats, error) {
+ var lines []string
+ sc := bufio.NewScanner(bytes.NewReader(bs))
+ for sc.Scan() {
+ if text := strings.TrimSpace(sc.Text()); text != "" {
+ lines = append(lines, text)
+ }
+
+ }
+ if len(lines) < 2 {
+ return nil, fmt.Errorf("unexpected data: wanted >= 2 lines, got %d", len(lines))
+ }
+
+ headers := strings.Fields(lines[0])
+ if len(headers) == 0 {
+ return nil, fmt.Errorf("unexpected data: missing headers")
+ }
+
+ var zpools []zpoolStats
+
+ /*
+ # zpool list -p
+ NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
+ rpool 21367462298 9051643576 12240656794 - 33 42 1.00 ONLINE -
+ zion - - - - - - - FAULTED -
+ */
+
+ for _, line := range lines[1:] {
+ values := strings.Fields(line)
+ if len(values) != len(headers) {
+ return nil, fmt.Errorf("unequal columns: headers(%d) != values(%d)", len(headers), len(values))
+ }
+
+ var zpool zpoolStats
+
+ for i, v := range values {
+ v = strings.TrimSpace(v)
+ switch strings.ToLower(headers[i]) {
+ case "name":
+ zpool.name = v
+ case "size":
+ zpool.sizeBytes = v
+ case "alloc":
+ zpool.allocBytes = v
+ case "free":
+ zpool.freeBytes = v
+ case "frag":
+ zpool.fragPerc = v
+ case "cap":
+ zpool.capPerc = v
+ case "dedup":
+ zpool.dedupRatio = v
+ case "health":
+ zpool.health = strings.ToLower(v)
+ }
+
+ if last := i+1 == len(headers); last && zpool.name != "" && zpool.health != "" {
+ zpools = append(zpools, zpool)
+ }
+ }
+ }
+
+ if len(zpools) == 0 {
+ return nil, fmt.Errorf("unexpected data: missing pools")
+ }
+
+ return zpools, nil
+}
+
+func parseInt(s string) (int64, bool) {
+ if s == "-" {
+ return 0, false
+ }
+ v, err := strconv.ParseInt(s, 10, 64)
+ return v, err == nil
+}
+
+func parseFloat(s string) (float64, bool) {
+ if s == "-" {
+ return 0, false
+ }
+ v, err := strconv.ParseFloat(s, 64)
+ return v, err == nil
+}