summaryrefslogtreecommitdiff
path: root/vendor/github.com/prometheus/procfs/mdstat.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/prometheus/procfs/mdstat.go')
-rw-r--r--vendor/github.com/prometheus/procfs/mdstat.go111
1 files changed, 77 insertions, 34 deletions
diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go
index 71c106782..2af3ada18 100644
--- a/vendor/github.com/prometheus/procfs/mdstat.go
+++ b/vendor/github.com/prometheus/procfs/mdstat.go
@@ -22,8 +22,8 @@ import (
)
var (
- statuslineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`)
- buildlineRE = regexp.MustCompile(`\((\d+)/\d+\)`)
+ statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`)
+ recoveryLineRE = regexp.MustCompile(`\((\d+)/\d+\)`)
)
// MDStat holds info parsed from /proc/mdstat.
@@ -34,8 +34,12 @@ type MDStat struct {
ActivityState string
// Number of active disks.
DisksActive int64
- // Total number of disks the device consists of.
+ // Total number of disks the device requires.
DisksTotal int64
+ // Number of failed disks.
+ DisksFailed int64
+ // Spare disks in the device.
+ DisksSpare int64
// Number of blocks the device holds.
BlocksTotal int64
// Number of blocks on the device that are in sync.
@@ -59,29 +63,38 @@ func (fs FS) MDStat() ([]MDStat, error) {
// parseMDStat parses data from mdstat file (/proc/mdstat) and returns a slice of
// structs containing the relevant info.
-func parseMDStat(mdstatData []byte) ([]MDStat, error) {
+func parseMDStat(mdStatData []byte) ([]MDStat, error) {
mdStats := []MDStat{}
- lines := strings.Split(string(mdstatData), "\n")
- for i, l := range lines {
- if strings.TrimSpace(l) == "" || l[0] == ' ' ||
- strings.HasPrefix(l, "Personalities") || strings.HasPrefix(l, "unused") {
+ lines := strings.Split(string(mdStatData), "\n")
+
+ for i, line := range lines {
+ if strings.TrimSpace(line) == "" || line[0] == ' ' ||
+ strings.HasPrefix(line, "Personalities") ||
+ strings.HasPrefix(line, "unused") {
continue
}
- deviceFields := strings.Fields(l)
+ deviceFields := strings.Fields(line)
if len(deviceFields) < 3 {
- return nil, fmt.Errorf("not enough fields in mdline (expected at least 3): %s", l)
+ return nil, fmt.Errorf("not enough fields in mdline (expected at least 3): %s", line)
}
- mdName := deviceFields[0]
- activityState := deviceFields[2]
+ mdName := deviceFields[0] // mdx
+ state := deviceFields[2] // active or inactive
if len(lines) <= i+3 {
- return mdStats, fmt.Errorf("missing lines for md device %s", mdName)
+ return nil, fmt.Errorf(
+ "error parsing %s: too few lines for md device",
+ mdName,
+ )
}
- active, total, size, err := evalStatusLine(lines[i+1])
+ // Failed disks have the suffix (F) & Spare disks have the suffix (S).
+ fail := int64(strings.Count(line, "(F)"))
+ spare := int64(strings.Count(line, "(S)"))
+ active, total, size, err := evalStatusLine(lines[i], lines[i+1])
+
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("error parsing md device lines: %s", err)
}
syncLineIdx := i + 2
@@ -89,20 +102,38 @@ func parseMDStat(mdstatData []byte) ([]MDStat, error) {
syncLineIdx++
}
- // If device is recovering/syncing at the moment, get the number of currently
+ // If device is syncing at the moment, get the number of currently
// synced bytes, otherwise that number equals the size of the device.
syncedBlocks := size
- if strings.Contains(lines[syncLineIdx], "recovery") || strings.Contains(lines[syncLineIdx], "resync") {
- syncedBlocks, err = evalRecoveryLine(lines[syncLineIdx])
- if err != nil {
- return nil, err
+ recovering := strings.Contains(lines[syncLineIdx], "recovery")
+ resyncing := strings.Contains(lines[syncLineIdx], "resync")
+
+ // Append recovery and resyncing state info.
+ if recovering || resyncing {
+ if recovering {
+ state = "recovering"
+ } else {
+ state = "resyncing"
+ }
+
+ // Handle case when resync=PENDING or resync=DELAYED.
+ if strings.Contains(lines[syncLineIdx], "PENDING") ||
+ strings.Contains(lines[syncLineIdx], "DELAYED") {
+ syncedBlocks = 0
+ } else {
+ syncedBlocks, err = evalRecoveryLine(lines[syncLineIdx])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing sync line in md device %s: %s", mdName, err)
+ }
}
}
mdStats = append(mdStats, MDStat{
Name: mdName,
- ActivityState: activityState,
+ ActivityState: state,
DisksActive: active,
+ DisksFailed: fail,
+ DisksSpare: spare,
DisksTotal: total,
BlocksTotal: size,
BlocksSynced: syncedBlocks,
@@ -112,39 +143,51 @@ func parseMDStat(mdstatData []byte) ([]MDStat, error) {
return mdStats, nil
}
-func evalStatusLine(statusline string) (active, total, size int64, err error) {
- matches := statuslineRE.FindStringSubmatch(statusline)
- if len(matches) != 4 {
- return 0, 0, 0, fmt.Errorf("unexpected statusline: %s", statusline)
- }
+func evalStatusLine(deviceLine, statusLine string) (active, total, size int64, err error) {
- size, err = strconv.ParseInt(matches[1], 10, 64)
+ sizeStr := strings.Fields(statusLine)[0]
+ size, err = strconv.ParseInt(sizeStr, 10, 64)
if err != nil {
- return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err)
+ return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
+ }
+
+ if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") {
+ // In the device deviceLine, only disks have a number associated with them in [].
+ total = int64(strings.Count(deviceLine, "["))
+ return total, total, size, nil
+ }
+
+ if strings.Contains(deviceLine, "inactive") {
+ return 0, 0, size, nil
+ }
+
+ matches := statusLineRE.FindStringSubmatch(statusLine)
+ if len(matches) != 4 {
+ return 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine)
}
total, err = strconv.ParseInt(matches[2], 10, 64)
if err != nil {
- return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err)
+ return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
}
active, err = strconv.ParseInt(matches[3], 10, 64)
if err != nil {
- return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err)
+ return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
}
return active, total, size, nil
}
-func evalRecoveryLine(buildline string) (syncedBlocks int64, err error) {
- matches := buildlineRE.FindStringSubmatch(buildline)
+func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, err error) {
+ matches := recoveryLineRE.FindStringSubmatch(recoveryLine)
if len(matches) != 2 {
- return 0, fmt.Errorf("unexpected buildline: %s", buildline)
+ return 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine)
}
syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
if err != nil {
- return 0, fmt.Errorf("%s in buildline: %s", err, buildline)
+ return 0, fmt.Errorf("%s in recoveryLine: %s", err, recoveryLine)
}
return syncedBlocks, nil