Merge ~raharper/curtin:feature/s390x-zkey into curtin:master
- Git
- lp:~raharper/curtin
- feature/s390x-zkey
- Merge into master
Status: | Merged |
---|---|
Approved by: | Ryan Harper |
Approved revision: | 55a46eb11ff0bea6835390d14e867cd7b58cad82 |
Merge reported by: | Server Team CI bot |
Merged at revision: | not available |
Proposed branch: | ~raharper/curtin:feature/s390x-zkey |
Merge into: | curtin:master |
Diff against target: |
476 lines (+349/-17) 6 files modified
curtin/block/__init__.py (+50/-6) curtin/commands/block_meta.py (+39/-9) curtin/commands/curthooks.py (+29/-0) tests/unittests/test_block.py (+33/-0) tests/unittests/test_commands_block_meta.py (+174/-0) tests/unittests/test_curthooks.py (+24/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ryan Harper (community) | Approve | ||
Server Team CI bot | continuous-integration | Approve | |
Dimitri John Ledkov (community) | ship it | Approve | |
Chad Smith | Approve | ||
Review via email: mp+368802@code.launchpad.net |
Commit message
block: Add opportunistic zkey encryption if supported
On s390x, systems with a crypto accelerator may be present
and enabled for sure. When handling a type: dm_crypt block
configuration, curtin will test if zkey is available and if
so, use the zkey command to generate keys and encrypt the
block device using zkey-based secrets.
In the case that zkey is not available, curtin will fallback
to using normal cryptsetup.
Description of the change
Server Team CI bot (server-team-bot) wrote : | # |
Chad Smith (chad.smith) : | # |
Ryan Harper (raharper) wrote : | # |
Thanks for the review, I'll update with changes.
- 534f51b... by Ryan Harper
-
zkey: add strict boolean to toggle log level in error paths.
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:ff03de861d8
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Chad Smith (chad.smith) wrote : | # |
LGTM!thanks for the clarification and fixups.
Dimitri John Ledkov (xnox) wrote : | # |
Only minor questions, and a typo to fix.
Ryan Harper (raharper) wrote : | # |
Thanks for the review, I'll fix it up.
- 7b4fd22... by Ryan Harper
-
fix typo in copy_zkey_
repository log message. - 5d5667b... by Ryan Harper
-
Only install s390-tools-zkey if zkey_used
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:4d6c38d5239
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Dimitri John Ledkov (xnox) wrote : | # |
hahahhahahahahhaha
worse typo ever
hahahhahahahahhaha
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:5d5667b3950
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Ryan Harper (raharper) wrote : | # |
vmtest detects the modprobe failure and fails the install even though it went fine.
I need to refactor the logged message when strict=False so that it doesn't trip up
the failure parsing.
- 55a46eb... by Ryan Harper
-
Reword logged error when strict=False to not trip up vmtest error detection.
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:55a46eb11ff
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Ryan Harper (raharper) wrote : | # |
https:/
-------
Ran 112 tests in 2362.318s
OK
Fri, 21 Jun 2019 20:38:24 +0000: vmtest end [0] in 2365s
Looks good.
Preview Diff
1 | diff --git a/curtin/block/__init__.py b/curtin/block/__init__.py |
2 | index 5d1b1bd..f30c5df 100644 |
3 | --- a/curtin/block/__init__.py |
4 | +++ b/curtin/block/__init__.py |
5 | @@ -668,6 +668,24 @@ def get_proc_mounts(): |
6 | return mounts |
7 | |
8 | |
9 | +def _get_dev_disk_by_prefix(prefix): |
10 | + """ |
11 | + Construct a dictionary mapping devname to disk/<prefix> paths |
12 | + |
13 | + :returns: Dictionary populated by examining /dev/disk/<prefix>/* |
14 | + |
15 | + { |
16 | + '/dev/sda': '/dev/disk/<prefix>/virtio-aaaa', |
17 | + '/dev/sda1': '/dev/disk/<prefix>/virtio-aaaa-part1', |
18 | + } |
19 | + """ |
20 | + return { |
21 | + os.path.realpath(bypfx): bypfx |
22 | + for bypfx in [os.path.join(prefix, path) |
23 | + for path in os.listdir(prefix)] |
24 | + } |
25 | + |
26 | + |
27 | def get_dev_disk_byid(): |
28 | """ |
29 | Construct a dictionary mapping devname to disk/by-id paths |
30 | @@ -679,12 +697,7 @@ def get_dev_disk_byid(): |
31 | '/dev/sda1': '/dev/disk/by-id/virtio-aaaa-part1', |
32 | } |
33 | """ |
34 | - |
35 | - prefix = '/dev/disk/by-id' |
36 | - return { |
37 | - os.path.realpath(byid): byid |
38 | - for byid in [os.path.join(prefix, path) for path in os.listdir(prefix)] |
39 | - } |
40 | + return _get_dev_disk_by_prefix('/dev/disk/by-id') |
41 | |
42 | |
43 | def disk_to_byid_path(kname): |
44 | @@ -696,6 +709,15 @@ def disk_to_byid_path(kname): |
45 | return mapping.get(dev_path(kname)) |
46 | |
47 | |
48 | +def disk_to_bypath_path(kname): |
49 | + """" |
50 | + Return a /dev/disk/by-path path to kname if present. |
51 | + """ |
52 | + |
53 | + mapping = _get_dev_disk_by_prefix('/dev/disk/by-path') |
54 | + return mapping.get(dev_path(kname)) |
55 | + |
56 | + |
57 | def get_device_mapper_links(devpath, first=False): |
58 | """ Return the best devlink to device at devpath. """ |
59 | info = udevadm_info(devpath) |
60 | @@ -892,6 +914,28 @@ def is_online(device): |
61 | return int(device_size) > 0 |
62 | |
63 | |
64 | +def zkey_supported(strict=True): |
65 | + """ Return True if zkey cmd present and can generate keys, else False.""" |
66 | + LOG.debug('Checking if zkey encryption is supported...') |
67 | + try: |
68 | + util.load_kernel_module('pkey') |
69 | + except util.ProcessExecutionError as err: |
70 | + msg = "Failed to load 'pkey' kernel module" |
71 | + LOG.error(msg + ": %s" % err) if strict else LOG.warning(msg) |
72 | + return False |
73 | + |
74 | + try: |
75 | + with tempfile.NamedTemporaryFile() as tf: |
76 | + util.subp(['zkey', 'generate', tf.name], capture=True) |
77 | + LOG.debug('zkey encryption supported.') |
78 | + return True |
79 | + except util.ProcessExecutionError as err: |
80 | + msg = "zkey not supported" |
81 | + LOG.error(msg + ": %s" % err) if strict else LOG.warning(msg) |
82 | + |
83 | + return False |
84 | + |
85 | + |
86 | @contextmanager |
87 | def exclusive_open(path, exclusive=True): |
88 | """ |
89 | diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py |
90 | index 79493fc..a9110a9 100644 |
91 | --- a/curtin/commands/block_meta.py |
92 | +++ b/curtin/commands/block_meta.py |
93 | @@ -1062,6 +1062,7 @@ def dm_crypt_handler(info, storage_config): |
94 | dm_name = info.get('id') |
95 | |
96 | volume_path = get_path_to_storage_volume(volume, storage_config) |
97 | + volume_byid_path = block.disk_to_byid_path(volume_path) |
98 | |
99 | if 'keyfile' in info: |
100 | if 'key' in info: |
101 | @@ -1077,16 +1078,45 @@ def dm_crypt_handler(info, storage_config): |
102 | else: |
103 | raise ValueError("encryption key or keyfile must be specified") |
104 | |
105 | - cmd = ["cryptsetup"] |
106 | - if cipher: |
107 | - cmd.extend(["--cipher", cipher]) |
108 | - if keysize: |
109 | - cmd.extend(["--key-size", keysize]) |
110 | - cmd.extend(["luksFormat", volume_path, keyfile]) |
111 | - |
112 | - util.subp(cmd) |
113 | + # if zkey is available, attempt to generate and use it; if it's not |
114 | + # available or fails to setup properly, fallback to normal cryptsetup |
115 | + # passing strict=False downgrades log messages to warnings |
116 | + zkey_used = None |
117 | + if block.zkey_supported(strict=False): |
118 | + volume_name = "%s:%s" % (volume_byid_path, dm_name) |
119 | + LOG.debug('Attempting to setup zkey for %s', volume_name) |
120 | + luks_type = 'luks2' |
121 | + gen_cmd = ['zkey', 'generate', '--xts', '--volume-type', luks_type, |
122 | + '--sector-size', '4096', '--name', dm_name, |
123 | + '--description', |
124 | + "curtin generated zkey for %s" % volume_name, |
125 | + '--volumes', volume_name] |
126 | + run_cmd = ['zkey', 'cryptsetup', '--run', '--volumes', |
127 | + volume_byid_path, '--batch-mode', '--key-file', keyfile] |
128 | + try: |
129 | + util.subp(gen_cmd, capture=True) |
130 | + util.subp(run_cmd, capture=True) |
131 | + zkey_used = os.path.join(os.path.split(state['fstab'])[0], |
132 | + "zkey_used") |
133 | + # mark in state that we used zkey |
134 | + util.write_file(zkey_used, "1") |
135 | + except util.ProcessExecutionError as e: |
136 | + LOG.exception(e) |
137 | + msg = 'Setup of zkey on %s failed, fallback to cryptsetup.' |
138 | + LOG.error(msg % volume_path) |
139 | + |
140 | + if not zkey_used: |
141 | + LOG.debug('Using cryptsetup on %s', volume_path) |
142 | + luks_type = "luks" |
143 | + cmd = ["cryptsetup"] |
144 | + if cipher: |
145 | + cmd.extend(["--cipher", cipher]) |
146 | + if keysize: |
147 | + cmd.extend(["--key-size", keysize]) |
148 | + cmd.extend(["luksFormat", volume_path, keyfile]) |
149 | + util.subp(cmd) |
150 | |
151 | - cmd = ["cryptsetup", "open", "--type", "luks", volume_path, dm_name, |
152 | + cmd = ["cryptsetup", "open", "--type", luks_type, volume_path, dm_name, |
153 | "--key-file", keyfile] |
154 | |
155 | util.subp(cmd) |
156 | diff --git a/curtin/commands/curthooks.py b/curtin/commands/curthooks.py |
157 | index 75f5083..2869c6c 100644 |
158 | --- a/curtin/commands/curthooks.py |
159 | +++ b/curtin/commands/curthooks.py |
160 | @@ -594,6 +594,28 @@ def copy_zpool_cache(zpool_cache, target): |
161 | shutil.copy(zpool_cache, os.path.sep.join([target, 'etc/zfs'])) |
162 | |
163 | |
164 | +def copy_zkey_repository(zkey_repository, target, |
165 | + target_repo='etc/zkey/repository'): |
166 | + if not zkey_repository: |
167 | + LOG.warn("zkey repository path must be specified, not copying") |
168 | + return |
169 | + |
170 | + tdir = os.path.sep.join([target, target_repo]) |
171 | + if not os.path.exists(tdir): |
172 | + util.ensure_dir(tdir) |
173 | + |
174 | + files_copied = [] |
175 | + for src in os.listdir(zkey_repository): |
176 | + source_path = os.path.join(zkey_repository, src) |
177 | + target_path = os.path.join(tdir, src) |
178 | + if not os.path.exists(target_path): |
179 | + shutil.copy2(source_path, target_path) |
180 | + files_copied.append(target_path) |
181 | + |
182 | + LOG.debug('Imported zkey repo %s with files: %s', |
183 | + zkey_repository, files_copied) |
184 | + |
185 | + |
186 | def apply_networking(target, state): |
187 | netconf = state.get('network_config') |
188 | interfaces = state.get('interfaces') |
189 | @@ -1379,6 +1401,13 @@ def builtin_curthooks(cfg, target, state): |
190 | if os.path.exists(zpool_cache): |
191 | copy_zpool_cache(zpool_cache, target) |
192 | |
193 | + zkey_repository = '/etc/zkey/repository' |
194 | + zkey_used = os.path.join(os.path.split(state['fstab'])[0], "zkey_used") |
195 | + if all(map(os.path.exists, [zkey_repository, zkey_used])): |
196 | + distro.install_packages(['s390-tools-zkey'], target=target, |
197 | + osfamily=osfamily) |
198 | + copy_zkey_repository(zkey_repository, target) |
199 | + |
200 | # If a crypttab file was created by block_meta than it needs to be |
201 | # copied onto the target system, and update_initramfs() needs to be |
202 | # run, so that the cryptsetup hooks are properly configured on the |
203 | diff --git a/tests/unittests/test_block.py b/tests/unittests/test_block.py |
204 | index c7ebdcc..167a697 100644 |
205 | --- a/tests/unittests/test_block.py |
206 | +++ b/tests/unittests/test_block.py |
207 | @@ -712,4 +712,37 @@ class TestGetSupportedFilesystems(CiTestCase): |
208 | self.assertEqual(0, mock_util.load_file.call_count) |
209 | |
210 | |
211 | +class TestZkeySupported(CiTestCase): |
212 | + |
213 | + @mock.patch('curtin.block.util') |
214 | + def test_zkey_supported_loads_module(self, m_util): |
215 | + block.zkey_supported() |
216 | + m_util.load_kernel_module.assert_called_with('pkey') |
217 | + |
218 | + @mock.patch('curtin.block.util.load_kernel_module') |
219 | + def test_zkey_supported_returns_false_missing_kmod(self, m_kmod): |
220 | + m_kmod.side_effect = ( |
221 | + util.ProcessExecutionError(stdout=self.random_string(), |
222 | + stderr=self.random_string(), |
223 | + exit_code=2)) |
224 | + self.assertFalse(block.zkey_supported()) |
225 | + |
226 | + @mock.patch('curtin.block.util.subp') |
227 | + @mock.patch('curtin.block.util.load_kernel_module') |
228 | + def test_zkey_supported_returns_false_zkey_error(self, m_kmod, m_subp): |
229 | + m_subp.side_effect = ( |
230 | + util.ProcessExecutionError(stdout=self.random_string(), |
231 | + stderr=self.random_string(), |
232 | + exit_code=2)) |
233 | + self.assertFalse(block.zkey_supported()) |
234 | + |
235 | + @mock.patch('curtin.block.tempfile.NamedTemporaryFile') |
236 | + @mock.patch('curtin.block.util') |
237 | + def test_zkey_supported_calls_zkey_generate(self, m_util, m_temp): |
238 | + testname = self.random_string() |
239 | + m_temp.return_value.__enter__.return_value.name = testname |
240 | + block.zkey_supported() |
241 | + m_util.subp.assert_called_with(['zkey', 'generate', testname], |
242 | + capture=True) |
243 | + |
244 | # vi: ts=4 expandtab syntax=python |
245 | diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py |
246 | index b4a9afa..b2e151e 100644 |
247 | --- a/tests/unittests/test_commands_block_meta.py |
248 | +++ b/tests/unittests/test_commands_block_meta.py |
249 | @@ -913,4 +913,178 @@ class TestLvmPartitionHandler(CiTestCase): |
250 | self.assertIn(expected_size_str, call_args[0]) |
251 | |
252 | |
253 | +class TestDmCryptHandler(CiTestCase): |
254 | + |
255 | + def setUp(self): |
256 | + super(TestDmCryptHandler, self).setUp() |
257 | + |
258 | + basepath = 'curtin.commands.block_meta.' |
259 | + self.add_patch(basepath + 'get_path_to_storage_volume', 'm_getpath') |
260 | + self.add_patch(basepath + 'util.load_command_environment', |
261 | + 'm_load_env') |
262 | + self.add_patch(basepath + 'util.which', 'm_which') |
263 | + self.add_patch(basepath + 'util.subp', 'm_subp') |
264 | + self.add_patch(basepath + 'block', 'm_block') |
265 | + |
266 | + self.target = "my_target" |
267 | + self.keyfile = self.random_string() |
268 | + self.cipher = self.random_string() |
269 | + self.keysize = self.random_string() |
270 | + self.config = { |
271 | + 'storage': { |
272 | + 'version': 1, |
273 | + 'config': [ |
274 | + {'grub_device': True, |
275 | + 'id': 'sda', |
276 | + 'name': 'sda', |
277 | + 'path': '/wark/xxx', |
278 | + 'ptable': 'msdos', |
279 | + 'type': 'disk', |
280 | + 'wipe': 'superblock'}, |
281 | + {'device': 'sda', |
282 | + 'id': 'sda-part1', |
283 | + 'name': 'sda-part1', |
284 | + 'number': 1, |
285 | + 'size': '511705088B', |
286 | + 'type': 'partition'}, |
287 | + {'id': 'dmcrypt0', |
288 | + 'type': 'dm_crypt', |
289 | + 'dm_name': 'cryptroot', |
290 | + 'volume': 'sda-part1', |
291 | + 'cipher': self.cipher, |
292 | + 'keysize': self.keysize, |
293 | + 'keyfile': self.keyfile}, |
294 | + ], |
295 | + } |
296 | + } |
297 | + self.storage_config = ( |
298 | + block_meta.extract_storage_ordered_dict(self.config)) |
299 | + self.m_block.zkey_supported.return_value = False |
300 | + self.m_which.return_value = False |
301 | + self.fstab = self.tmp_path('fstab') |
302 | + self.crypttab = os.path.join(os.path.dirname(self.fstab), 'crypttab') |
303 | + self.m_load_env.return_value = {'fstab': self.fstab, |
304 | + 'target': self.target} |
305 | + |
306 | + def test_dm_crypt_calls_cryptsetup(self): |
307 | + """ verify dm_crypt calls (format, open) w/ correct params""" |
308 | + volume_path = self.random_string() |
309 | + self.m_getpath.return_value = volume_path |
310 | + |
311 | + info = self.storage_config['dmcrypt0'] |
312 | + block_meta.dm_crypt_handler(info, self.storage_config) |
313 | + expected_calls = [ |
314 | + call(['cryptsetup', '--cipher', self.cipher, |
315 | + '--key-size', self.keysize, |
316 | + 'luksFormat', volume_path, self.keyfile]), |
317 | + call(['cryptsetup', 'open', '--type', 'luks', volume_path, |
318 | + info['dm_name'], '--key-file', self.keyfile]) |
319 | + ] |
320 | + self.m_subp.assert_has_calls(expected_calls) |
321 | + self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1) |
322 | + |
323 | + def test_dm_crypt_zkey_cryptsetup(self): |
324 | + """ verify dm_crypt zkey calls generates and run before crypt open.""" |
325 | + |
326 | + # zkey binary is present |
327 | + self.m_block.zkey_supported.return_value = True |
328 | + self.m_which.return_value = "/my/path/to/zkey" |
329 | + volume_path = self.random_string() |
330 | + self.m_getpath.return_value = volume_path |
331 | + volume_byid = "/dev/disk/by-id/ccw-%s" % volume_path |
332 | + self.m_block.disk_to_byid_path.return_value = volume_byid |
333 | + |
334 | + info = self.storage_config['dmcrypt0'] |
335 | + volume_name = "%s:%s" % (volume_byid, info['dm_name']) |
336 | + block_meta.dm_crypt_handler(info, self.storage_config) |
337 | + expected_calls = [ |
338 | + call(['zkey', 'generate', '--xts', '--volume-type', 'luks2', |
339 | + '--sector-size', '4096', '--name', info['dm_name'], |
340 | + '--description', |
341 | + 'curtin generated zkey for %s' % volume_name, |
342 | + '--volumes', volume_name], capture=True), |
343 | + call(['zkey', 'cryptsetup', '--run', '--volumes', volume_byid, |
344 | + '--batch-mode', '--key-file', self.keyfile], capture=True), |
345 | + call(['cryptsetup', 'open', '--type', 'luks2', volume_path, |
346 | + info['dm_name'], '--key-file', self.keyfile]), |
347 | + ] |
348 | + self.m_subp.assert_has_calls(expected_calls) |
349 | + self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1) |
350 | + |
351 | + def test_dm_crypt_zkey_gen_failure_fallback_to_cryptsetup(self): |
352 | + """ verify dm_cyrpt zkey generate err falls back cryptsetup format. """ |
353 | + |
354 | + # zkey binary is present |
355 | + self.m_block.zkey_supported.return_value = True |
356 | + self.m_which.return_value = "/my/path/to/zkey" |
357 | + |
358 | + self.m_subp.side_effect = iter([ |
359 | + util.ProcessExecutionError("foobar"), # zkey generate |
360 | + (0, 0), # cryptsetup luksFormat |
361 | + (0, 0), # cryptsetup open |
362 | + ]) |
363 | + |
364 | + volume_path = self.random_string() |
365 | + self.m_getpath.return_value = volume_path |
366 | + volume_byid = "/dev/disk/by-id/ccw-%s" % volume_path |
367 | + self.m_block.disk_to_byid_path.return_value = volume_byid |
368 | + |
369 | + info = self.storage_config['dmcrypt0'] |
370 | + volume_name = "%s:%s" % (volume_byid, info['dm_name']) |
371 | + block_meta.dm_crypt_handler(info, self.storage_config) |
372 | + expected_calls = [ |
373 | + call(['zkey', 'generate', '--xts', '--volume-type', 'luks2', |
374 | + '--sector-size', '4096', '--name', info['dm_name'], |
375 | + '--description', |
376 | + 'curtin generated zkey for %s' % volume_name, |
377 | + '--volumes', volume_name], capture=True), |
378 | + call(['cryptsetup', '--cipher', self.cipher, |
379 | + '--key-size', self.keysize, |
380 | + 'luksFormat', volume_path, self.keyfile]), |
381 | + call(['cryptsetup', 'open', '--type', 'luks', volume_path, |
382 | + info['dm_name'], '--key-file', self.keyfile]) |
383 | + ] |
384 | + self.m_subp.assert_has_calls(expected_calls) |
385 | + self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1) |
386 | + |
387 | + def test_dm_crypt_zkey_run_failure_fallback_to_cryptsetup(self): |
388 | + """ verify dm_cyrpt zkey run err falls back on cryptsetup format. """ |
389 | + |
390 | + # zkey binary is present |
391 | + self.m_block.zkey_supported.return_value = True |
392 | + self.m_which.return_value = "/my/path/to/zkey" |
393 | + |
394 | + self.m_subp.side_effect = iter([ |
395 | + (0, 0), # zkey generate |
396 | + util.ProcessExecutionError("foobar"), # zkey cryptsetup --run |
397 | + (0, 0), # cryptsetup luksFormat |
398 | + (0, 0), # cryptsetup open |
399 | + ]) |
400 | + |
401 | + volume_path = self.random_string() |
402 | + self.m_getpath.return_value = volume_path |
403 | + volume_byid = "/dev/disk/by-id/ccw-%s" % volume_path |
404 | + self.m_block.disk_to_byid_path.return_value = volume_byid |
405 | + |
406 | + info = self.storage_config['dmcrypt0'] |
407 | + volume_name = "%s:%s" % (volume_byid, info['dm_name']) |
408 | + block_meta.dm_crypt_handler(info, self.storage_config) |
409 | + expected_calls = [ |
410 | + call(['zkey', 'generate', '--xts', '--volume-type', 'luks2', |
411 | + '--sector-size', '4096', '--name', info['dm_name'], |
412 | + '--description', |
413 | + 'curtin generated zkey for %s' % volume_name, |
414 | + '--volumes', volume_name], capture=True), |
415 | + call(['zkey', 'cryptsetup', '--run', '--volumes', volume_byid, |
416 | + '--batch-mode', '--key-file', self.keyfile], capture=True), |
417 | + call(['cryptsetup', '--cipher', self.cipher, |
418 | + '--key-size', self.keysize, |
419 | + 'luksFormat', volume_path, self.keyfile]), |
420 | + call(['cryptsetup', 'open', '--type', 'luks', volume_path, |
421 | + info['dm_name'], '--key-file', self.keyfile]) |
422 | + ] |
423 | + self.m_subp.assert_has_calls(expected_calls) |
424 | + self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1) |
425 | + |
426 | + |
427 | # vi: ts=4 expandtab syntax=python |
428 | diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py |
429 | index 26a582c..e7d506e 100644 |
430 | --- a/tests/unittests/test_curthooks.py |
431 | +++ b/tests/unittests/test_curthooks.py |
432 | @@ -9,7 +9,7 @@ from curtin import distro |
433 | from curtin import util |
434 | from curtin import config |
435 | from curtin.reporter import events |
436 | -from .helpers import CiTestCase, dir2dict |
437 | +from .helpers import CiTestCase, dir2dict, populate_dir |
438 | |
439 | |
440 | class TestGetFlashKernelPkgs(CiTestCase): |
441 | @@ -201,7 +201,8 @@ class TestInstallMissingPkgs(CiTestCase): |
442 | cfg = {} |
443 | curthooks.install_missing_packages(cfg, target=target) |
444 | self.mock_install_packages.assert_called_with( |
445 | - ['s390-tools'], target=target, osfamily=self.distro_family) |
446 | + ['s390-tools'], target=target, |
447 | + osfamily=self.distro_family) |
448 | |
449 | @patch.object(events, 'ReportEventStack') |
450 | def test_install_packages_s390x_has_zipl(self, mock_events): |
451 | @@ -1140,4 +1141,25 @@ class TestCurthooksChzdev(CiTestCase): |
452 | output = curthooks.chzdev_prepare_for_import(self.chzdev_export) |
453 | self.assertEqual(self.chzdev_import, output) |
454 | |
455 | + |
456 | +class TestCurthooksCopyZkey(CiTestCase): |
457 | + def setUp(self): |
458 | + super(TestCurthooksCopyZkey, self).setUp() |
459 | + self.add_patch('curtin.distro.install_packages', 'mock_instpkg') |
460 | + |
461 | + self.target = self.tmp_dir() |
462 | + self.host_dir = self.tmp_dir() |
463 | + self.zkey_content = { |
464 | + '/etc/zkey/repository/mykey.info': "key info", |
465 | + '/etc/zkey/repository/mykey.skey': "key data", |
466 | + } |
467 | + self.files = populate_dir(self.host_dir, self.zkey_content) |
468 | + self.host_zkey = os.path.join(self.host_dir, 'etc/zkey/repository') |
469 | + |
470 | + def test_copy_zkey_when_dir_present(self): |
471 | + curthooks.copy_zkey_repository(self.host_zkey, self.target) |
472 | + found_files = dir2dict(self.target, prefix=self.target) |
473 | + self.assertEqual(self.zkey_content, found_files) |
474 | + |
475 | + |
476 | # vi: ts=4 expandtab syntax=python |
PASSED: Continuous integration, rev:71392162468 008a273258c5b2c 4dfa09c8997dc9 /jenkins. ubuntu. com/server/ job/curtin- ci/1296/ /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-arm64/ 1296 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-ppc64el/ 1296 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-s390x/ 1296 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= torkoal/ 1296
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/curtin- ci/1296/ rebuild
https:/