Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions collector/fixtures/e2e-output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ node_load5 0.37
# HELP node_md_blocks Total number of blocks on device.
# TYPE node_md_blocks gauge
node_md_blocks{device="md0"} 248896
node_md_blocks{device="md10"} 3.14159265e+08
node_md_blocks{device="md127"} 3.12319552e+08
node_md_blocks{device="md3"} 5.853468288e+09
node_md_blocks{device="md4"} 4.883648e+06
Expand All @@ -496,6 +497,7 @@ node_md_blocks{device="md9"} 523968
# HELP node_md_blocks_synced Number of blocks synced on device.
# TYPE node_md_blocks_synced gauge
node_md_blocks_synced{device="md0"} 248896
node_md_blocks_synced{device="md10"} 3.14159265e+08
node_md_blocks_synced{device="md127"} 3.12319552e+08
node_md_blocks_synced{device="md3"} 5.853468288e+09
node_md_blocks_synced{device="md4"} 4.883648e+06
Expand All @@ -506,6 +508,7 @@ node_md_blocks_synced{device="md9"} 523968
# HELP node_md_disks Total number of disks of device.
# TYPE node_md_disks gauge
node_md_disks{device="md0"} 2
node_md_disks{device="md10"} 2
node_md_disks{device="md127"} 2
node_md_disks{device="md3"} 8
node_md_disks{device="md4"} 2
Expand All @@ -516,6 +519,7 @@ node_md_disks{device="md9"} 4
# HELP node_md_disks_active Number of active disks of device.
# TYPE node_md_disks_active gauge
node_md_disks_active{device="md0"} 2
node_md_disks_active{device="md10"} 2
node_md_disks_active{device="md127"} 2
node_md_disks_active{device="md3"} 8
node_md_disks_active{device="md4"} 2
Expand All @@ -526,6 +530,7 @@ node_md_disks_active{device="md9"} 4
# HELP node_md_is_active Indicator whether the md-device is active or not.
# TYPE node_md_is_active gauge
node_md_is_active{device="md0"} 1
node_md_is_active{device="md10"} 1
node_md_is_active{device="md127"} 1
node_md_is_active{device="md3"} 1
node_md_is_active{device="md4"} 0
Expand Down
2 changes: 2 additions & 0 deletions collector/fixtures/proc/mdstat
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ md9 : active raid1 sdc2[2] sdd2[3] sdb2[1] sda2[0]
523968 blocks super 1.2 [4/4] [UUUU]
resync=DELAYED

md10 : active raid0 sda1[0] sdb1[1]
314159265 blocks 64k chunks

unused devices: <none>
5 changes: 5 additions & 0 deletions collector/fixtures/proc/mdstat_invalid
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Personalities : [invalid]
md3 : invalid
314159265 blocks 64k chunks

unused devices: <none>
38 changes: 33 additions & 5 deletions collector/mdadm_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

var (
statuslineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`)
raid0lineRE = regexp.MustCompile(`(\d+) blocks \d+k chunks`)
buildlineRE = regexp.MustCompile(`\((\d+)/\d+\)`)
)

Expand Down Expand Up @@ -76,6 +77,21 @@ func evalStatusline(statusline string) (active, total, size int64, err error) {
return active, total, size, nil
}

func evalRaid0line(statusline string) (size int64, err error) {
matches := raid0lineRE.FindStringSubmatch(statusline)

if len(matches) != 2 {
return 0, fmt.Errorf("invalid raid0 status line: %s", statusline)
}

size, err = strconv.ParseInt(matches[1], 10, 64)
if err != nil {
return 0, fmt.Errorf("%s in statusline: %s", err, statusline)
}

return size, nil
}

// Gets the size that has already been synced out of the sync-line.
func evalBuildline(buildline string) (int64, error) {
matches := buildlineRE.FindStringSubmatch(buildline)
Expand Down Expand Up @@ -108,7 +124,11 @@ func parseMdstat(mdStatusFilePath string) ([]mdStatus, error) {
mdStatusFile := string(content)

lines := strings.Split(mdStatusFile, "\n")
var currentMD string
var (
currentMD string
personality string
active, total, size int64
)

// Each md has at least the deviceline, statusline and one empty line afterwards
// so we will have probably something of the order len(lines)/3 devices
Expand All @@ -133,17 +153,25 @@ func parseMdstat(mdStatusFilePath string) ([]mdStatus, error) {
}

mainLine := strings.Split(l, " ")
if len(mainLine) < 3 {
if len(mainLine) < 4 {
return mdStates, fmt.Errorf("error parsing mdline: %s", l)
}
currentMD = mainLine[0] // name of md-device
isActive := (mainLine[2] == "active") // activity status of said md-device
currentMD = mainLine[0] // The name of the md-device.
isActive := (mainLine[2] == "active") // The activity status of the md-device.
personality = mainLine[3] // The personality type of the md-device.

if len(lines) <= i+3 {
return mdStates, fmt.Errorf("error parsing mdstat: entry for %s has fewer lines than expected", currentMD)
}

active, total, size, err := evalStatusline(lines[i+1]) // parse statusline, always present
switch personality {
case "raid0":
active = int64(len(mainLine) - 4) // Get the number of devices from the main line.
total = active // Raid0 active and total is always the same if active.
size, err = evalRaid0line(lines[i+1]) // Parse statusline, always present.
default:
active, total, size, err = evalStatusline(lines[i+1]) // Parse statusline, always present.
}

if err != nil {
return mdStates, fmt.Errorf("error parsing mdstat: %s", err)
Expand Down
9 changes: 9 additions & 0 deletions collector/mdadm_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestMdadm(t *testing.T) {
"md8": {"md8", true, 2, 2, 195310144, 16775552},
"md7": {"md7", true, 3, 4, 7813735424, 7813735424},
"md9": {"md9", true, 4, 4, 523968, 523968},
"md10": {"md10", true, 2, 2, 314159265, 314159265},
}

for _, md := range mdStates {
Expand All @@ -45,3 +46,11 @@ func TestMdadm(t *testing.T) {
t.Errorf("expected number of parsed md-device to be %d, but was %d", len(refs), len(mdStates))
}
}

func TestInvalidMdstat(t *testing.T) {
_, err := parseMdstat("fixtures/proc/mdstat_invalid")

if err == nil {
t.Fatalf("parsing of invalid reference file did not find any errors")
}
}