2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # Example for output from agent (contents of /proc/mdstat):
28 # ---------------------------------------------------------
29 # Personalities : [raid1]
30 # md1 : active raid1 dm-19[0] dm-9[1]
31 # 20971456 blocks [2/2] [UU]
32 # 20971456 blocks super 1.2 [2/2] [UU]
34 # md2 : active (auto-read-only) raid1 sda6[0] sdb6[1]
35 # 4200952 blocks super 1.0 [2/2] [UU]
36 # bitmap: 0/9 pages [0KB], 256KB chunk
38 # unused devices: <none>
39 # ---------------------------------------------------------
41 # Another example (with RAID 5 and spare disk (md2) and a RAID-0
43 # ---------------------------------------------------------
44 # Personalities : [raid1] [raid6] [raid5] [raid4]
45 # md2 : active raid5 sde1[3](S) sdd1[0] sdg1[2] sdf1[1]
46 # 976767872 blocks level 5, 64k chunk, algorithm 2 [3/3] [UUU]
48 # md0 : active raid1 sdb1[1] sda1[0]
49 # 104320 blocks [2/2] [UU]
51 # md1 : active raid1 sdb3[1] sda3[0]
52 # 486239232 blocks [2/2] [UU]
54 # md4 : active (auto-read-only) raid1 sda6[0] sdb6[1]
55 # 4200952 blocks super 1.0 [2/2] [UU]
57 # bitmap: 9/9 pages [36KB], 256KB chunk
59 # md3 : active raid0 sdb3[0] sda3[1]
60 # 16386048 blocks 64k chunks
62 # unused devices: <none>
63 # ---------------------------------------------------------
65 # Another example with RAID1 replacement gone wrong
66 # ---------------------------------------------------------
67 # Personalities : [raid1]
68 # md0 : active raid1 sdc3[3] sda3[2](F) sdb3[1]
69 # 48837528 blocks super 1.0 [2/2] [UU]
71 # md1 : active raid1 sdc4[3] sda4[2](F) sdb4[1]
72 # 193277940 blocks super 1.0 [2/2] [UU]
74 # unused devices: <none>
75 # ----------------------------------------------------------
77 # Another example with RAID5 being recovered
78 # ---------------------------------------------------------
79 # Personalities : [raid1] [raid6] [raid5] [raid4]
80 # md1 : active raid1 sdd1[1] sdc1[0]
81 # 10484668 blocks super 1.1 [2/2] [UU]
82 # bitmap: 1/1 pages [4KB], 65536KB chunk
84 # md127 : active raid5 sda3[0] sdb3[1] sdd3[4] sdc3[2]
85 # 11686055424 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/3] [UUU_]
86 # [======>..............] recovery = 31.8% (1241578496/3895351808) finish=746.8min speed=59224K/sec
88 # md0 : active raid1 sdb1[1] sda1[0]
89 # 10485688 blocks super 1.0 [2/2] [UU]
90 # bitmap: 0/1 pages [0KB], 65536KB chunk
92 # unused devices: <none>
93 # ----------------------------------------------------------
95 # And now for something completely different:
96 # ---------------------------------------------------------
97 # Personalities : [raid1] [raid10]
98 # md1 : active raid10 sdd6[3] sdb6[1] sda6[0]
99 # 1463055360 blocks 64K chunks 2 near-copies [4/3] [UU_U]
101 # md0 : active raid1 sdd1[3] sdb1[1] sda1[0]
102 # 104320 blocks [4/3] [UU_U]
104 # unused devices: <none>
105 # ---------------------------------------------------------
112 if line
[0].startswith("md") and line
[1] == ':':
113 if line
[3].startswith("(") and line
[3].endswith(")"):
114 raid_state
= line
[2] + line
[3]
122 spare_disks
= len([x
for x
in disk_list
if x
.endswith("(S)")])
123 failed_disks
= len([x
for x
in disk_list
if x
.endswith("(F)")])
125 instance
= parsed
.setdefault(
127 'raid_name': raid_name
,
128 'raid_state': raid_state
,
129 'spare_disks': spare_disks
,
130 'failed_disks': failed_disks
,
131 'active_disks': len(disk_list
) - spare_disks
- failed_disks
,
135 if line
[0].startswith("resync="):
136 k
, v
= line
[0].split("=")
137 instance
["%s_state" % k
] = v
140 if line
[0].startswith("[") and line
[0].endswith("]"):
141 for idx
, e
in enumerate(line
[1:]):
142 if e
.startswith("finish=") or e
.startswith("speed="):
145 elif e
in ["recovery", "resync"]:
146 instance
["%s_values" % e
] = line
[idx
+ 3]
149 if line
[-1].startswith("[") and line
[-1].endswith("]"):
150 instance
["working_disks"] = line
[-1][1:-1]
152 if len(line
) >= 2 and line
[-2].startswith("[") and line
[-2].endswith("]"):
153 for key
, value
in zip(["num_disks", "expected_disks"], line
[-2][1:-1].split('/')):
155 instance
[key
] = int(value
)
162 def inventory_md(parsed
):
163 for device
, attrs
in parsed
.iteritems():
164 if attrs
["raid_name"] != "raid0":
168 def check_md(item
, _no_params
, parsed
):
169 data
= parsed
.get(item
)
173 raid_state
= data
["raid_state"]
174 infotext
= "Status: %s" % raid_state
175 if raid_state
== "active" or raid_state
== "active(auto-read-only)":
178 infotext
+= " (should be 'active')"
180 yield state
, infotext
182 spare_disks
= data
["spare_disks"]
183 failed_disks
= data
["failed_disks"]
184 active_disks
= data
["active_disks"]
185 yield 0, "Spare: %s, Failed: %s, Active: %s" % (spare_disks
, failed_disks
, active_disks
)
187 num_disks
= data
["num_disks"]
188 expected_disks
= data
["expected_disks"]
189 working_disks
= data
["working_disks"]
191 infotext
= "Status: %s/%s, %s" % (num_disks
, expected_disks
, working_disks
)
192 if num_disks
== expected_disks
and active_disks
== working_disks
.count("U"):
197 header
= "[Resync/Recovery]"
199 if "resync_state" in data
:
201 infotexts
.append("Status: %s" % data
["resync_state"])
203 if "resync_values" in data
:
205 infotexts
.append(data
["resync_values"])
207 if "recovery_values" in data
:
208 header
= "[Recovery]"
209 infotexts
.append(data
["recovery_values"])
212 infotexts
.append("Finish: %s" % data
["finish"])
215 infotexts
.append("Speed: %s" % data
["speed"])
218 yield 1, "%s %s" % (header
, ", ".join(infotexts
))
222 'parse_function': parse_md
,
223 'inventory_function': inventory_md
,
224 'check_function': check_md
,
225 'service_description': 'MD Softraid %s',