Merge lp:~wesley-wiedenmeier/curtin/1618429 into lp:~curtin-dev/curtin/trunk

Proposed by Wesley Wiedenmeier
Status: Merged
Merged at revision: 424
Proposed branch: lp:~wesley-wiedenmeier/curtin/1618429
Merge into: lp:~curtin-dev/curtin/trunk
Diff against target: 177 lines (+64/-30)
4 files modified
curtin/block/clear_holders.py (+10/-2)
curtin/block/mdadm.py (+18/-5)
tests/unittests/test_block_mdadm.py (+28/-23)
tests/unittests/test_clear_holders.py (+8/-0)
To merge this branch: bzr merge lp:~wesley-wiedenmeier/curtin/1618429
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Ryan Harper (community) Approve
Review via email: mp+304424@code.launchpad.net

Description of the change

Before clear_holders runs, it starts a mdadm --assemble in order to detect mdadm devices on the system and remove them cleanly. However, if part of a mdadm device is present, but not enough to assemble it, then this may fail. Therefore, ignore any errors encountered running mdadm --assemble for device wipe purposes.

To post a comment you must log in.
Revision history for this message
Wesley Wiedenmeier (wesley-wiedenmeier) wrote :
Revision history for this message
Wesley Wiedenmeier (wesley-wiedenmeier) wrote :
Revision history for this message
Ryan Harper (raharper) wrote :

Thanks!

