Merge lp:~raharper/curtin/trunk.md-uefi into lp:~curtin-dev/curtin/trunk
- trunk.md-uefi
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 495 |
Proposed branch: | lp:~raharper/curtin/trunk.md-uefi |
Merge into: | lp:~curtin-dev/curtin/trunk |
Diff against target: |
490 lines (+379/-6) 6 files modified
curtin/block/clear_holders.py (+23/-1) curtin/block/mdadm.py (+27/-1) examples/tests/mirrorboot-uefi.yaml (+138/-0) tests/unittests/test_block_mdadm.py (+94/-1) tests/unittests/test_clear_holders.py (+57/-3) tests/vmtests/test_mdadm_bcache.py (+40/-0) |
To merge this branch: | bzr merge lp:~raharper/curtin/trunk.md-uefi |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Scott Moser (community) | Approve | ||
Chad Smith | Approve | ||
Joshua Powers (community) | Approve | ||
Review via email: mp+322553@code.launchpad.net |
Commit message
Description of the change
clear-holders: mdadm use /proc/mdstat to wait until an array has been stopped
shutdown_mdadm needs to wait until the md device has stopped. Using files in sysfs is unreliable due to a kernel bug (LP:1682456) so
instead use device presence in /proc/mdstat.
Add the use of --manage flag to force mdadm to interrupt actions on the device (like a resync).
Add vmtest with storage config to recreate issue found (LP:1682584) using
early_command to dirty existing disks with raid configurations.
Server Team CI bot (server-team-bot) wrote : | # |
- 449. By Ryan Harper
-
merge from trunk
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:449
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
- 450. By Ryan Harper
-
Don't force launch into smp mode
- 451. By Ryan Harper
-
merge from trunk
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:451
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
- 452. By Ryan Harper
-
Fix and add unittests for mdadm.md_present
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:452
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Scott Moser (smoser) wrote : | # |
some small things.
Chad Smith (chad.smith) wrote : | # |
While I don't have a lot of context on raid setup, just an initial review on the code and tests as written.
Ryan Harper (raharper) wrote : | # |
Thanks for the reviews; will update.
- 453. By Ryan Harper
-
tl;dr wait-for-mdadm comment
- 454. By Ryan Harper
-
Use variable to define how often to retry waiting on mdadm release
- 455. By Ryan Harper
-
On shutdown failure, log critical, handle missing /proc/mdstat, add unittests
- 456. By Ryan Harper
-
Use IOError, it's supported in both py2 and py3
Ryan Harper (raharper) wrote : | # |
I've addressed the comments as I replied earlier. Please re-review.
The updated branch is running through vmtest again.
https:/
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:456
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Joshua Powers (powersj) wrote : | # |
LGTM, given my limited exposure to mdadm
Chad Smith (chad.smith) wrote : | # |
+1 with a minor nit below
- 457. By Ryan Harper
-
remove unnused variable and enumerate of MDADM_RELEASE_
RETRIES
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:457
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Scott Moser (smoser) : | # |
Scott Moser (smoser) wrote : | # |
they're small, but i think worth fixing.
Ryan Harper (raharper) wrote : | # |
On Wed, Apr 26, 2017 at 10:03 AM, Scott Moser <email address hidden> wrote:
> Review: Needs Fixing
>
> they're small, but i think worth fixing.
>
>
> Diff comments:
>
> > === modified file 'curtin/
> > --- curtin/
> > +++ curtin/
> > @@ -187,7 +191,26 @@
> > blockdev = block.sysfs_
> > LOG.debug('using mdadm.mdadm_stop on dev: %s', blockdev)
> > mdadm.mdadm_
> > - mdadm.mdadm_
> > +
> > + # mdadm stop operation is asynchronous so we must wait for the
> kernel to
> > + # release resources. For more details see lp:1682456
> > + try:
> > + for wait in MDADM_RELEASE_
> > + if mdadm.md_
> > + time.sleep(wait)
> > + else:
> > + LOG.debug('%s has been removed', blockdev)
> > + break
> > +
> > + if mdadm.md_
> > + raise OSError('Timeout exceeded for removal of %s',
> blockdev)
> > +
> > + except OSError:
> > + LOG.critical(
> > + if os.path.
> > + out, _ = util.subp(['cat', '/proc/mdstat'], capture=True)
>
> use util.load_file here. cat and capture for reading a file?
>
It's really just debugging so it doesn't matter the method.
I'm find for using load_file.
>
> > + LOG.critical(out)
> > + raise
> >
> >
> > def wipe_superblock
> >
> > === modified file 'curtin/
> > --- curtin/
> > +++ curtin/
> > @@ -293,6 +294,26 @@
> > return out
> >
> >
> > +def md_present(mdname):
> > + """Check if mdname is present in /proc/mdstat"""
> > + if not mdname:
> > + raise ValueError(
> > +
> > + try:
> > + mdstat = util.load_
> > + except IOError:
> > + LOG.warning('Failed to read /proc/mdstat; '
>
> we really should check if this is a ENOENT. that is very specifically
> different than any other type of IOError
> If we got a IOError reading that file, we should just raise the exception
> and fail rather than printing this message.
>
> if util.is_
> LOG.warning("....")
> else:
> raise e
>
You mentioned that before and somehow I failed to find it and thought you
were suggesting to
write one.
>
> > + 'md modules might not be loaded')
> > + return False
> > +
> > + md_kname = dev_short(mdname)
> > + present = [line for line in mdstat.splitlines()
> > + if line.startswith
> > + if len(present) > 0:
> > + return True
> > + return False
> > +
> > +
> > # -------
> > def valid_mdname(
> > assert_
>
>
> --
> https:/
> You are the owner of lp:~raharper/c...
- 458. By Ryan Harper
-
Use load_file, check exception for file-not-found
- 459. By Ryan Harper
-
Merge from trunk
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:459
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
- 460. By Ryan Harper
-
merge from trunk
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:460
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Scott Moser (smoser) wrote : | # |
There are some nits here.
only one really needs to be fixed ("md10"
fix my nits (you dont have to fix the util.loadfile if you dont want)
and then i approve.
- 461. By Ryan Harper
-
Match entire mdname not just the start
- 462. By Ryan Harper
-
fix style lint
- 463. By Ryan Harper
-
drop useless out return value
- 464. By Ryan Harper
-
Change format for LP bug reference
- 465. By Ryan Harper
-
remove debugging late_commands from mirrorboot-uefi vmtest
Ryan Harper (raharper) wrote : | # |
Applied fixes for all; thanks for the .startswith catch.
I've pushed the fixes to this MR and started a vmtest run for just the mdadm tests here:
https:/
If that comes out green, I'll land this to trunk tomorrow AM.
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:465
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'curtin/block/clear_holders.py' | |||
2 | --- curtin/block/clear_holders.py 2017-04-11 20:52:11 +0000 | |||
3 | +++ curtin/block/clear_holders.py 2017-05-03 02:14:17 +0000 | |||
4 | @@ -23,12 +23,16 @@ | |||
5 | 23 | 23 | ||
6 | 24 | import errno | 24 | import errno |
7 | 25 | import os | 25 | import os |
8 | 26 | import time | ||
9 | 26 | 27 | ||
10 | 27 | from curtin import (block, udev, util) | 28 | from curtin import (block, udev, util) |
11 | 28 | from curtin.block import lvm | 29 | from curtin.block import lvm |
12 | 29 | from curtin.block import mdadm | 30 | from curtin.block import mdadm |
13 | 30 | from curtin.log import LOG | 31 | from curtin.log import LOG |
14 | 31 | 32 | ||
15 | 33 | # poll frequenty, but wait up to 60 seconds total | ||
16 | 34 | MDADM_RELEASE_RETRIES = [0.4] * 150 | ||
17 | 35 | |||
18 | 32 | 36 | ||
19 | 33 | def _define_handlers_registry(): | 37 | def _define_handlers_registry(): |
20 | 34 | """ | 38 | """ |
21 | @@ -187,7 +191,25 @@ | |||
22 | 187 | blockdev = block.sysfs_to_devpath(device) | 191 | blockdev = block.sysfs_to_devpath(device) |
23 | 188 | LOG.debug('using mdadm.mdadm_stop on dev: %s', blockdev) | 192 | LOG.debug('using mdadm.mdadm_stop on dev: %s', blockdev) |
24 | 189 | mdadm.mdadm_stop(blockdev) | 193 | mdadm.mdadm_stop(blockdev) |
26 | 190 | mdadm.mdadm_remove(blockdev) | 194 | |
27 | 195 | # mdadm stop operation is asynchronous so we must wait for the kernel to | ||
28 | 196 | # release resources. For more details see LP: #1682456 | ||
29 | 197 | try: | ||
30 | 198 | for wait in MDADM_RELEASE_RETRIES: | ||
31 | 199 | if mdadm.md_present(block.path_to_kname(blockdev)): | ||
32 | 200 | time.sleep(wait) | ||
33 | 201 | else: | ||
34 | 202 | LOG.debug('%s has been removed', blockdev) | ||
35 | 203 | break | ||
36 | 204 | |||
37 | 205 | if mdadm.md_present(block.path_to_kname(blockdev)): | ||
38 | 206 | raise OSError('Timeout exceeded for removal of %s', blockdev) | ||
39 | 207 | |||
40 | 208 | except OSError: | ||
41 | 209 | LOG.critical('Failed to stop mdadm device %s', device) | ||
42 | 210 | if os.path.exists('/proc/mdstat'): | ||
43 | 211 | LOG.critical("/proc/mdstat:\n%s", util.load_file('/proc/mdstat')) | ||
44 | 212 | raise | ||
45 | 191 | 213 | ||
46 | 192 | 214 | ||
47 | 193 | def wipe_superblock(device): | 215 | def wipe_superblock(device): |
48 | 194 | 216 | ||
49 | === modified file 'curtin/block/mdadm.py' | |||
50 | --- curtin/block/mdadm.py 2017-01-31 19:15:24 +0000 | |||
51 | +++ curtin/block/mdadm.py 2017-05-03 02:14:17 +0000 | |||
52 | @@ -257,7 +257,8 @@ | |||
53 | 257 | assert_valid_devpath(devpath) | 257 | assert_valid_devpath(devpath) |
54 | 258 | 258 | ||
55 | 259 | LOG.info("mdadm stopping: %s" % devpath) | 259 | LOG.info("mdadm stopping: %s" % devpath) |
57 | 260 | out, err = util.subp(["mdadm", "--stop", devpath], capture=True) | 260 | out, err = util.subp(["mdadm", "--manage", "--stop", devpath], |
58 | 261 | capture=True) | ||
59 | 261 | LOG.debug("mdadm stop:\n%s\n%s", out, err) | 262 | LOG.debug("mdadm stop:\n%s\n%s", out, err) |
60 | 262 | 263 | ||
61 | 263 | 264 | ||
62 | @@ -293,6 +294,31 @@ | |||
63 | 293 | return out | 294 | return out |
64 | 294 | 295 | ||
65 | 295 | 296 | ||
66 | 297 | def md_present(mdname): | ||
67 | 298 | """Check if mdname is present in /proc/mdstat""" | ||
68 | 299 | if not mdname: | ||
69 | 300 | raise ValueError('md_present requires a valid md name') | ||
70 | 301 | |||
71 | 302 | try: | ||
72 | 303 | mdstat = util.load_file('/proc/mdstat') | ||
73 | 304 | except IOError as e: | ||
74 | 305 | if util.is_file_not_found_exc(e): | ||
75 | 306 | LOG.warning('Failed to read /proc/mdstat; ' | ||
76 | 307 | 'md modules might not be loaded') | ||
77 | 308 | return False | ||
78 | 309 | else: | ||
79 | 310 | raise e | ||
80 | 311 | |||
81 | 312 | md_kname = dev_short(mdname) | ||
82 | 313 | # Find lines like: | ||
83 | 314 | # md10 : active raid1 vdc1[1] vda2[0] | ||
84 | 315 | present = [line for line in mdstat.splitlines() | ||
85 | 316 | if line.split(":")[0].rstrip() == md_kname] | ||
86 | 317 | if len(present) > 0: | ||
87 | 318 | return True | ||
88 | 319 | return False | ||
89 | 320 | |||
90 | 321 | |||
91 | 296 | # ------------------------------ # | 322 | # ------------------------------ # |
92 | 297 | def valid_mdname(md_devname): | 323 | def valid_mdname(md_devname): |
93 | 298 | assert_valid_devpath(md_devname) | 324 | assert_valid_devpath(md_devname) |
94 | 299 | 325 | ||
95 | === added file 'examples/tests/mirrorboot-uefi.yaml' | |||
96 | --- examples/tests/mirrorboot-uefi.yaml 1970-01-01 00:00:00 +0000 | |||
97 | +++ examples/tests/mirrorboot-uefi.yaml 2017-05-03 02:14:17 +0000 | |||
98 | @@ -0,0 +1,138 @@ | |||
99 | 1 | showtrace: true | ||
100 | 2 | |||
101 | 3 | early_commands: | ||
102 | 4 | # running block-meta custom from the install environment | ||
103 | 5 | # inherits the CONFIG environment, so this works to actually prepare | ||
104 | 6 | # the disks exactly as in this config before the rest of the install | ||
105 | 7 | # will just blow it all away. We have to clean out the other | ||
106 | 8 | # environment that could unintentionally mess things up. | ||
107 | 9 | blockmeta: [env, -u, OUTPUT_FSTAB, | ||
108 | 10 | TARGET_MOUNT_POINT=/tmp/my.bdir/target, | ||
109 | 11 | WORKING_DIR=/tmp/my.bdir/work.d, | ||
110 | 12 | curtin, --showtrace, -v, block-meta, --umount, custom] | ||
111 | 13 | |||
112 | 14 | storage: | ||
113 | 15 | config: | ||
114 | 16 | - grub_device: true | ||
115 | 17 | id: sda | ||
116 | 18 | name: sda | ||
117 | 19 | ptable: msdos | ||
118 | 20 | type: disk | ||
119 | 21 | wipe: superblock | ||
120 | 22 | path: /dev/vdb | ||
121 | 23 | name: main_disk | ||
122 | 24 | - id: sdb | ||
123 | 25 | name: sdb | ||
124 | 26 | ptable: gpt | ||
125 | 27 | type: disk | ||
126 | 28 | wipe: superblock | ||
127 | 29 | path: /dev/vdc | ||
128 | 30 | name: second_disk | ||
129 | 31 | - device: sda | ||
130 | 32 | flag: boot | ||
131 | 33 | id: sda-part1 | ||
132 | 34 | name: sda-part1 | ||
133 | 35 | number: 1 | ||
134 | 36 | offset: 4194304B | ||
135 | 37 | size: 511705088B | ||
136 | 38 | type: partition | ||
137 | 39 | uuid: fc7ab24c-b6bf-460f-8446-d3ac362c0625 | ||
138 | 40 | wipe: superblock | ||
139 | 41 | - device: sda | ||
140 | 42 | id: sda-part2 | ||
141 | 43 | name: sda-part2 | ||
142 | 44 | number: 2 | ||
143 | 45 | size: 2G | ||
144 | 46 | type: partition | ||
145 | 47 | uuid: 47c97eae-f35d-473f-8f3d-d64161d571f1 | ||
146 | 48 | wipe: superblock | ||
147 | 49 | - device: sda | ||
148 | 50 | id: sda-part3 | ||
149 | 51 | name: sda-part3 | ||
150 | 52 | number: 3 | ||
151 | 53 | size: 2G | ||
152 | 54 | type: partition | ||
153 | 55 | uuid: e3202633-841c-4936-a520-b18d1f7938ea | ||
154 | 56 | wipe: superblock | ||
155 | 57 | - device: sdb | ||
156 | 58 | flag: boot | ||
157 | 59 | id: sdb-part1 | ||
158 | 60 | name: sdb-part1 | ||
159 | 61 | number: 1 | ||
160 | 62 | offset: 4194304B | ||
161 | 63 | size: 511705088B | ||
162 | 64 | type: partition | ||
163 | 65 | uuid: 86326392-3706-4124-87c6-2992acfa31cc | ||
164 | 66 | wipe: superblock | ||
165 | 67 | - device: sdb | ||
166 | 68 | id: sdb-part2 | ||
167 | 69 | name: sdb-part2 | ||
168 | 70 | number: 2 | ||
169 | 71 | size: 2G | ||
170 | 72 | type: partition | ||
171 | 73 | uuid: a33a83dd-d1bf-4940-bf3e-6d931de85dbc | ||
172 | 74 | wipe: superblock | ||
173 | 75 | - devices: | ||
174 | 76 | - sda-part2 | ||
175 | 77 | - sdb-part2 | ||
176 | 78 | id: md0 | ||
177 | 79 | name: md0 | ||
178 | 80 | raidlevel: 1 | ||
179 | 81 | spare_devices: [] | ||
180 | 82 | type: raid | ||
181 | 83 | - device: sdb | ||
182 | 84 | id: sdb-part3 | ||
183 | 85 | name: sdb-part3 | ||
184 | 86 | number: 3 | ||
185 | 87 | size: 2G | ||
186 | 88 | type: partition | ||
187 | 89 | uuid: 27e29758-fdcf-4c6a-8578-c92f907a8a9d | ||
188 | 90 | wipe: superblock | ||
189 | 91 | - devices: | ||
190 | 92 | - sda-part3 | ||
191 | 93 | - sdb-part3 | ||
192 | 94 | id: md1 | ||
193 | 95 | name: md1 | ||
194 | 96 | raidlevel: 1 | ||
195 | 97 | spare_devices: [] | ||
196 | 98 | type: raid | ||
197 | 99 | - fstype: fat32 | ||
198 | 100 | id: sda-part1_format | ||
199 | 101 | label: efi | ||
200 | 102 | type: format | ||
201 | 103 | uuid: b3d50fc7-2f9e-4d1a-9e24-28985e4c560b | ||
202 | 104 | volume: sda-part1 | ||
203 | 105 | - fstype: fat32 | ||
204 | 106 | id: sdb-part1_format | ||
205 | 107 | label: efi | ||
206 | 108 | type: format | ||
207 | 109 | uuid: c604cbb1-2ee1-4575-9489-d38a60fa0cf2 | ||
208 | 110 | volume: sdb-part1 | ||
209 | 111 | - fstype: ext4 | ||
210 | 112 | id: md0_format | ||
211 | 113 | label: '' | ||
212 | 114 | type: format | ||
213 | 115 | uuid: 76a315b7-2979-436c-b156-9ae64a565a59 | ||
214 | 116 | volume: md0 | ||
215 | 117 | - fstype: ext4 | ||
216 | 118 | id: md1_format | ||
217 | 119 | label: '' | ||
218 | 120 | type: format | ||
219 | 121 | uuid: 48dceca6-a9f9-4c7b-bfd3-7f3a0faa4ecc | ||
220 | 122 | volume: md1 | ||
221 | 123 | - device: md0_format | ||
222 | 124 | id: md0_mount | ||
223 | 125 | options: '' | ||
224 | 126 | path: / | ||
225 | 127 | type: mount | ||
226 | 128 | - device: sda-part1_format | ||
227 | 129 | id: sda-part1_mount | ||
228 | 130 | options: '' | ||
229 | 131 | path: /boot/efi | ||
230 | 132 | type: mount | ||
231 | 133 | - device: md1_format | ||
232 | 134 | id: md1_mount | ||
233 | 135 | options: '' | ||
234 | 136 | path: /var | ||
235 | 137 | type: mount | ||
236 | 138 | version: 1 | ||
237 | 0 | 139 | ||
238 | === modified file 'tests/unittests/test_block_mdadm.py' | |||
239 | --- tests/unittests/test_block_mdadm.py 2017-01-27 01:00:39 +0000 | |||
240 | +++ tests/unittests/test_block_mdadm.py 2017-05-03 02:14:17 +0000 | |||
241 | @@ -5,6 +5,7 @@ | |||
242 | 5 | from curtin import util | 5 | from curtin import util |
243 | 6 | import os | 6 | import os |
244 | 7 | import subprocess | 7 | import subprocess |
245 | 8 | import textwrap | ||
246 | 8 | 9 | ||
247 | 9 | 10 | ||
248 | 10 | class MdadmTestBase(TestCase): | 11 | class MdadmTestBase(TestCase): |
249 | @@ -348,7 +349,7 @@ | |||
250 | 348 | device = "/dev/vdc" | 349 | device = "/dev/vdc" |
251 | 349 | mdadm.mdadm_stop(device) | 350 | mdadm.mdadm_stop(device) |
252 | 350 | expected_calls = [ | 351 | expected_calls = [ |
254 | 351 | call(["mdadm", "--stop", device], capture=True), | 352 | call(["mdadm", "--manage", "--stop", device], capture=True) |
255 | 352 | ] | 353 | ] |
256 | 353 | self.mock_util.subp.assert_has_calls(expected_calls) | 354 | self.mock_util.subp.assert_has_calls(expected_calls) |
257 | 354 | 355 | ||
258 | @@ -944,4 +945,96 @@ | |||
259 | 944 | mdadm.md_check(md_devname, raidlevel, devices=devices, | 945 | mdadm.md_check(md_devname, raidlevel, devices=devices, |
260 | 945 | spares=spares) | 946 | spares=spares) |
261 | 946 | 947 | ||
262 | 948 | def test_md_present(self): | ||
263 | 949 | mdname = 'md0' | ||
264 | 950 | self.mock_util.load_file.return_value = textwrap.dedent(""" | ||
265 | 951 | Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] | ||
266 | 952 | [raid4] [raid10] | ||
267 | 953 | md0 : active raid1 vdc1[1] vda2[0] | ||
268 | 954 | 3143680 blocks super 1.2 [2/2] [UU] | ||
269 | 955 | |||
270 | 956 | unused devices: <none> | ||
271 | 957 | """) | ||
272 | 958 | |||
273 | 959 | md_is_present = mdadm.md_present(mdname) | ||
274 | 960 | |||
275 | 961 | self.assertTrue(md_is_present) | ||
276 | 962 | self.mock_util.load_file.assert_called_with('/proc/mdstat') | ||
277 | 963 | |||
278 | 964 | def test_md_present_not_found(self): | ||
279 | 965 | mdname = 'md1' | ||
280 | 966 | self.mock_util.load_file.return_value = textwrap.dedent(""" | ||
281 | 967 | Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] | ||
282 | 968 | [raid4] [raid10] | ||
283 | 969 | md0 : active raid1 vdc1[1] vda2[0] | ||
284 | 970 | 3143680 blocks super 1.2 [2/2] [UU] | ||
285 | 971 | |||
286 | 972 | unused devices: <none> | ||
287 | 973 | """) | ||
288 | 974 | |||
289 | 975 | md_is_present = mdadm.md_present(mdname) | ||
290 | 976 | |||
291 | 977 | self.assertFalse(md_is_present) | ||
292 | 978 | self.mock_util.load_file.assert_called_with('/proc/mdstat') | ||
293 | 979 | |||
294 | 980 | def test_md_present_not_found_check_matching(self): | ||
295 | 981 | mdname = 'md1' | ||
296 | 982 | found_mdname = 'md10' | ||
297 | 983 | self.mock_util.load_file.return_value = textwrap.dedent(""" | ||
298 | 984 | Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] | ||
299 | 985 | [raid4] [raid10] | ||
300 | 986 | md10 : active raid1 vdc1[1] vda2[0] | ||
301 | 987 | 3143680 blocks super 1.2 [2/2] [UU] | ||
302 | 988 | |||
303 | 989 | unused devices: <none> | ||
304 | 990 | """) | ||
305 | 991 | |||
306 | 992 | md_is_present = mdadm.md_present(mdname) | ||
307 | 993 | |||
308 | 994 | self.assertFalse(md_is_present, | ||
309 | 995 | "%s mistakenly matched %s" % (mdname, found_mdname)) | ||
310 | 996 | self.mock_util.load_file.assert_called_with('/proc/mdstat') | ||
311 | 997 | |||
312 | 998 | def test_md_present_with_dev_path(self): | ||
313 | 999 | mdname = '/dev/md0' | ||
314 | 1000 | self.mock_util.load_file.return_value = textwrap.dedent(""" | ||
315 | 1001 | Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] | ||
316 | 1002 | [raid4] [raid10] | ||
317 | 1003 | md0 : active raid1 vdc1[1] vda2[0] | ||
318 | 1004 | 3143680 blocks super 1.2 [2/2] [UU] | ||
319 | 1005 | |||
320 | 1006 | unused devices: <none> | ||
321 | 1007 | """) | ||
322 | 1008 | |||
323 | 1009 | md_is_present = mdadm.md_present(mdname) | ||
324 | 1010 | |||
325 | 1011 | self.assertTrue(md_is_present) | ||
326 | 1012 | self.mock_util.load_file.assert_called_with('/proc/mdstat') | ||
327 | 1013 | |||
328 | 1014 | def test_md_present_none(self): | ||
329 | 1015 | mdname = '' | ||
330 | 1016 | self.mock_util.load_file.return_value = textwrap.dedent(""" | ||
331 | 1017 | Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] | ||
332 | 1018 | [raid4] [raid10] | ||
333 | 1019 | md0 : active raid1 vdc1[1] vda2[0] | ||
334 | 1020 | 3143680 blocks super 1.2 [2/2] [UU] | ||
335 | 1021 | |||
336 | 1022 | unused devices: <none> | ||
337 | 1023 | """) | ||
338 | 1024 | |||
339 | 1025 | with self.assertRaises(ValueError): | ||
340 | 1026 | mdadm.md_present(mdname) | ||
341 | 1027 | |||
342 | 1028 | # util.load_file should NOT have been called | ||
343 | 1029 | self.assertEqual([], self.mock_util.call_args_list) | ||
344 | 1030 | |||
345 | 1031 | def test_md_present_no_proc_mdstat(self): | ||
346 | 1032 | mdname = 'md0' | ||
347 | 1033 | self.mock_util.side_effect = IOError | ||
348 | 1034 | |||
349 | 1035 | md_is_present = mdadm.md_present(mdname) | ||
350 | 1036 | self.assertFalse(md_is_present) | ||
351 | 1037 | self.mock_util.load_file.assert_called_with('/proc/mdstat') | ||
352 | 1038 | |||
353 | 1039 | |||
354 | 947 | # vi: ts=4 expandtab syntax=python | 1040 | # vi: ts=4 expandtab syntax=python |
355 | 948 | 1041 | ||
356 | === modified file 'tests/unittests/test_clear_holders.py' | |||
357 | --- tests/unittests/test_clear_holders.py 2017-04-11 20:52:11 +0000 | |||
358 | +++ tests/unittests/test_clear_holders.py 2017-05-03 02:14:17 +0000 | |||
359 | @@ -360,16 +360,70 @@ | |||
360 | 360 | mock_util.subp.assert_called_with( | 360 | mock_util.subp.assert_called_with( |
361 | 361 | ['cryptsetup', 'remove', self.test_blockdev], capture=True) | 361 | ['cryptsetup', 'remove', self.test_blockdev], capture=True) |
362 | 362 | 362 | ||
363 | 363 | @mock.patch('curtin.block.clear_holders.time') | ||
364 | 364 | @mock.patch('curtin.block.clear_holders.util') | ||
365 | 363 | @mock.patch('curtin.block.clear_holders.LOG') | 365 | @mock.patch('curtin.block.clear_holders.LOG') |
366 | 364 | @mock.patch('curtin.block.clear_holders.mdadm') | 366 | @mock.patch('curtin.block.clear_holders.mdadm') |
367 | 365 | @mock.patch('curtin.block.clear_holders.block') | 367 | @mock.patch('curtin.block.clear_holders.block') |
369 | 366 | def test_shutdown_mdadm(self, mock_block, mock_mdadm, mock_log): | 368 | def test_shutdown_mdadm(self, mock_block, mock_mdadm, mock_log, mock_util, |
370 | 369 | mock_time): | ||
371 | 367 | """test clear_holders.shutdown_mdadm""" | 370 | """test clear_holders.shutdown_mdadm""" |
372 | 368 | mock_block.sysfs_to_devpath.return_value = self.test_blockdev | 371 | mock_block.sysfs_to_devpath.return_value = self.test_blockdev |
373 | 372 | mock_block.path_to_kname.return_value = self.test_blockdev | ||
374 | 373 | mock_mdadm.md_present.return_value = False | ||
375 | 369 | clear_holders.shutdown_mdadm(self.test_syspath) | 374 | clear_holders.shutdown_mdadm(self.test_syspath) |
376 | 370 | mock_mdadm.mdadm_stop.assert_called_with(self.test_blockdev) | 375 | mock_mdadm.mdadm_stop.assert_called_with(self.test_blockdev) |
379 | 371 | mock_mdadm.mdadm_remove.assert_called_with(self.test_blockdev) | 376 | mock_mdadm.md_present.assert_called_with(self.test_blockdev) |
380 | 372 | self.assertTrue(mock_log.debug.called) | 377 | self.assertTrue(mock_log.debug.called) |
381 | 378 | |||
382 | 379 | @mock.patch('curtin.block.clear_holders.os') | ||
383 | 380 | @mock.patch('curtin.block.clear_holders.time') | ||
384 | 381 | @mock.patch('curtin.block.clear_holders.util') | ||
385 | 382 | @mock.patch('curtin.block.clear_holders.LOG') | ||
386 | 383 | @mock.patch('curtin.block.clear_holders.mdadm') | ||
387 | 384 | @mock.patch('curtin.block.clear_holders.block') | ||
388 | 385 | def test_shutdown_mdadm_fail_raises_oserror(self, mock_block, mock_mdadm, | ||
389 | 386 | mock_log, mock_util, mock_time, | ||
390 | 387 | mock_os): | ||
391 | 388 | """test clear_holders.shutdown_mdadm raises OSError on failure""" | ||
392 | 389 | mock_block.sysfs_to_devpath.return_value = self.test_blockdev | ||
393 | 390 | mock_block.path_to_kname.return_value = self.test_blockdev | ||
394 | 391 | mock_mdadm.md_present.return_value = True | ||
395 | 392 | mock_util.subp.return_value = ("", "") | ||
396 | 393 | mock_os.path.exists.return_value = True | ||
397 | 394 | |||
398 | 395 | with self.assertRaises(OSError): | ||
399 | 396 | clear_holders.shutdown_mdadm(self.test_syspath) | ||
400 | 397 | |||
401 | 398 | mock_mdadm.mdadm_stop.assert_called_with(self.test_blockdev) | ||
402 | 399 | mock_mdadm.md_present.assert_called_with(self.test_blockdev) | ||
403 | 400 | mock_util.load_file.assert_called_with('/proc/mdstat') | ||
404 | 401 | self.assertTrue(mock_log.debug.called) | ||
405 | 402 | self.assertTrue(mock_log.critical.called) | ||
406 | 403 | |||
407 | 404 | @mock.patch('curtin.block.clear_holders.os') | ||
408 | 405 | @mock.patch('curtin.block.clear_holders.time') | ||
409 | 406 | @mock.patch('curtin.block.clear_holders.util') | ||
410 | 407 | @mock.patch('curtin.block.clear_holders.LOG') | ||
411 | 408 | @mock.patch('curtin.block.clear_holders.mdadm') | ||
412 | 409 | @mock.patch('curtin.block.clear_holders.block') | ||
413 | 410 | def test_shutdown_mdadm_fails_no_proc_mdstat(self, mock_block, mock_mdadm, | ||
414 | 411 | mock_log, mock_util, | ||
415 | 412 | mock_time, mock_os): | ||
416 | 413 | """test clear_holders.shutdown_mdadm handles no /proc/mdstat""" | ||
417 | 414 | mock_block.sysfs_to_devpath.return_value = self.test_blockdev | ||
418 | 415 | mock_block.path_to_kname.return_value = self.test_blockdev | ||
419 | 416 | mock_mdadm.md_present.return_value = True | ||
420 | 417 | mock_os.path.exists.return_value = False | ||
421 | 418 | |||
422 | 419 | with self.assertRaises(OSError): | ||
423 | 420 | clear_holders.shutdown_mdadm(self.test_syspath) | ||
424 | 421 | |||
425 | 422 | mock_mdadm.mdadm_stop.assert_called_with(self.test_blockdev) | ||
426 | 423 | mock_mdadm.md_present.assert_called_with(self.test_blockdev) | ||
427 | 424 | self.assertEqual([], mock_util.subp.call_args_list) | ||
428 | 425 | self.assertTrue(mock_log.debug.called) | ||
429 | 426 | self.assertTrue(mock_log.critical.called) | ||
430 | 373 | 427 | ||
431 | 374 | @mock.patch('curtin.block.clear_holders.LOG') | 428 | @mock.patch('curtin.block.clear_holders.LOG') |
432 | 375 | @mock.patch('curtin.block.clear_holders.block') | 429 | @mock.patch('curtin.block.clear_holders.block') |
433 | 376 | 430 | ||
434 | === modified file 'tests/vmtests/test_mdadm_bcache.py' | |||
435 | --- tests/vmtests/test_mdadm_bcache.py 2017-04-03 02:27:33 +0000 | |||
436 | +++ tests/vmtests/test_mdadm_bcache.py 2017-05-03 02:14:17 +0000 | |||
437 | @@ -16,6 +16,10 @@ | |||
438 | 16 | grep -c active /proc/mdstat > mdadm_active2 | 16 | grep -c active /proc/mdstat > mdadm_active2 |
439 | 17 | ls /dev/disk/by-dname > ls_dname | 17 | ls /dev/disk/by-dname > ls_dname |
440 | 18 | find /etc/network/interfaces.d > find_interfacesd | 18 | find /etc/network/interfaces.d > find_interfacesd |
441 | 19 | cat /proc/mdstat | tee mdstat | ||
442 | 20 | cat /proc/partitions | tee procpartitions | ||
443 | 21 | ls -1 /sys/class/block | tee sys_class_block | ||
444 | 22 | ls -1 /dev/md* | tee dev_md | ||
445 | 19 | """)] | 23 | """)] |
446 | 20 | 24 | ||
447 | 21 | def test_mdadm_output_files_exist(self): | 25 | def test_mdadm_output_files_exist(self): |
448 | @@ -234,6 +238,42 @@ | |||
449 | 234 | __test__ = True | 238 | __test__ = True |
450 | 235 | 239 | ||
451 | 236 | 240 | ||
452 | 241 | class TestMirrorbootPartitionsUEFIAbs(TestMdadmAbs): | ||
453 | 242 | # alternative config for more complex setup | ||
454 | 243 | conf_file = "examples/tests/mirrorboot-uefi.yaml" | ||
455 | 244 | # initialize secondary disk | ||
456 | 245 | extra_disks = ['10G'] | ||
457 | 246 | disk_to_check = [('main_disk', 2), | ||
458 | 247 | ('second_disk', 3), | ||
459 | 248 | ('md0', 0), | ||
460 | 249 | ('md1', 0)] | ||
461 | 250 | active_mdadm = "2" | ||
462 | 251 | uefi = True | ||
463 | 252 | |||
464 | 253 | |||
465 | 254 | class TrustyTestMirrorbootPartitionsUEFI(relbase.trusty, | ||
466 | 255 | TestMirrorbootPartitionsUEFIAbs): | ||
467 | 256 | __test__ = True | ||
468 | 257 | |||
469 | 258 | # FIXME(LP: #1523037): dname does not work on trusty | ||
470 | 259 | # when dname works on trusty, then we need to re-enable by removing line. | ||
471 | 260 | def test_dname(self): | ||
472 | 261 | print("test_dname does not work for Trusty") | ||
473 | 262 | |||
474 | 263 | def test_ptable(self): | ||
475 | 264 | print("test_ptable does not work for Trusty") | ||
476 | 265 | |||
477 | 266 | |||
478 | 267 | class XenialTestMirrorbootPartitionsUEFI(relbase.xenial, | ||
479 | 268 | TestMirrorbootPartitionsUEFIAbs): | ||
480 | 269 | __test__ = True | ||
481 | 270 | |||
482 | 271 | |||
483 | 272 | class ZestyTestMirrorbootPartitionsUEFI(relbase.zesty, | ||
484 | 273 | TestMirrorbootPartitionsUEFIAbs): | ||
485 | 274 | __test__ = True | ||
486 | 275 | |||
487 | 276 | |||
488 | 237 | class TestRaid5bootAbs(TestMdadmAbs): | 277 | class TestRaid5bootAbs(TestMdadmAbs): |
489 | 238 | # alternative config for more complex setup | 278 | # alternative config for more complex setup |
490 | 239 | conf_file = "examples/tests/raid5boot.yaml" | 279 | conf_file = "examples/tests/raid5boot.yaml" |
PASSED: Continuous integration, rev:448 /jenkins. ubuntu. com/server/ job/curtin- ci/448/ /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-amd64/ 448 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-arm64/ 448 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-ppc64el/ 448 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-s390x/ 448 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= vm-i386/ 448
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/curtin- ci/448/ rebuild
https:/