Merge ~dbungert/curtin:cryptoswap into curtin:master
- Git
- lp:~dbungert/curtin
- cryptoswap
- Merge into master
Proposed by
Dan Bungert
Status: | Merged |
---|---|
Merged at revision: | 1997a1614e774cbd152fa33059d53417a641dbd6 |
Proposed branch: | ~dbungert/curtin:cryptoswap |
Merge into: | curtin:master |
Diff against target: |
348 lines (+196/-17) 5 files modified
curtin/commands/block_meta.py (+11/-3) doc/topics/storage.rst (+13/-1) tests/integration/test_block_meta.py (+45/-1) tests/unittests/test_commands_block_meta.py (+126/-12) tools/vmtest-system-setup (+1/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Gayot | Approve | ||
Server Team CI bot | continuous-integration | Approve | |
Chris Peterson | Approve | ||
Review via email: mp+458460@code.launchpad.net |
Commit message
Add features to the dm_crypt action to support cryptoswap
Description of the change
To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Chris Peterson (cpete) : | # |
review:
Approve
Revision history for this message
Olivier Gayot (ogayot) wrote : | # |
Thanks! I only have minor suggestions. Nothing blocking really.
Revision history for this message
Dan Bungert (dbungert) : | # |
Revision history for this message
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:1997a1614e7
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py | |||
2 | index ebae27c..8ba7a55 100644 | |||
3 | --- a/curtin/commands/block_meta.py | |||
4 | +++ b/curtin/commands/block_meta.py | |||
5 | @@ -1618,6 +1618,8 @@ def dm_crypt_handler(info, storage_config, context): | |||
6 | 1618 | keysize = info.get('keysize') | 1618 | keysize = info.get('keysize') |
7 | 1619 | cipher = info.get('cipher') | 1619 | cipher = info.get('cipher') |
8 | 1620 | dm_name = info.get('dm_name') | 1620 | dm_name = info.get('dm_name') |
9 | 1621 | options = ','.join(info.get('options', ['luks'])) | ||
10 | 1622 | crypttab_keyfile = 'none' | ||
11 | 1621 | if not dm_name: | 1623 | if not dm_name: |
12 | 1622 | dm_name = info.get('id') | 1624 | dm_name = info.get('id') |
13 | 1623 | dmcrypt_dev = os.path.join("/dev", "mapper", dm_name) | 1625 | dmcrypt_dev = os.path.join("/dev", "mapper", dm_name) |
14 | @@ -1634,8 +1636,13 @@ def dm_crypt_handler(info, storage_config, context): | |||
15 | 1634 | if 'keyfile' in info: | 1636 | if 'keyfile' in info: |
16 | 1635 | if 'key' in info: | 1637 | if 'key' in info: |
17 | 1636 | raise ValueError("cannot specify both key and keyfile") | 1638 | raise ValueError("cannot specify both key and keyfile") |
18 | 1637 | keyfile_is_tmp = False | ||
19 | 1638 | keyfile = info['keyfile'] | 1639 | keyfile = info['keyfile'] |
20 | 1640 | if keyfile in ("/dev/random", "/dev/urandom"): | ||
21 | 1641 | crypttab_keyfile = keyfile | ||
22 | 1642 | keyfile = tempfile.mkstemp()[1] | ||
23 | 1643 | keyfile_is_tmp = True | ||
24 | 1644 | else: | ||
25 | 1645 | keyfile_is_tmp = False | ||
26 | 1639 | elif 'key' in info: | 1646 | elif 'key' in info: |
27 | 1640 | # TODO: this is insecure, find better way to do this | 1647 | # TODO: this is insecure, find better way to do this |
28 | 1641 | key = info.get('key') | 1648 | key = info.get('key') |
29 | @@ -1727,8 +1734,9 @@ def dm_crypt_handler(info, storage_config, context): | |||
30 | 1727 | state_dir = os.path.dirname(state['fstab']) | 1734 | state_dir = os.path.dirname(state['fstab']) |
31 | 1728 | crypt_tab_location = os.path.join(state_dir, "crypttab") | 1735 | crypt_tab_location = os.path.join(state_dir, "crypttab") |
32 | 1729 | uuid = block.get_volume_uuid(volume_path) | 1736 | uuid = block.get_volume_uuid(volume_path) |
35 | 1730 | util.write_file(crypt_tab_location, | 1737 | util.write_file( |
36 | 1731 | "%s UUID=%s none luks\n" % (dm_name, uuid), omode="a") | 1738 | crypt_tab_location, |
37 | 1739 | f"{dm_name} UUID={uuid} {crypttab_keyfile} {options}\n", omode="a") | ||
38 | 1732 | else: | 1740 | else: |
39 | 1733 | LOG.info("fstab configuration is not present in environment, so \ | 1741 | LOG.info("fstab configuration is not present in environment, so \ |
40 | 1734 | cannot locate an appropriate directory to write crypttab in \ | 1742 | cannot locate an appropriate directory to write crypttab in \ |
41 | diff --git a/doc/topics/storage.rst b/doc/topics/storage.rst | |||
42 | index 45b9bbe..97e900d 100644 | |||
43 | --- a/doc/topics/storage.rst | |||
44 | +++ b/doc/topics/storage.rst | |||
45 | @@ -886,6 +886,15 @@ system will prompt for this password in order to mount the disk. | |||
46 | 886 | The ``keyfile`` contains the password of the encryption key. The target | 886 | The ``keyfile`` contains the password of the encryption key. The target |
47 | 887 | system will prompt for this password in order to mount the disk. | 887 | system will prompt for this password in order to mount the disk. |
48 | 888 | 888 | ||
49 | 889 | A special case of ``keyfile`` are the values ``/dev/urandom`` and | ||
50 | 890 | ``/dev/random``, which indicate that this ``keyfile`` value will be used in | ||
51 | 891 | entirety to decrypt the device. In this case, the keyfile is passed along to | ||
52 | 892 | the crypttab, as the third field. | ||
53 | 893 | |||
54 | 894 | .. note:: | ||
55 | 895 | ``/dev/urandom`` and ``/dev/random`` are functionally equivalent on modern | ||
56 | 896 | systems. | ||
57 | 897 | |||
58 | 889 | Exactly one of **key** and **keyfile** must be supplied. | 898 | Exactly one of **key** and **keyfile** must be supplied. |
59 | 890 | 899 | ||
60 | 891 | **preserve**: *true, false* | 900 | **preserve**: *true, false* |
61 | @@ -893,13 +902,16 @@ Exactly one of **key** and **keyfile** must be supplied. | |||
62 | 893 | If the ``preserve`` option is True, curtin will verify the dm-crypt device | 902 | If the ``preserve`` option is True, curtin will verify the dm-crypt device |
63 | 894 | specified is composed of the device specified in ``volume``. | 903 | specified is composed of the device specified in ``volume``. |
64 | 895 | 904 | ||
65 | 896 | |||
66 | 897 | **wipe**: *superblock, superblock-recursive, pvremove, zero, random* | 905 | **wipe**: *superblock, superblock-recursive, pvremove, zero, random* |
67 | 898 | 906 | ||
68 | 899 | If ``wipe`` option is set, and ``preserve`` is False, curtin will wipe the | 907 | If ``wipe`` option is set, and ``preserve`` is False, curtin will wipe the |
69 | 900 | contents of the dm-crypt device. Curtin skips wipe settings if it creates | 908 | contents of the dm-crypt device. Curtin skips wipe settings if it creates |
70 | 901 | the dm-crypt volume. | 909 | the dm-crypt volume. |
71 | 902 | 910 | ||
72 | 911 | **options**: *<list of man 5 crypttab options strings>* | ||
73 | 912 | |||
74 | 913 | Options to pass to crypttab, as the fourth field. See man 5 crypttab for | ||
75 | 914 | details. The default is ``[luks]``. | ||
76 | 903 | 915 | ||
77 | 904 | .. note:: | 916 | .. note:: |
78 | 905 | 917 | ||
79 | diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py | |||
80 | index acd12e1..ec9b33c 100644 | |||
81 | --- a/tests/integration/test_block_meta.py | |||
82 | +++ b/tests/integration/test_block_meta.py | |||
83 | @@ -6,6 +6,7 @@ import contextlib | |||
84 | 6 | import json | 6 | import json |
85 | 7 | import os | 7 | import os |
86 | 8 | from parameterized import parameterized | 8 | from parameterized import parameterized |
87 | 9 | from pathlib import Path | ||
88 | 9 | import re | 10 | import re |
89 | 10 | import sys | 11 | import sys |
90 | 11 | from typing import Optional | 12 | from typing import Optional |
91 | @@ -192,6 +193,15 @@ class StorageConfigBuilder: | |||
92 | 192 | for action in self.config: | 193 | for action in self.config: |
93 | 193 | action['preserve'] = True | 194 | action['preserve'] = True |
94 | 194 | 195 | ||
95 | 196 | def add_dmcrypt(self, *, volume, dm_name=None, **kw): | ||
96 | 197 | if dm_name is None: | ||
97 | 198 | dm_name = CiTestCase.random_string() | ||
98 | 199 | return self._add( | ||
99 | 200 | type='dm_crypt', | ||
100 | 201 | volume=volume['id'], | ||
101 | 202 | dm_name=dm_name, | ||
102 | 203 | **kw) | ||
103 | 204 | |||
104 | 195 | 205 | ||
105 | 196 | class TestBlockMeta(IntegrationTestCase): | 206 | class TestBlockMeta(IntegrationTestCase): |
106 | 197 | def setUp(self): | 207 | def setUp(self): |
107 | @@ -239,15 +249,17 @@ class TestBlockMeta(IntegrationTestCase): | |||
108 | 239 | with open(config_path, 'w') as fp: | 249 | with open(config_path, 'w') as fp: |
109 | 240 | yaml.dump(config, fp) | 250 | yaml.dump(config, fp) |
110 | 241 | 251 | ||
111 | 252 | self.fstab_dir = self.tmp_dir() | ||
112 | 242 | cmd_env = kwargs.pop('env', {}) | 253 | cmd_env = kwargs.pop('env', {}) |
113 | 243 | cmd_env.update({ | 254 | cmd_env.update({ |
114 | 244 | 'PATH': os.environ['PATH'], | 255 | 'PATH': os.environ['PATH'], |
115 | 245 | 'CONFIG': config_path, | 256 | 'CONFIG': config_path, |
116 | 246 | 'WORKING_DIR': '/tmp', | 257 | 'WORKING_DIR': '/tmp', |
118 | 247 | 'OUTPUT_FSTAB': self.tmp_path('fstab'), | 258 | 'OUTPUT_FSTAB': self.tmp_path('fstab', _dir=self.fstab_dir), |
119 | 248 | 'OUTPUT_INTERFACES': '', | 259 | 'OUTPUT_INTERFACES': '', |
120 | 249 | 'OUTPUT_NETWORK_STATE': '', | 260 | 'OUTPUT_NETWORK_STATE': '', |
121 | 250 | 'OUTPUT_NETWORK_CONFIG': '', | 261 | 'OUTPUT_NETWORK_CONFIG': '', |
122 | 262 | 'TARGET_MOUNT_POINT': self.tmp_dir(), | ||
123 | 251 | }) | 263 | }) |
124 | 252 | 264 | ||
125 | 253 | cmd = [ | 265 | cmd = [ |
126 | @@ -1285,6 +1297,38 @@ table-length: 256'''.encode() | |||
127 | 1285 | partition_type='82')) | 1297 | partition_type='82')) |
128 | 1286 | 1298 | ||
129 | 1287 | @parameterized.expand(((1,), (2,))) | 1299 | @parameterized.expand(((1,), (2,))) |
130 | 1300 | def test_cryptoswap(self, sv=2): | ||
131 | 1301 | self.img = self.tmp_path('image.img') | ||
132 | 1302 | config = StorageConfigBuilder(version=sv) | ||
133 | 1303 | config.add_image(path=self.img, create=True, size='200M', | ||
134 | 1304 | ptable='msdos') | ||
135 | 1305 | p1 = config.add_part( | ||
136 | 1306 | number=1, offset=1 << 20, size=19 << 20, flag='swap' | ||
137 | 1307 | ) | ||
138 | 1308 | cryptoswap = f"cryptoswap-{self.random_string(length=6)}" | ||
139 | 1309 | dmc1 = config.add_dmcrypt( | ||
140 | 1310 | volume=p1, | ||
141 | 1311 | dm_name=cryptoswap, | ||
142 | 1312 | keyfile="/dev/urandom", | ||
143 | 1313 | options=["swap", "initramfs"], | ||
144 | 1314 | ) | ||
145 | 1315 | config.add_format(part=dmc1, fstype="swap") | ||
146 | 1316 | self.run_bm(config.render()) | ||
147 | 1317 | |||
148 | 1318 | self.assertPartitions( | ||
149 | 1319 | PartData(number=1, offset=1 << 20, size=19 << 20, boot=False, | ||
150 | 1320 | partition_type='82')) | ||
151 | 1321 | |||
152 | 1322 | crypttab_path = Path(self.fstab_dir) / "crypttab" | ||
153 | 1323 | with open(crypttab_path) as fp: | ||
154 | 1324 | crypttab = fp.read() | ||
155 | 1325 | tokens = re.split(r'\s+', crypttab) | ||
156 | 1326 | self.assertEqual(cryptoswap, tokens[0]) | ||
157 | 1327 | self.assertTrue(tokens[1].startswith("UUID=")) | ||
158 | 1328 | self.assertEqual("/dev/urandom", tokens[2]) | ||
159 | 1329 | self.assertEqual("swap,initramfs", tokens[3]) | ||
160 | 1330 | |||
161 | 1331 | @parameterized.expand(((1,), (2,))) | ||
162 | 1288 | def test_msftres(self, sv): | 1332 | def test_msftres(self, sv): |
163 | 1289 | self.img = self.tmp_path('image.img') | 1333 | self.img = self.tmp_path('image.img') |
164 | 1290 | config = StorageConfigBuilder(version=sv) | 1334 | config = StorageConfigBuilder(version=sv) |
165 | diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py | |||
166 | index 9d7d0f3..5adb46c 100644 | |||
167 | --- a/tests/unittests/test_commands_block_meta.py | |||
168 | +++ b/tests/unittests/test_commands_block_meta.py | |||
169 | @@ -2030,10 +2030,10 @@ class TestLvmPartitionHandler(CiTestCase): | |||
170 | 2030 | self.assertEqual(0, self.m_subp.call_count) | 2030 | self.assertEqual(0, self.m_subp.call_count) |
171 | 2031 | 2031 | ||
172 | 2032 | 2032 | ||
174 | 2033 | class TestDmCryptHandler(CiTestCase): | 2033 | class DmCryptCommon(CiTestCase): |
175 | 2034 | 2034 | ||
176 | 2035 | def setUp(self): | 2035 | def setUp(self): |
178 | 2036 | super(TestDmCryptHandler, self).setUp() | 2036 | super().setUp() |
179 | 2037 | 2037 | ||
180 | 2038 | basepath = 'curtin.commands.block_meta.' | 2038 | basepath = 'curtin.commands.block_meta.' |
181 | 2039 | self.add_patch(basepath + 'get_path_to_storage_volume', 'm_getpath') | 2039 | self.add_patch(basepath + 'get_path_to_storage_volume', 'm_getpath') |
182 | @@ -2047,7 +2047,26 @@ class TestDmCryptHandler(CiTestCase): | |||
183 | 2047 | self.keyfile = self.random_string() | 2047 | self.keyfile = self.random_string() |
184 | 2048 | self.cipher = self.random_string() | 2048 | self.cipher = self.random_string() |
185 | 2049 | self.keysize = self.random_string() | 2049 | self.keysize = self.random_string() |
187 | 2050 | self.config = { | 2050 | self.m_block.zkey_supported.return_value = False |
188 | 2051 | self.block_uuids = [random_uuid() for unused in range(2)] | ||
189 | 2052 | self.m_block.get_volume_uuid.side_effect = self.block_uuids | ||
190 | 2053 | |||
191 | 2054 | self.m_which.return_value = False | ||
192 | 2055 | self.fstab = self.tmp_path('fstab') | ||
193 | 2056 | self.crypttab = os.path.join(os.path.dirname(self.fstab), 'crypttab') | ||
194 | 2057 | self.m_load_env.return_value = {'fstab': self.fstab, | ||
195 | 2058 | 'target': self.target} | ||
196 | 2059 | |||
197 | 2060 | def setUpStorageConfig(self, config): | ||
198 | 2061 | self.config = config | ||
199 | 2062 | self.storage_config = block_meta.extract_storage_ordered_dict(config) | ||
200 | 2063 | |||
201 | 2064 | |||
202 | 2065 | class TestDmCryptHandler(DmCryptCommon): | ||
203 | 2066 | |||
204 | 2067 | def setUp(self): | ||
205 | 2068 | super().setUp() | ||
206 | 2069 | self.setUpStorageConfig({ | ||
207 | 2051 | 'storage': { | 2070 | 'storage': { |
208 | 2052 | 'version': 1, | 2071 | 'version': 1, |
209 | 2053 | 'config': [ | 2072 | 'config': [ |
210 | @@ -2073,15 +2092,7 @@ class TestDmCryptHandler(CiTestCase): | |||
211 | 2073 | 'keyfile': self.keyfile}, | 2092 | 'keyfile': self.keyfile}, |
212 | 2074 | ], | 2093 | ], |
213 | 2075 | } | 2094 | } |
223 | 2076 | } | 2095 | }) |
215 | 2077 | self.storage_config = ( | ||
216 | 2078 | block_meta.extract_storage_ordered_dict(self.config)) | ||
217 | 2079 | self.m_block.zkey_supported.return_value = False | ||
218 | 2080 | self.m_which.return_value = False | ||
219 | 2081 | self.fstab = self.tmp_path('fstab') | ||
220 | 2082 | self.crypttab = os.path.join(os.path.dirname(self.fstab), 'crypttab') | ||
221 | 2083 | self.m_load_env.return_value = {'fstab': self.fstab, | ||
222 | 2084 | 'target': self.target} | ||
224 | 2085 | 2096 | ||
225 | 2086 | def test_dm_crypt_calls_cryptsetup(self): | 2097 | def test_dm_crypt_calls_cryptsetup(self): |
226 | 2087 | """ verify dm_crypt calls (format, open) w/ correct params""" | 2098 | """ verify dm_crypt calls (format, open) w/ correct params""" |
227 | @@ -2402,6 +2413,109 @@ class TestDmCryptHandler(CiTestCase): | |||
228 | 2402 | info, self.storage_config, empty_context) | 2413 | info, self.storage_config, empty_context) |
229 | 2403 | 2414 | ||
230 | 2404 | 2415 | ||
231 | 2416 | class TestCrypttab(DmCryptCommon): | ||
232 | 2417 | |||
233 | 2418 | def test_multi_dm_crypt(self): | ||
234 | 2419 | """ verify that multiple dm_crypt calls result in the data for both | ||
235 | 2420 | being present in crypttab""" | ||
236 | 2421 | |||
237 | 2422 | self.setUpStorageConfig({ | ||
238 | 2423 | 'storage': { | ||
239 | 2424 | 'version': 1, | ||
240 | 2425 | 'config': [ | ||
241 | 2426 | {'grub_device': True, | ||
242 | 2427 | 'id': 'sda', | ||
243 | 2428 | 'name': 'sda', | ||
244 | 2429 | 'path': '/wark/xxx', | ||
245 | 2430 | 'ptable': 'msdos', | ||
246 | 2431 | 'type': 'disk', | ||
247 | 2432 | 'wipe': 'superblock'}, | ||
248 | 2433 | {'device': 'sda', | ||
249 | 2434 | 'id': 'sda-part1', | ||
250 | 2435 | 'name': 'sda-part1', | ||
251 | 2436 | 'number': 1, | ||
252 | 2437 | 'size': '511705088B', | ||
253 | 2438 | 'type': 'partition'}, | ||
254 | 2439 | {'id': 'dmcrypt0', | ||
255 | 2440 | 'type': 'dm_crypt', | ||
256 | 2441 | 'dm_name': 'cryptroot', | ||
257 | 2442 | 'volume': 'sda-part1', | ||
258 | 2443 | 'cipher': self.cipher, | ||
259 | 2444 | 'keysize': self.keysize, | ||
260 | 2445 | 'keyfile': self.keyfile}, | ||
261 | 2446 | {'device': 'sda', | ||
262 | 2447 | 'id': 'sda-part2', | ||
263 | 2448 | 'name': 'sda-part2', | ||
264 | 2449 | 'number': 2, | ||
265 | 2450 | 'size': '511705088B', | ||
266 | 2451 | 'type': 'partition'}, | ||
267 | 2452 | {'id': 'dmcrypt1', | ||
268 | 2453 | 'type': 'dm_crypt', | ||
269 | 2454 | 'dm_name': 'cryptfoo', | ||
270 | 2455 | 'volume': 'sda-part2', | ||
271 | 2456 | 'cipher': self.cipher, | ||
272 | 2457 | 'keysize': self.keysize, | ||
273 | 2458 | 'keyfile': self.keyfile}, | ||
274 | 2459 | ], | ||
275 | 2460 | } | ||
276 | 2461 | }) | ||
277 | 2462 | |||
278 | 2463 | for i in range(2): | ||
279 | 2464 | self.m_getpath.return_value = self.random_string() | ||
280 | 2465 | info = self.storage_config['dmcrypt' + str(i)] | ||
281 | 2466 | block_meta.dm_crypt_handler( | ||
282 | 2467 | info, self.storage_config, empty_context | ||
283 | 2468 | ) | ||
284 | 2469 | |||
285 | 2470 | data = util.load_file(self.crypttab) | ||
286 | 2471 | self.assertEqual( | ||
287 | 2472 | f"cryptroot UUID={self.block_uuids[0]} none luks\n" | ||
288 | 2473 | f"cryptfoo UUID={self.block_uuids[1]} none luks\n", | ||
289 | 2474 | data | ||
290 | 2475 | ) | ||
291 | 2476 | |||
292 | 2477 | def test_cryptoswap(self): | ||
293 | 2478 | """ Check the keyfile and options features needed for cryptoswap """ | ||
294 | 2479 | |||
295 | 2480 | self.setUpStorageConfig({ | ||
296 | 2481 | 'storage': { | ||
297 | 2482 | 'version': 1, | ||
298 | 2483 | 'config': [ | ||
299 | 2484 | {'grub_device': True, | ||
300 | 2485 | 'id': 'sda', | ||
301 | 2486 | 'name': 'sda', | ||
302 | 2487 | 'path': '/wark/xxx', | ||
303 | 2488 | 'ptable': 'msdos', | ||
304 | 2489 | 'type': 'disk', | ||
305 | 2490 | 'wipe': 'superblock'}, | ||
306 | 2491 | {'device': 'sda', | ||
307 | 2492 | 'id': 'sda-part1', | ||
308 | 2493 | 'name': 'sda-part1', | ||
309 | 2494 | 'number': 1, | ||
310 | 2495 | 'size': '511705088B', | ||
311 | 2496 | 'type': 'partition'}, | ||
312 | 2497 | {'id': 'dmcrypt0', | ||
313 | 2498 | 'type': 'dm_crypt', | ||
314 | 2499 | 'dm_name': 'cryptswap', | ||
315 | 2500 | 'volume': 'sda-part1', | ||
316 | 2501 | 'options': ["swap", "initramfs"], | ||
317 | 2502 | 'keyfile': "/dev/urandom"}, | ||
318 | 2503 | ], | ||
319 | 2504 | } | ||
320 | 2505 | }) | ||
321 | 2506 | |||
322 | 2507 | self.m_getpath.return_value = self.random_string() | ||
323 | 2508 | block_meta.dm_crypt_handler( | ||
324 | 2509 | self.storage_config['dmcrypt0'], self.storage_config, empty_context | ||
325 | 2510 | ) | ||
326 | 2511 | |||
327 | 2512 | uuid = self.block_uuids[0] | ||
328 | 2513 | self.assertEqual( | ||
329 | 2514 | f"cryptswap UUID={uuid} /dev/urandom swap,initramfs\n", | ||
330 | 2515 | util.load_file(self.crypttab), | ||
331 | 2516 | ) | ||
332 | 2517 | |||
333 | 2518 | |||
334 | 2405 | class TestRaidHandler(CiTestCase): | 2519 | class TestRaidHandler(CiTestCase): |
335 | 2406 | 2520 | ||
336 | 2407 | def setUp(self): | 2521 | def setUp(self): |
337 | diff --git a/tools/vmtest-system-setup b/tools/vmtest-system-setup | |||
338 | index 5172741..2f82464 100755 | |||
339 | --- a/tools/vmtest-system-setup | |||
340 | +++ b/tools/vmtest-system-setup | |||
341 | @@ -14,6 +14,7 @@ esac | |||
342 | 14 | DEPS=( | 14 | DEPS=( |
343 | 15 | build-essential | 15 | build-essential |
344 | 16 | cloud-image-utils | 16 | cloud-image-utils |
345 | 17 | cryptsetup | ||
346 | 17 | git | 18 | git |
347 | 18 | make | 19 | make |
348 | 19 | net-tools | 20 | net-tools |
PASSED: Continuous integration, rev:6afaafefaf4 12a61bda2eb125d 354d0b6daa6aab /jenkins. canonical. com/server- team/job/ curtin- ci/216/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-amd64/ 216/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-arm64/ 216/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-ppc64el/ 216/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-s390x/ 216/
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/server- team/job/ curtin- ci/216/ /rebuild
https:/