Merge ~aieri/charm-hw-health:lp1832906 into charm-hw-health:master
- Git
- lp:~aieri/charm-hw-health
- lp1832906
- Merge into master
Status: | Merged |
---|---|
Approved by: | Paul Goins |
Approved revision: | 7ae7e1f45d2f4507fa4f5f8168fa73a4e32b8eaa |
Merged at revision: | 7ae7e1f45d2f4507fa4f5f8168fa73a4e32b8eaa |
Proposed branch: | ~aieri/charm-hw-health:lp1832906 |
Merge into: | charm-hw-health:master |
Diff against target: |
702 lines (+256/-86) 13 files modified
src/files/mdadm/cron_mdadm.py (+93/-31) src/tests/hw-health-samples/mdadm.output (+4/-4) src/tests/hw-health-samples/mdadm.output.critical.1 (+4/-4) src/tests/hw-health-samples/mdadm.output.critical.2 (+33/-0) src/tests/hw-health-samples/mdadm.output.warning (+33/-0) src/tests/unit/lib/samples.py (+17/-0) src/tests/unit/test_check_mdadm.py (+10/-18) src/tests/unit/test_check_megacli.py (+7/-7) src/tests/unit/test_check_nvme.py (+5/-3) src/tests/unit/test_check_sas2ircu.py (+5/-4) src/tests/unit/test_check_sas3ircu.py (+5/-3) src/tests/unit/test_cron_mdadm.py (+35/-8) src/tests/unit/test_hwdiscovery.py (+5/-4) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paul Goins | Approve | ||
Drew Freiberger (community) | Approve | ||
Stuart Bishop | Pending | ||
Review via email:
|
Commit message
Fix issue with cron_mdadm.py which causes degraded state to not be reported
Closes-Bug: 1832906
Description of the change
Fix issue with cron_mdadm.py which causes degraded state to not be reported
There was a formatting assumption which broke the detection of the degraded
flag in the State section of each device report from mdadm --detail <devices>
This merge adds code to split the State flags and check for both degraded and
recovering states and sets alert status based on the combination of states.
Also added is the direct detection of a "removed" member of the raid.
Closes-Bug: 1832906
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrea Ieri (aieri) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrea Ieri (aieri) wrote : | # |
Which itself was an attempt at superseding 385837
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrea Ieri (aieri) wrote : | # |
Comments from 385837 should have now been addressed.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Drew Freiberger (afreiberger) wrote : | # |
Please see inline comment echoing Stu's point about API oddity on get_device_stats. We moved the try-except of the parse_output function into get_device_stats, but didn't refactor this exception to be API clean. It reads a bit hackish.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Drew Freiberger (afreiberger) wrote : | # |
lgtm, this addresses the bug, the comments prior, and includes all of the updates from the history of the other merge.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Paul Goins (vultaire) wrote : | # |
I haven't fully reviewed this yet, but - it seems we're missing the samples.py module into which the get_sample() function was refactored?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrea Ieri (aieri) wrote : | # |
Yes, I had done a git commit -a and missed committing hte samples.py file. The MR has now been updated
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Paul Goins (vultaire) : | # |
Preview Diff
1 | diff --git a/src/files/mdadm/cron_mdadm.py b/src/files/mdadm/cron_mdadm.py |
2 | index 0b0b365..5aaafa4 100755 |
3 | --- a/src/files/mdadm/cron_mdadm.py |
4 | +++ b/src/files/mdadm/cron_mdadm.py |
5 | @@ -6,24 +6,28 @@ import shutil |
6 | import subprocess |
7 | import sys |
8 | |
9 | -OUTPUT_FILE = "/var/lib/nagios/mdadm.out" |
10 | -TEMP_FILE = "/tmp/mdadm.out" |
11 | +OUTPUT_FILE = '/var/lib/nagios/mdadm.out' |
12 | +TEMP_FILE = '/tmp/mdadm.out' |
13 | |
14 | |
15 | def get_devices(): |
16 | - if os.path.exists("/sbin/mdadm"): |
17 | + if os.path.exists('/sbin/mdadm'): |
18 | try: |
19 | - devices_raw = subprocess.check_output(["/sbin/mdadm", "--detail", "--scan"]) |
20 | - devices_re = re.compile(r"^ARRAY\s+([^ ]+) ") |
21 | + devices_raw = subprocess.check_output( |
22 | + ['/sbin/mdadm', '--detail', '--scan'] |
23 | + ) |
24 | + devices_re = re.compile(r'^ARRAY\s+([^ ]+) ') |
25 | devices = set() |
26 | - for line in devices_raw.decode().split("\n"): |
27 | + for line in devices_raw.decode().split('\n'): |
28 | line = line.strip() |
29 | device_re = devices_re.match(line) |
30 | if device_re is not None: |
31 | devices.add(device_re.group(1)) |
32 | return devices |
33 | except subprocess.CalledProcessError as error: |
34 | - rc = generate_output("CRITICAL: get_devices error - {}".format(error)) |
35 | + rc = generate_output( |
36 | + 'CRITICAL: get_devices error - {}'.format(error) |
37 | + ) |
38 | if rc: |
39 | sys.exit(0) |
40 | return set() |
41 | @@ -31,90 +35,148 @@ def get_devices(): |
42 | |
43 | def generate_output(msg): |
44 | try: |
45 | - with open(TEMP_FILE, "w") as fd: |
46 | + with open(TEMP_FILE, 'w') as fd: |
47 | fd.write(msg) |
48 | shutil.move(TEMP_FILE, OUTPUT_FILE) |
49 | return True |
50 | except Exception as error: |
51 | - print("Unable to generate output file:", error) |
52 | + print('Unable to generate output file:', error) |
53 | return False |
54 | |
55 | |
56 | def get_devices_stats(devices): |
57 | - mdadm_detail = ["/sbin/mdadm", "--detail"] |
58 | + mdadm_detail = ['/sbin/mdadm', '--detail'] |
59 | mdadm_detail.extend(sorted(devices)) |
60 | + |
61 | devices_details_raw = subprocess.check_output(mdadm_detail) |
62 | |
63 | - devices_re = r"^(/\S+):$" |
64 | - state_re = r"^\s*State\s+:\s+(\S+)$" |
65 | - status_re = r"^\s*(Active|Working|Failed|Spare) Devices\s+:\s+(\d+)$" |
66 | + devices_re = r'^(/\S+):$' |
67 | + state_re = r'^\s*State\s+:\s+(.+)\s*$' |
68 | + status_re = r'^\s*(Active|Working|Failed|Spare) Devices\s+:\s+(\d+)$' |
69 | + rebuild_status_re = r'^\s*Rebuild Status\s+:\s+(\d+%\s+\S+)$' |
70 | + removed_re = r'^\s*-\s+0\s+0\s+(\d+)\s+removed$' |
71 | + # 4 8 162 3 spare rebuilding /dev/sdk2 |
72 | + rebuilding_re = r'^\s*\d+\s+\d+\s+\d+\s+\d+\s+\S+\s+rebuilding\s+(\S+)$' |
73 | |
74 | devices_cre = re.compile(devices_re) |
75 | state_cre = re.compile(state_re) |
76 | status_cre = re.compile(status_re) |
77 | + rebuild_status_cre = re.compile(rebuild_status_re) |
78 | + removed_cre = re.compile(removed_re) |
79 | + rebuilding_cre = re.compile(rebuilding_re) |
80 | |
81 | device = None |
82 | devices_stats = {} |
83 | - for line in devices_details_raw.decode().split("\n"): |
84 | + for line in devices_details_raw.decode().split('\n'): |
85 | line = line.rstrip() |
86 | m = devices_cre.match(line) |
87 | if m: |
88 | device = m.group(1) |
89 | devices_stats[device] = { |
90 | - "stats": {"Active": 0, "Working": 0, "Failed": 0, "Spare": 0}, |
91 | - "degraded": False, |
92 | + 'stats': { |
93 | + 'Active': 0, |
94 | + 'Working': 0, |
95 | + 'Failed': 0, |
96 | + 'Spare': 0, |
97 | + }, |
98 | + 'rebuild_status': '', |
99 | + 'degraded': False, |
100 | + 'recovering': False, |
101 | + 'removed': [], |
102 | + 'rebuilding': [], |
103 | } |
104 | continue |
105 | |
106 | m = state_cre.match(line) |
107 | if m: |
108 | - if "degraded" in m.group(1) and device: |
109 | - devices_stats[device]["degraded"] = True |
110 | + # format for State line can be "clean" or "clean, degraded" or "active, degraded, rebuilding", etc. |
111 | + states = m.group(1).split(", ") |
112 | + if 'degraded' in states and device: |
113 | + devices_stats[device]['degraded'] = True |
114 | + if 'recovering' in states and device: |
115 | + devices_stats[device]['recovering'] = True |
116 | continue |
117 | |
118 | m = status_cre.match(line) |
119 | if m and device: |
120 | - devices_stats[device]["stats"][m.group(1)] = int(m.group(2)) |
121 | + devices_stats[device]['stats'][m.group(1)] = int(m.group(2)) |
122 | + continue |
123 | + |
124 | + m = removed_cre.match(line) |
125 | + if m and device: |
126 | + devices_stats[device]['removed'].append(m.group(1)) |
127 | + continue |
128 | + |
129 | + m = rebuild_status_cre.match(line) |
130 | + if m and device: |
131 | + devices_stats[device]['rebuild_status'] = m.group(1) |
132 | + continue |
133 | + |
134 | + m = rebuilding_cre.match(line) |
135 | + if m and device: |
136 | + devices_stats[device]['rebuilding'].append(m.group(1)) |
137 | + continue |
138 | + |
139 | return devices_stats |
140 | |
141 | |
142 | def parse_output(): |
143 | devices = get_devices() |
144 | if len(devices) == 0: |
145 | - return generate_output("WARNING: unexpectedly checked no devices") |
146 | + return generate_output('WARNING: unexpectedly checked no devices') |
147 | |
148 | try: |
149 | devices_stats = get_devices_stats(devices) |
150 | except subprocess.CalledProcessError as error: |
151 | - return generate_output("WARNING: error executing mdadm: {}".format(error)) |
152 | + return generate_output( |
153 | + 'WARNING: error executing mdadm: {}'.format(error) |
154 | + ) |
155 | |
156 | msg = [] |
157 | critical = False |
158 | + warning = False |
159 | for device in devices_stats: |
160 | + parts = [] |
161 | # Is device degraded? |
162 | - if devices_stats[device]["degraded"]: |
163 | + if devices_stats[device]['degraded'] and devices_stats[device]['recovering']: |
164 | + warning = True |
165 | + parts = ['{} recovering'.format(device)] |
166 | + elif devices_stats[device]['degraded']: |
167 | critical = True |
168 | - parts = ["{} degraded".format(device)] |
169 | + parts = ['{} degraded'.format(device)] |
170 | else: |
171 | - parts = ["{} ok".format(device)] |
172 | + parts = ['{} ok'.format(device)] |
173 | |
174 | # If Failed drives are found, list counters (how many?) |
175 | - failed_cnt = devices_stats[device]["stats"].get("Failed", 0) |
176 | + failed_cnt = devices_stats[device]['stats'].get('Failed', 0) |
177 | if failed_cnt > 0: |
178 | critical = True |
179 | dev_stats = [ |
180 | - "{}[{}]".format(status, devices_stats[device]["stats"][status]) |
181 | - for status in sorted(devices_stats[device]["stats"]) |
182 | + '{}[{}]'.format(status, devices_stats[device]['stats'][status]) |
183 | + for status in sorted(devices_stats[device]['stats']) |
184 | ] |
185 | parts.extend(dev_stats) |
186 | - msg.append(", ".join(parts)) |
187 | + |
188 | + if len(devices_stats[device]['removed']) != 0: |
189 | + critical = True |
190 | + members = " and ".join(devices_stats[device]['removed']) |
191 | + parts.append('RaidDevice(s) {} marked removed'.format(members)) |
192 | + |
193 | + if len(devices_stats[device]['rebuilding']) != 0: |
194 | + rebuilding_members = " ".join(devices_stats[device]['rebuilding']) |
195 | + rebuild_status = devices_stats[device]['rebuild_status'] |
196 | + parts.append('{} rebuilding ({})'.format(rebuilding_members, rebuild_status)) |
197 | + |
198 | + msg.append(', '.join(parts)) |
199 | |
200 | if critical: |
201 | - msg = "CRITICAL: {}".format("; ".join(msg)) |
202 | + msg = 'CRITICAL: {}'.format('; '.join(msg)) |
203 | + elif warning: |
204 | + msg = 'WARNING: {}'.format('; '.join(msg)) |
205 | else: |
206 | - msg = "OK: {}".format("; ".join(msg)) |
207 | + msg = 'OK: {}'.format('; '.join(msg)) |
208 | return generate_output(msg) |
209 | |
210 | |
211 | -if __name__ == "__main__": |
212 | +if __name__ == '__main__': |
213 | parse_output() |
214 | diff --git a/src/tests/hw-health-samples/mdadm.output b/src/tests/hw-health-samples/mdadm.output |
215 | index 9356757..c5d498d 100644 |
216 | --- a/src/tests/hw-health-samples/mdadm.output |
217 | +++ b/src/tests/hw-health-samples/mdadm.output |
218 | @@ -15,7 +15,7 @@ Working Devices : 2 |
219 | Failed Devices : 0 |
220 | Spare Devices : 0 |
221 | |
222 | - Name : fnos-nvme05:0 (local to host fnos-nvme05) |
223 | + Name : some-host:0 (local to host some-host) |
224 | UUID : dfaf7413:7551b000:56dd7442:5b020adb |
225 | Events : 51 |
226 | |
227 | @@ -39,7 +39,7 @@ Working Devices : 2 |
228 | Failed Devices : 0 |
229 | Spare Devices : 0 |
230 | |
231 | - Name : fnos-nvme05:1 (local to host fnos-nvme05) |
232 | + Name : some-host:1 (local to host some-host) |
233 | UUID : 8946258c:a6246ca7:8d3dc20a:33bcabcb |
234 | Events : 51 |
235 | |
236 | @@ -65,7 +65,7 @@ Working Devices : 2 |
237 | Failed Devices : 0 |
238 | Spare Devices : 0 |
239 | |
240 | - Name : fnos-nvme05:3 (local to host fnos-nvme05) |
241 | + Name : some-host:3 (local to host some-host) |
242 | UUID : ae461b25:13219daa:75846e9e:2e5a52f1 |
243 | Events : 1418 |
244 | |
245 | @@ -91,7 +91,7 @@ Working Devices : 2 |
246 | Failed Devices : 0 |
247 | Spare Devices : 0 |
248 | |
249 | - Name : fnos-nvme05:2 (local to host fnos-nvme05) |
250 | + Name : some-host:2 (local to host some-host) |
251 | UUID : a83fda21:56cf85d4:99c802ed:c07c4f76 |
252 | Events : 5715 |
253 | |
254 | diff --git a/src/tests/hw-health-samples/mdadm.output.critical b/src/tests/hw-health-samples/mdadm.output.critical.1 |
255 | similarity index 95% |
256 | rename from src/tests/hw-health-samples/mdadm.output.critical |
257 | rename to src/tests/hw-health-samples/mdadm.output.critical.1 |
258 | index 4bdab35..05ec12b 100644 |
259 | --- a/src/tests/hw-health-samples/mdadm.output.critical |
260 | +++ b/src/tests/hw-health-samples/mdadm.output.critical.1 |
261 | @@ -15,7 +15,7 @@ Working Devices : 2 |
262 | Failed Devices : 0 |
263 | Spare Devices : 0 |
264 | |
265 | - Name : fnos-nvme05:0 (local to host fnos-nvme05) |
266 | + Name : some-host:0 (local to host some-host) |
267 | UUID : dfaf7413:7551b000:56dd7442:5b020adb |
268 | Events : 51 |
269 | |
270 | @@ -39,7 +39,7 @@ Working Devices : 1 |
271 | Failed Devices : 1 |
272 | Spare Devices : 0 |
273 | |
274 | - Name : fnos-nvme05:1 (local to host fnos-nvme05) |
275 | + Name : some-host:1 (local to host some-host) |
276 | UUID : 8946258c:a6246ca7:8d3dc20a:33bcabcb |
277 | Events : 51 |
278 | |
279 | @@ -65,7 +65,7 @@ Working Devices : 2 |
280 | Failed Devices : 0 |
281 | Spare Devices : 0 |
282 | |
283 | - Name : fnos-nvme05:3 (local to host fnos-nvme05) |
284 | + Name : some-host:3 (local to host some-host) |
285 | UUID : ae461b25:13219daa:75846e9e:2e5a52f1 |
286 | Events : 1418 |
287 | |
288 | @@ -91,7 +91,7 @@ Working Devices : 2 |
289 | Failed Devices : 0 |
290 | Spare Devices : 0 |
291 | |
292 | - Name : fnos-nvme05:2 (local to host fnos-nvme05) |
293 | + Name : some-host:2 (local to host some-host) |
294 | UUID : a83fda21:56cf85d4:99c802ed:c07c4f76 |
295 | Events : 5715 |
296 | |
297 | diff --git a/src/tests/hw-health-samples/mdadm.output.critical.2 b/src/tests/hw-health-samples/mdadm.output.critical.2 |
298 | new file mode 100644 |
299 | index 0000000..3b1d268 |
300 | --- /dev/null |
301 | +++ b/src/tests/hw-health-samples/mdadm.output.critical.2 |
302 | @@ -0,0 +1,33 @@ |
303 | +/dev/md1: |
304 | + Version : 1.2 |
305 | + Creation Time : Wed Jun 26 18:18:55 2019 |
306 | + Raid Level : raid10 |
307 | + Array Size : 7812235264 (7450.33 GiB 7999.73 GB) |
308 | + Used Dev Size : 3906117632 (3725.16 GiB 3999.86 GB) |
309 | + Raid Devices : 4 |
310 | + Total Devices : 3 |
311 | + Persistence : Superblock is persistent |
312 | + |
313 | + Intent Bitmap : Internal |
314 | + |
315 | + Update Time : Mon Oct 28 17:27:54 2019 |
316 | + State : active, degraded |
317 | + Active Devices : 3 |
318 | + Working Devices : 3 |
319 | + Failed Devices : 0 |
320 | + Spare Devices : 0 |
321 | + |
322 | + Layout : near=2 |
323 | + Chunk Size : 512K |
324 | + |
325 | +Consistency Policy : bitmap |
326 | + |
327 | + Name : some-host:1 (local to host some-host) |
328 | + UUID : 3887c84d:ebd28589:5a4b5d9e:3c83a25d |
329 | + Events : 491275 |
330 | + |
331 | + Number Major Minor RaidDevice State |
332 | + 0 8 98 0 active sync set-A /dev/sdg2 |
333 | + 1 8 114 1 active sync set-B /dev/sdh2 |
334 | + - 0 0 2 removed |
335 | + 3 8 162 3 active sync set-B /dev/sdk2 |
336 | diff --git a/src/tests/hw-health-samples/mdadm.output.warning b/src/tests/hw-health-samples/mdadm.output.warning |
337 | new file mode 100644 |
338 | index 0000000..21f9090 |
339 | --- /dev/null |
340 | +++ b/src/tests/hw-health-samples/mdadm.output.warning |
341 | @@ -0,0 +1,33 @@ |
342 | +/dev/md1: |
343 | + Version : 1.2 |
344 | + Creation Time : Thu Oct 18 17:41:01 2018 |
345 | + Raid Level : raid10 |
346 | + Array Size : 7812235264 (7450.33 GiB 7999.73 GB) |
347 | + Used Dev Size : 3906117632 (3725.16 GiB 3999.86 GB) |
348 | + Raid Devices : 4 |
349 | + Total Devices : 4 |
350 | + Persistence : Superblock is persistent |
351 | + |
352 | + Intent Bitmap : Internal |
353 | + |
354 | + Update Time : Mon Oct 28 18:46:34 2019 |
355 | + State : active, degraded, recovering |
356 | + Active Devices : 3 |
357 | +Working Devices : 4 |
358 | + Failed Devices : 0 |
359 | + Spare Devices : 1 |
360 | + |
361 | + Layout : near=2 |
362 | + Chunk Size : 512K |
363 | + |
364 | + Rebuild Status : 13% complete |
365 | + |
366 | + Name : some-host:1 (local to host some-host) |
367 | + UUID : fed3a645:1f742fd3:1685dda5:71794407 |
368 | + Events : 750593 |
369 | + |
370 | + Number Major Minor RaidDevice State |
371 | + 0 8 98 0 active sync set-A /dev/sdg2 |
372 | + 1 8 114 1 active sync set-B /dev/sdh2 |
373 | + 2 8 146 2 active sync set-A /dev/sdj2 |
374 | + 4 8 162 3 spare rebuilding /dev/sdk2 |
375 | diff --git a/src/tests/unit/lib/samples.py b/src/tests/unit/lib/samples.py |
376 | new file mode 100644 |
377 | index 0000000..a0790ee |
378 | --- /dev/null |
379 | +++ b/src/tests/unit/lib/samples.py |
380 | @@ -0,0 +1,17 @@ |
381 | +import os |
382 | +import glob |
383 | + |
384 | +SAMPLES_DIR = os.path.join( |
385 | + os.path.dirname(__file__), |
386 | + '..', |
387 | + '..', |
388 | + 'hw-health-samples' |
389 | +) |
390 | + |
391 | + |
392 | +def get_sample(name): |
393 | + sample = os.path.join(SAMPLES_DIR, name) |
394 | + if glob.has_magic(sample): |
395 | + return glob.glob(sample) |
396 | + else: |
397 | + return sample |
398 | diff --git a/src/tests/unit/test_check_mdadm.py b/src/tests/unit/test_check_mdadm.py |
399 | index 231ca4f..0314032 100644 |
400 | --- a/src/tests/unit/test_check_mdadm.py |
401 | +++ b/src/tests/unit/test_check_mdadm.py |
402 | @@ -6,24 +6,23 @@ import unittest.mock as mock |
403 | |
404 | import nagios_plugin3 |
405 | |
406 | -sys.path.append('files/mdadm') |
407 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
408 | +from samples import get_sample # noqa: E402 |
409 | + |
410 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../files/mdadm')) |
411 | import check_mdadm # noqa: E402 |
412 | |
413 | |
414 | class TestCheckMdadm(unittest.TestCase): |
415 | def test_parse_output_crit(self): |
416 | - check_mdadm.INPUT_FILE = os.path.join( |
417 | - os.getcwd(), 'tests', 'hw-health-samples', |
418 | - 'mdadm.output.nrpe.critical') |
419 | + check_mdadm.INPUT_FILE = get_sample('mdadm.output.nrpe.critical') |
420 | expected = 'CRITICAL: critical msg' |
421 | with self.assertRaises(nagios_plugin3.CriticalError) as context: |
422 | check_mdadm.parse_output() |
423 | self.assertTrue(expected in str(context.exception)) |
424 | |
425 | def test_parse_output_warn(self): |
426 | - check_mdadm.INPUT_FILE = os.path.join( |
427 | - os.getcwd(), 'tests', 'hw-health-samples', |
428 | - 'mdadm.output.nrpe.warning') |
429 | + check_mdadm.INPUT_FILE = get_sample('mdadm.output.nrpe.warning') |
430 | expected = 'WARNING: warning msg' |
431 | with self.assertRaises(nagios_plugin3.WarnError) as context: |
432 | check_mdadm.parse_output() |
433 | @@ -31,8 +30,7 @@ class TestCheckMdadm(unittest.TestCase): |
434 | |
435 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
436 | def test_parse_output_ok(self, mock_print): |
437 | - check_mdadm.INPUT_FILE = os.path.join( |
438 | - os.getcwd(), 'tests', 'hw-health-samples', 'mdadm.output.nrpe.ok') |
439 | + check_mdadm.INPUT_FILE = get_sample('mdadm.output.nrpe.ok') |
440 | check_mdadm.parse_output() |
441 | self.assertEqual( |
442 | mock_print.getvalue(), |
443 | @@ -41,9 +39,7 @@ class TestCheckMdadm(unittest.TestCase): |
444 | |
445 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
446 | def test_parse_output_unknown_filenotfound(self, mock_print): |
447 | - check_mdadm.INPUT_FILE = os.path.join( |
448 | - os.getcwd(), 'tests', 'hw-health-samples', |
449 | - 'thisfiledoesnotexist') |
450 | + check_mdadm.INPUT_FILE = get_sample('thisfiledoesnotexist') |
451 | expected = 'UNKNOWN: file not found ({})'.format( |
452 | check_mdadm.INPUT_FILE) |
453 | with self.assertRaises(nagios_plugin3.UnknownError) as context: |
454 | @@ -52,9 +48,7 @@ class TestCheckMdadm(unittest.TestCase): |
455 | |
456 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
457 | def test_parse_output_unknown1(self, mock_print): |
458 | - check_mdadm.INPUT_FILE = os.path.join( |
459 | - os.getcwd(), 'tests', 'hw-health-samples', |
460 | - 'mdadm.output.nrpe.unknown.1') |
461 | + check_mdadm.INPUT_FILE = get_sample('mdadm.output.nrpe.unknown.1') |
462 | check_mdadm.parse_output() |
463 | self.assertEqual( |
464 | mock_print.getvalue(), |
465 | @@ -63,9 +57,7 @@ class TestCheckMdadm(unittest.TestCase): |
466 | |
467 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
468 | def test_parse_output_unknown2(self, mock_print): |
469 | - check_mdadm.INPUT_FILE = os.path.join( |
470 | - os.getcwd(), 'tests', 'hw-health-samples', |
471 | - 'mdadm.output.nrpe.unknown.2') |
472 | + check_mdadm.INPUT_FILE = get_sample('mdadm.output.nrpe.unknown.2') |
473 | check_mdadm.parse_output() |
474 | self.assertEqual( |
475 | mock_print.getvalue(), |
476 | diff --git a/src/tests/unit/test_check_megacli.py b/src/tests/unit/test_check_megacli.py |
477 | index 988075a..4207953 100644 |
478 | --- a/src/tests/unit/test_check_megacli.py |
479 | +++ b/src/tests/unit/test_check_megacli.py |
480 | @@ -6,15 +6,17 @@ import unittest.mock as mock |
481 | |
482 | import nagios_plugin3 |
483 | |
484 | -sys.path.append('files/megacli') |
485 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
486 | +from samples import get_sample # noqa: E402 |
487 | + |
488 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../files/megacli')) |
489 | import check_megacli # noqa: E402 |
490 | |
491 | |
492 | class TestCheckMegaCLI(unittest.TestCase): |
493 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
494 | def test_parse_output(self, mock_print): |
495 | - check_megacli.INPUT_FILE = os.path.join( |
496 | - os.getcwd(), 'tests', 'hw-health-samples', 'megacli.output.1') |
497 | + check_megacli.INPUT_FILE = get_sample('megacli.output.1') |
498 | check_megacli.parse_output() |
499 | actual = mock_print.getvalue() |
500 | expected = 'OK: Optimal, ldrives[1], pdrives[4]\n' |
501 | @@ -22,8 +24,7 @@ class TestCheckMegaCLI(unittest.TestCase): |
502 | |
503 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
504 | def test_parse_output_critical_singledrive(self, mock_print): |
505 | - check_megacli.INPUT_FILE = os.path.join( |
506 | - os.getcwd(), 'tests', 'hw-health-samples', 'megacli.output.nrpe.critical.1') |
507 | + check_megacli.INPUT_FILE = get_sample('megacli.output.nrpe.critical.1') |
508 | expected = 'CRITICAL: adapter(0):ld(0):state(Degraded)' |
509 | with self.assertRaises(nagios_plugin3.CriticalError) as context: |
510 | check_megacli.parse_output() |
511 | @@ -31,8 +32,7 @@ class TestCheckMegaCLI(unittest.TestCase): |
512 | |
513 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
514 | def test_parse_output_critical_multiple(self, mock_print): |
515 | - check_megacli.INPUT_FILE = os.path.join( |
516 | - os.getcwd(), 'tests', 'hw-health-samples', 'megacli.output.nrpe.critical.2') |
517 | + check_megacli.INPUT_FILE = get_sample('megacli.output.nrpe.critical.2') |
518 | expected = ('CRITICAL: adapter(0):ld(0):state(Degraded);' |
519 | ' adapter(0):ld(4):state(Degraded)') |
520 | with self.assertRaises(nagios_plugin3.CriticalError) as context: |
521 | diff --git a/src/tests/unit/test_check_nvme.py b/src/tests/unit/test_check_nvme.py |
522 | index 53466e4..097fd76 100644 |
523 | --- a/src/tests/unit/test_check_nvme.py |
524 | +++ b/src/tests/unit/test_check_nvme.py |
525 | @@ -4,7 +4,10 @@ import sys |
526 | import unittest |
527 | import unittest.mock as mock |
528 | |
529 | -sys.path.append('files/nvme') |
530 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
531 | +from samples import get_sample # noqa: E402 |
532 | + |
533 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../files/nvme')) |
534 | import check_nvme # noqa: E402 |
535 | |
536 | |
537 | @@ -14,8 +17,7 @@ class TestCheckNvme(unittest.TestCase): |
538 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
539 | def test_parse_output(self, mock_print, mock_subprocess, mock_glob): |
540 | mock_glob.return_value = ['/dev/nvme0'] |
541 | - input_file = os.path.join(os.getcwd(), 'tests', 'hw-health-samples', |
542 | - 'nvme.output.1') |
543 | + input_file = get_sample('nvme.output.1') |
544 | with open(input_file, 'r') as fd: |
545 | mock_subprocess.return_value = fd.read().encode() |
546 | check_nvme.parse_output() |
547 | diff --git a/src/tests/unit/test_check_sas2ircu.py b/src/tests/unit/test_check_sas2ircu.py |
548 | index 1d0dc80..5464889 100644 |
549 | --- a/src/tests/unit/test_check_sas2ircu.py |
550 | +++ b/src/tests/unit/test_check_sas2ircu.py |
551 | @@ -4,16 +4,17 @@ import sys |
552 | import unittest |
553 | import unittest.mock as mock |
554 | |
555 | -sys.path.append('files/sas2ircu') |
556 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
557 | +from samples import get_sample # noqa: E402 |
558 | + |
559 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../files/sas2ircu')) |
560 | import check_sas2ircu # noqa: E402 |
561 | |
562 | |
563 | class TestCheckMegaCLI(unittest.TestCase): |
564 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
565 | def test_parse_output(self, mock_print): |
566 | - check_sas2ircu.INPUT_FILE = os.path.join(os.getcwd(), 'tests', |
567 | - 'hw-health-samples', |
568 | - 'sas2ircu.huawei.output.1') |
569 | + check_sas2ircu.INPUT_FILE = get_sample('sas2ircu.huawei.output.1') |
570 | check_sas2ircu.parse_output() |
571 | actual = mock_print.getvalue() |
572 | expected = 'OK: Ready[1:0,1:1,1:2,1:3,1:4,1:5,1:6,1:7]\n' |
573 | diff --git a/src/tests/unit/test_check_sas3ircu.py b/src/tests/unit/test_check_sas3ircu.py |
574 | index 5747de9..1379369 100644 |
575 | --- a/src/tests/unit/test_check_sas3ircu.py |
576 | +++ b/src/tests/unit/test_check_sas3ircu.py |
577 | @@ -4,15 +4,17 @@ import sys |
578 | import unittest |
579 | import unittest.mock as mock |
580 | |
581 | -sys.path.append('files/sas3ircu') |
582 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
583 | +from samples import get_sample # noqa: E402 |
584 | + |
585 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../files/sas3ircu')) |
586 | import check_sas3ircu # noqa: E402 |
587 | |
588 | |
589 | class TestCheckMegaCLI(unittest.TestCase): |
590 | @mock.patch('sys.stdout', new_callable=io.StringIO) |
591 | def test_parse_output_ok(self, mock_print): |
592 | - _filepath = os.path.join(os.getcwd(), 'tests', 'hw-health-samples', |
593 | - 'sas3ircu.supermicro.ok.output.1') |
594 | + _filepath = get_sample('sas3ircu.supermicro.ok.output.1') |
595 | data = check_sas3ircu.parse_output(_filepath) |
596 | check_sas3ircu.eval_status(data) |
597 | actual = mock_print.getvalue() |
598 | diff --git a/src/tests/unit/test_cron_mdadm.py b/src/tests/unit/test_cron_mdadm.py |
599 | index d124931..f52ea9c 100644 |
600 | --- a/src/tests/unit/test_cron_mdadm.py |
601 | +++ b/src/tests/unit/test_cron_mdadm.py |
602 | @@ -5,7 +5,10 @@ import sys # noqa: F401 |
603 | import unittest |
604 | import unittest.mock as mock |
605 | |
606 | -sys.path.append('files/mdadm') |
607 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
608 | +from samples import get_sample # noqa: E402 |
609 | + |
610 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../files/mdadm')) |
611 | import cron_mdadm # noqa: E402 |
612 | |
613 | |
614 | @@ -44,13 +47,11 @@ class TestCronMdadm(unittest.TestCase): |
615 | def test_parse_output_ok(self, mock_print, mdadm_details, devices, genout): |
616 | class Test_Popen(object): |
617 | def __init__(cls): |
618 | - test_output = os.path.join( |
619 | - os.getcwd(), 'tests', 'hw-health-samples', 'mdadm.output') |
620 | + test_output = get_sample('mdadm.output') |
621 | cls.stdout = io.FileIO(test_output) |
622 | cls.wait = lambda: 0 |
623 | |
624 | - test_output = os.path.join( |
625 | - os.getcwd(), 'tests', 'hw-health-samples', 'mdadm.output') |
626 | + test_output = get_sample('mdadm.output') |
627 | with open(test_output, 'r') as fd: |
628 | mdadm_details.return_value = ''.join(fd.readlines()).encode() |
629 | devices.return_value = set(['/dev/md0', '/dev/md1', '/dev/md2']) |
630 | @@ -87,9 +88,7 @@ class TestCronMdadm(unittest.TestCase): |
631 | @mock.patch('cron_mdadm.get_devices') |
632 | @mock.patch('subprocess.check_output') |
633 | def test_parse_output_degraded(self, mdadm_details, devices, genout): |
634 | - test_output = os.path.join( |
635 | - os.getcwd(), 'tests', 'hw-health-samples', |
636 | - 'mdadm.output.critical') |
637 | + test_output = get_sample('mdadm.output.critical.1') |
638 | with open(test_output, 'r') as fd: |
639 | mdadm_details.return_value = ''.join(fd.readlines()).encode() |
640 | |
641 | @@ -100,3 +99,31 @@ class TestCronMdadm(unittest.TestCase): |
642 | ' /dev/md2 ok') |
643 | self.assertTrue(cron_mdadm.parse_output()) |
644 | genout.assert_called_once_with(expected) |
645 | + |
646 | + @mock.patch('cron_mdadm.generate_output') |
647 | + @mock.patch('cron_mdadm.get_devices') |
648 | + @mock.patch('subprocess.check_output') |
649 | + def test_parse_output_removed(self, mdadm_details, devices, genout): |
650 | + test_output = get_sample('mdadm.output.critical.2') |
651 | + with open(test_output, 'r') as fd: |
652 | + mdadm_details.return_value = ''.join(fd.readlines()).encode() |
653 | + |
654 | + devices.return_value = set(['/dev/md1']) |
655 | + genout.return_value = True |
656 | + expected = ('CRITICAL: /dev/md1 degraded, RaidDevice(s) 2 marked removed') |
657 | + self.assertTrue(cron_mdadm.parse_output()) |
658 | + genout.assert_called_once_with(expected) |
659 | + |
660 | + @mock.patch('cron_mdadm.generate_output') |
661 | + @mock.patch('cron_mdadm.get_devices') |
662 | + @mock.patch('subprocess.check_output') |
663 | + def test_parse_output_rebuilding(self, mdadm_details, devices, genout): |
664 | + test_output = get_sample('mdadm.output.warning') |
665 | + with open(test_output, 'r') as fd: |
666 | + mdadm_details.return_value = ''.join(fd.readlines()).encode() |
667 | + |
668 | + devices.return_value = set(['/dev/md0', '/dev/md1', '/dev/md2']) |
669 | + genout.return_value = True |
670 | + expected = ('WARNING: /dev/md1 recovering, /dev/sdk2 rebuilding (13% complete)') |
671 | + self.assertTrue(cron_mdadm.parse_output()) |
672 | + genout.assert_called_once_with(expected) |
673 | diff --git a/src/tests/unit/test_hwdiscovery.py b/src/tests/unit/test_hwdiscovery.py |
674 | index 6e5bf3d..43ea360 100644 |
675 | --- a/src/tests/unit/test_hwdiscovery.py |
676 | +++ b/src/tests/unit/test_hwdiscovery.py |
677 | @@ -1,11 +1,13 @@ |
678 | -import glob |
679 | import os # noqa: F401 |
680 | import subprocess # noqa: F401 |
681 | import sys |
682 | import unittest |
683 | import unittest.mock as mock |
684 | |
685 | -sys.path.append('lib/hwhealth') |
686 | +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) |
687 | +from samples import get_sample # noqa: E402 |
688 | + |
689 | +sys.path.append(os.path.join(os.path.dirname(__file__), '../../lib/hwhealth')) |
690 | import hwdiscovery # noqa: E402 |
691 | from discovery.lshw import Hardware # noqa: E402 |
692 | |
693 | @@ -83,8 +85,7 @@ class TestGetTools(unittest.TestCase): |
694 | 'lshw.supermicro.sas.02.json': set(['Nvme', 'Sas3Ircu']), |
695 | } |
696 | |
697 | - for filename in glob.glob(os.path.join( |
698 | - os.getcwd(), 'tests/hw-health-samples/lshw.*.json')): |
699 | + for filename in get_sample('lshw.*.json'): |
700 | mock_hwinfo.return_value = Hardware(filename) |
701 | actual = hwdiscovery._get_tools() |
702 | if os.path.basename(filename) in TOOLS: |
This supersedes 385838. I had to recreate this from scratch to clean up the launchpad diff.