Merge ~ltrager/maas:lp1733923_2.3 into maas:2.3

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: 0e2b5655f741736b26850a336a6f9d331fc48ac9
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:lp1733923_2.3
Merge into: maas:2.3
Diff against target: 201 lines (+62/-50)
2 files modified
src/metadataserver/builtin_scripts/badblocks.py (+49/-18)
src/metadataserver/builtin_scripts/tests/test_badblocks.py (+13/-32)
Reviewer Review Type Date Requested Status
Lee Trager (community) Approve
MAAS Lander unittests Pending
Andres Rodriguez Pending
Review via email: mp+334324@code.launchpad.net

Commit message

Backport a03af41 from master - LP: #1733923 - Fail badblocks if any error is detected

To post a comment you must log in.
Revision history for this message
Lee Trager (ltrager) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/metadataserver/builtin_scripts/badblocks.py b/src/metadataserver/builtin_scripts/badblocks.py
2index 6dfeca9..292b7fd 100644
3--- a/src/metadataserver/builtin_scripts/badblocks.py
4+++ b/src/metadataserver/builtin_scripts/badblocks.py
5@@ -31,6 +31,18 @@
6 # badblocks:
7 # title: Bad blocks
8 # description: The number of bad blocks found on the storage device.
9+# read_errors:
10+# title: Bad blocks read errors
11+# description: >
12+# The number of bad blocks read errors found on the storage device.
13+# write_errors:
14+# title: Bad blocks write errors
15+# description: >
16+# The number of bad blocks write errors found on the storage device.
17+# comparison_errors:
18+# title: Bad blocks comparison errors
19+# description: >
20+# The number of bad blocks comparison errors found on the storage device.
21 # parameters:
22 # storage: {type: storage}
23 # destructive: {{if 'destructive' in name}}True{{else}}False{{endif}}
24@@ -113,37 +125,56 @@ def run_badblocks(storage, destructive=False):
25 if destructive:
26 cmd = [
27 'sudo', '-n', 'badblocks', '-b', str(blocksize),
28- '-c', str(parallel_blocks), '-v', '-f', '-w', storage
29+ '-c', str(parallel_blocks), '-v', '-f', '-s', '-w', storage
30 ]
31 else:
32 cmd = [
33 'sudo', '-n', 'badblocks', '-b', str(blocksize),
34- '-c', str(parallel_blocks), '-v', '-f', '-n', storage
35+ '-c', str(parallel_blocks), '-v', '-f', '-s', '-n', storage
36 ]
37
38 print('INFO: Running command: %s\n' % ' '.join(cmd))
39 proc = Popen(cmd, stdout=PIPE, stderr=STDOUT)
40 stdout, _ = proc.communicate()
41+ stdout = stdout.decode()
42
43 # Print stdout to the console.
44- if stdout is not None:
45- print(stdout.decode())
46-
47- result_path = os.environ.get("RESULT_PATH")
48+ print(stdout)
49+
50+ m = re.search(
51+ '^Pass completed, (?P<badblocks>\d+) bad blocks found. '
52+ '\((?P<read>\d+)\/(?P<write>\d+)\/(?P<comparison>\d+) errors\)$',
53+ stdout, re.M)
54+ badblocks = int(m.group('badblocks'))
55+ read_errors = int(m.group('read'))
56+ write_errors = int(m.group('write'))
57+ comparison_errors = int(m.group('comparison'))
58+ result_path = os.environ.get('RESULT_PATH')
59 if result_path is not None:
60- # Parse the results for the desired information and
61- # then wrtie this to the results file.
62- match = re.search(b', ([0-9]+) bad blocks found', stdout)
63- if match is not None:
64- results = {
65- 'results': {
66- 'badblocks': int(match.group(1).decode()),
67- }
68+ results = {
69+ 'results': {
70+ 'badblocks': badblocks,
71+ 'read_errors': read_errors,
72+ 'write_errors': write_errors,
73+ 'comparison_errors': comparison_errors,
74 }
75- with open(result_path, 'w') as results_file:
76- yaml.safe_dump(results, results_file)
77-
78- return proc.returncode
79+ }
80+ with open(result_path, 'w') as results_file:
81+ yaml.safe_dump(results, results_file)
82+
83+ # LP: #1733923 - Badblocks normally returns 0 no matter the result. If any
84+ # errors are found fail the test.
85+ if (proc.returncode + badblocks + read_errors + write_errors +
86+ comparison_errors) != 0:
87+ print('FAILURE: Test FAILED!')
88+ print('INFO: %s badblocks found' % badblocks)
89+ print('INFO: %s read errors found' % read_errors)
90+ print('INFO: %s write errors found' % write_errors)
91+ print('INFO: %s comparison errors found' % comparison_errors)
92+ return 1
93+ else:
94+ print('SUCCESS: Test PASSED!')
95+ return 0
96
97
98 if __name__ == '__main__':
99diff --git a/src/metadataserver/builtin_scripts/tests/test_badblocks.py b/src/metadataserver/builtin_scripts/tests/test_badblocks.py
100index a04c33c..66f6b25 100644
101--- a/src/metadataserver/builtin_scripts/tests/test_badblocks.py
102+++ b/src/metadataserver/builtin_scripts/tests/test_badblocks.py
103@@ -9,7 +9,6 @@ __all__ = []
104 import io
105 import os
106 import random
107-import re
108 from subprocess import (
109 PIPE,
110 STDOUT,
111@@ -18,22 +17,22 @@ from textwrap import dedent
112 from unittest.mock import ANY
113
114 from maastesting.factory import factory
115-from maastesting.matchers import (
116- MockCalledOnce,
117- MockCalledOnceWith,
118-)
119+from maastesting.matchers import MockCalledOnceWith
120 from maastesting.testcase import MAASTestCase
121 from metadataserver.builtin_scripts import badblocks
122 import yaml
123
124
125 BADBLOCKS = random.randint(0, 1000)
126+READ_ERRORS = random.randint(0, 1000)
127+WRITE_ERRORS = random.randint(0, 1000)
128+COMPARISON_ERRORS = random.randint(0, 1000)
129 BADBLOCKS_OUTPUT = dedent("""
130 Checking for bad blocks in non-destructive read-write mode
131 From block 0 to 5242879
132 Testing with random pattern:
133- Pass completed, %s bad blocks found. (0/0/%s errors)
134- """ % (BADBLOCKS, BADBLOCKS))
135+ Pass completed, %s bad blocks found. (%s/%s/%s errors)
136+ """ % (BADBLOCKS, READ_ERRORS, WRITE_ERRORS, COMPARISON_ERRORS))
137
138
139 class TestRunBadBlocks(MAASTestCase):
140@@ -75,7 +74,7 @@ class TestRunBadBlocks(MAASTestCase):
141 })
142 cmd = [
143 'sudo', '-n', 'badblocks', '-b', str(blocksize),
144- '-c', str(parallel_blocks), '-v', '-f', '-n', storage
145+ '-c', str(parallel_blocks), '-v', '-f', '-s', '-n', storage
146 ]
147 mock_popen = self.patch(badblocks, "Popen")
148 proc = mock_popen.return_value
149@@ -88,10 +87,13 @@ class TestRunBadBlocks(MAASTestCase):
150 results = {
151 'results': {
152 'badblocks': BADBLOCKS,
153+ 'read_errors': READ_ERRORS,
154+ 'write_errors': WRITE_ERRORS,
155+ 'comparison_errors': COMPARISON_ERRORS,
156 }
157 }
158
159- self.assertEquals(0, badblocks.run_badblocks(storage))
160+ self.assertEquals(1, badblocks.run_badblocks(storage))
161 self.assertThat(mock_popen, MockCalledOnceWith(
162 cmd, stdout=PIPE, stderr=STDOUT))
163 self.assertThat(mock_open, MockCalledOnceWith(ANY, "w"))
164@@ -107,7 +109,7 @@ class TestRunBadBlocks(MAASTestCase):
165 parallel_blocks)
166 cmd = [
167 'sudo', '-n', 'badblocks', '-b', str(blocksize),
168- '-c', str(parallel_blocks), '-v', '-f', '-w', storage,
169+ '-c', str(parallel_blocks), '-v', '-f', '-s', '-w', storage,
170 ]
171 mock_popen = self.patch(badblocks, "Popen")
172 proc = mock_popen.return_value
173@@ -116,27 +118,6 @@ class TestRunBadBlocks(MAASTestCase):
174 proc.returncode = 0
175
176 self.assertEquals(
177- 0, badblocks.run_badblocks(storage, destructive=True))
178+ 1, badblocks.run_badblocks(storage, destructive=True))
179 self.assertThat(mock_popen, MockCalledOnceWith(
180 cmd, stdout=PIPE, stderr=STDOUT))
181-
182- def test_run_badblocks_exits_if_no_regex_match_found(self):
183- storage = factory.make_name('storage')
184- blocksize = random.randint(512, 4096)
185- self.patch(badblocks, 'get_block_size').return_value = blocksize
186- parallel_blocks = random.randint(1, 50000)
187- self.patch(badblocks, 'get_parallel_blocks').return_value = (
188- parallel_blocks)
189- self.patch(os, "environ", {
190- "RESULT_PATH": factory.make_name()
191- })
192- mock_popen = self.patch(badblocks, "Popen")
193- proc = mock_popen.return_value
194- proc.communicate.return_value = (
195- BADBLOCKS_OUTPUT.encode('utf-8'), None)
196- proc.returncode = 0
197- mock_re_search = self.patch(re, "search")
198- mock_re_search.return_value = None
199-
200- self.assertEquals(0, badblocks.run_badblocks(storage))
201- self.assertThat(mock_re_search, MockCalledOnce())

Subscribers

People subscribed via source and target branches