review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'curtin/block/clear_holders.py'
2--- curtin/block/clear_holders.py 2016-08-11 20:41:40 +0000
3+++ curtin/block/clear_holders.py 2016-09-14 19:52:48 +0000
4@@ -360,8 +360,16 @@
5 prepare system for clear holders to be able to scan old devices
6 """
7 # a mdadm scan has to be started in case there is a md device that needs to
8- # be detected
9- block.mdadm.mdadm_assemble(scan=True)
10+ # be detected. if the scan fails, it is either because there are no mdadm
11+ # devices on the system, or because there is a mdadm device in a damaged
12+ # state that could not be started. due to the nature of mdadm tools, it is
13+ # difficult to know which is the case. if any errors did occur, then ignore
14+ # them, since no action needs to be taken if there were no mdadm devices on
15+ # the system, and in the case where there is some mdadm metadata on a disk,
16+ # but there was not enough to start the array, the call to wipe_volume on
17+ # all disks and partitions should be sufficient to remove the mdadm
18+ # metadata
19+ block.mdadm.mdadm_assemble(scan=True, ignore_errors=True)
20 # the bcache module needs to be present to properly detect bcache devs
21 # on some systems (precise without hwe kernel) it may not be possible to
22 # lad the bcache module bcause it is not present in the kernel. if this
23
24=== modified file 'curtin/block/mdadm.py'
25--- curtin/block/mdadm.py 2016-04-14 01:45:54 +0000
26+++ curtin/block/mdadm.py 2016-09-14 19:52:48 +0000
27@@ -28,7 +28,7 @@
28 from subprocess import CalledProcessError
29
30 from curtin.block import (dev_short, dev_path, is_valid_device, sys_block_path)
31-from curtin import util
32+from curtin import (util, udev)
33 from curtin.log import LOG
34
35 NOSPARE_RAID_LEVELS = [
36@@ -117,21 +117,34 @@
37 #
38
39
40-def mdadm_assemble(md_devname=None, devices=[], spares=[], scan=False):
41+def mdadm_assemble(md_devname=None, devices=[], spares=[], scan=False,
42+ ignore_errors=False):
43 # md_devname is a /dev/XXXX
44 # devices is non-empty list of /dev/xxx
45 # if spares is non-empt list append of /dev/xxx
46 cmd = ["mdadm", "--assemble"]
47 if scan:
48- cmd += ['--scan']
49+ cmd += ['--scan', '-v']
50 else:
51 valid_mdname(md_devname)
52 cmd += [md_devname, "--run"] + devices
53 if spares:
54 cmd += spares
55
56- util.subp(cmd, capture=True, rcs=[0, 1, 2])
57- util.subp(["udevadm", "settle"])
58+ try:
59+ # mdadm assemble returns 1 when no arrays are found. this might not be
60+ # an error depending on the situation this function was called in, so
61+ # accept a return code of 1
62+ # mdadm assemble returns 2 when called on an array that is already
63+ # assembled. this is not an error, so accept return code of 2
64+ # all other return codes can be accepted with ignore_error set to true
65+ util.subp(cmd, capture=True, rcs=[0, 1, 2])
66+ except util.ProcessExecutionError:
67+ LOG.warning("mdadm_assemble had unexpected return code")
68+ if not ignore_errors:
69+ raise
70+
71+ udev.udevadm_settle()
72
73
74 def mdadm_create(md_devname, raidlevel, devices, spares=None, md_name=""):
75
76=== modified file 'tests/unittests/test_block_mdadm.py'
77--- tests/unittests/test_block_mdadm.py 2016-04-14 01:45:54 +0000
78+++ tests/unittests/test_block_mdadm.py 2016-09-14 19:52:48 +0000
79@@ -2,6 +2,7 @@
80 from mock import call, patch
81 from curtin.block import dev_short
82 from curtin.block import mdadm
83+from curtin import util
84 import os
85 import subprocess
86
87@@ -24,34 +25,27 @@
88 super(TestBlockMdadmAssemble, self).setUp()
89 self.add_patch('curtin.block.mdadm.util', 'mock_util')
90 self.add_patch('curtin.block.mdadm.is_valid_device', 'mock_valid')
91+ self.add_patch('curtin.block.mdadm.udev', 'mock_udev')
92
93 # Common mock settings
94 self.mock_valid.return_value = True
95 self.mock_util.lsb_release.return_value = {'codename': 'precise'}
96- self.mock_util.subp.side_effect = [
97- ("", ""), # mdadm assemble
98- ("", ""), # udevadm settle
99- ]
100+ self.mock_util.subp.return_value = ('', '')
101
102 def test_mdadm_assemble_scan(self):
103 mdadm.mdadm_assemble(scan=True)
104- expected_calls = [
105- call(["mdadm", "--assemble", "--scan"], capture=True,
106- rcs=[0, 1, 2]),
107- call(["udevadm", "settle"]),
108- ]
109- self.mock_util.subp.assert_has_calls(expected_calls)
110+ self.mock_util.subp.assert_called_with(
111+ ["mdadm", "--assemble", "--scan", "-v"], capture=True,
112+ rcs=[0, 1, 2])
113+ self.assertTrue(self.mock_udev.udevadm_settle.called)
114
115 def test_mdadm_assemble_md_devname(self):
116 md_devname = "/dev/md0"
117 mdadm.mdadm_assemble(md_devname=md_devname)
118-
119- expected_calls = [
120- call(["mdadm", "--assemble", md_devname, "--run"], capture=True,
121- rcs=[0, 1, 2]),
122- call(["udevadm", "settle"]),
123- ]
124- self.mock_util.subp.assert_has_calls(expected_calls)
125+ self.mock_util.subp.assert_called_with(
126+ ["mdadm", "--assemble", md_devname, "--run"], capture=True,
127+ rcs=[0, 1, 2])
128+ self.assertTrue(self.mock_udev.udevadm_settle.called)
129
130 def test_mdadm_assemble_md_devname_short(self):
131 with self.assertRaises(ValueError):
132@@ -67,12 +61,23 @@
133 md_devname = "/dev/md0"
134 devices = ["/dev/vdc1", "/dev/vdd1"]
135 mdadm.mdadm_assemble(md_devname=md_devname, devices=devices)
136- expected_calls = [
137- call(["mdadm", "--assemble", md_devname, "--run"] + devices,
138- capture=True, rcs=[0, 1, 2]),
139- call(["udevadm", "settle"]),
140- ]
141- self.mock_util.subp.assert_has_calls(expected_calls)
142+ self.mock_util.subp.assert_called_with(
143+ ["mdadm", "--assemble", md_devname, "--run"] + devices,
144+ capture=True, rcs=[0, 1, 2])
145+ self.assertTrue(self.mock_udev.udevadm_settle.called)
146+
147+ def test_mdadm_assemble_exec_error(self):
148+
149+ def _raise_pexec_error(*args, **kwargs):
150+ raise util.ProcessExecutionError()
151+
152+ self.mock_util.ProcessExecutionError = util.ProcessExecutionError
153+ self.mock_util.subp.side_effect = _raise_pexec_error
154+ with self.assertRaises(util.ProcessExecutionError):
155+ mdadm.mdadm_assemble(scan=True, ignore_errors=False)
156+ self.mock_util.subp.assert_called_with(
157+ ['mdadm', '--assemble', '--scan', '-v'], capture=True,
158+ rcs=[0, 1, 2])
159
160
161 class TestBlockMdadmCreate(MdadmTestBase):
162
163=== modified file 'tests/unittests/test_clear_holders.py'
164--- tests/unittests/test_clear_holders.py 2016-08-11 20:30:27 +0000
165+++ tests/unittests/test_clear_holders.py 2016-09-14 19:52:48 +0000
166@@ -319,3 +319,11 @@
167 mock_gen_holders_tree.assert_called_with(device)
168 mock_gen_holders_tree.return_value = self.example_holders_trees[1][1]
169 clear_holders.assert_clear(device)
170+
171+ @mock.patch('curtin.block.clear_holders.block.mdadm')
172+ @mock.patch('curtin.block.clear_holders.util')
173+ def test_start_clear_holders_deps(self, mock_util, mock_mdadm):
174+ clear_holders.start_clear_holders_deps()
175+ mock_mdadm.mdadm_assemble.assert_called_with(
176+ scan=True, ignore_errors=True)
177+ mock_util.subp.assert_called_with(['modprobe', 'bcache'], rcs=[0, 1])

Subscribers

People subscribed via source and target branches