Merge lp:~wesley-wiedenmeier/curtin/custom-partitioning-layout into lp:~curtin-dev/curtin/trunk
- custom-partitioning-layout
- Merge into trunk
Proposed by
Wesley Wiedenmeier
Status: | Merged |
---|---|
Merged at revision: | 246 |
Proposed branch: | lp:~wesley-wiedenmeier/curtin/custom-partitioning-layout |
Merge into: | lp:~curtin-dev/curtin/trunk |
Diff against target: |
410 lines (+248/-2) 8 files modified
curtin/commands/block_meta.py (+61/-0) curtin/commands/curthooks.py (+15/-0) examples/tests/basic.yaml (+1/-0) examples/tests/lvm.yaml (+70/-0) examples/tests/mdadm_bcache.yaml (+2/-0) tests/vmtests/test_basic.py (+9/-2) tests/vmtests/test_lvm.py (+80/-0) tests/vmtests/test_mdadm_bcache.py (+10/-0) |
To merge this branch: | bzr merge lp:~wesley-wiedenmeier/curtin/custom-partitioning-layout |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
curtin developers | Pending | ||
Review via email: mp+267867@code.launchpad.net |
Commit message
Description of the change
Added support for dname rules https:/
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'curtin/commands/block_meta.py' |
2 | --- curtin/commands/block_meta.py 2015-08-10 18:27:09 +0000 |
3 | +++ curtin/commands/block_meta.py 2015-08-12 19:16:20 +0000 |
4 | @@ -21,6 +21,7 @@ |
5 | from curtin.log import LOG |
6 | |
7 | from . import populate_one_subcmd |
8 | +from curtin.commands.net_meta import compose_udev_equality |
9 | |
10 | import glob |
11 | import os |
12 | @@ -268,6 +269,50 @@ |
13 | return partnumber |
14 | |
15 | |
16 | +def make_dname(volume, storage_config): |
17 | + state = util.load_command_environment() |
18 | + rules_dir = os.path.join(state['scratch'], "rules.d") |
19 | + vol = storage_config.get(volume) |
20 | + path = get_path_to_storage_volume(volume, storage_config) |
21 | + dname = vol.get('name') |
22 | + if vol.get('type') in ["partition", "disk"]: |
23 | + (out, _err) = util.subp(["blkid", "-o", "export", path], capture=True) |
24 | + for line in out.splitlines(): |
25 | + if "PTUUID" in line or "PARTUUID" in line: |
26 | + ptuuid = line.split('=')[-1] |
27 | + break |
28 | + rule = [ |
29 | + compose_udev_equality("SUBSYSTEM", "block"), |
30 | + compose_udev_equality("ACTION", "add|change"), |
31 | + ] |
32 | + if vol.get('type') == "disk": |
33 | + rule.append(compose_udev_equality('ENV{DEVTYPE}', "disk")) |
34 | + rule.append(compose_udev_equality('ENV{ID_PART_TABLE_UUID}', ptuuid)) |
35 | + elif vol.get('type') == "partition": |
36 | + rule.append(compose_udev_equality('ENV{DEVTYPE}', "partition")) |
37 | + dname = storage_config.get(vol.get('device')).get('name') + \ |
38 | + "-part%s" % determine_partition_number(volume, storage_config) |
39 | + rule.append(compose_udev_equality('ENV{ID_PART_ENTRY_UUID}', ptuuid)) |
40 | + elif vol.get('type') == "raid": |
41 | + (out, _err) = util.subp(["mdadm", "--detail", "--export", path], |
42 | + capture=True) |
43 | + for line in out.splitlines(): |
44 | + if "MD_UUID" in line: |
45 | + md_uuid = line.split('=')[-1] |
46 | + break |
47 | + rule.append(compose_udev_equality("ENV{MD_UUID}", md_uuid)) |
48 | + elif vol.get('type') == "bcache": |
49 | + rule.append(compose_udev_equality("ENV{DEVNAME}", path)) |
50 | + elif vol.get('type') == "lvm_partition": |
51 | + volgroup_name = storage_config.get(vol.get('volgroup')).get('name') |
52 | + dname = "%s-%s" % (volgroup_name, dname) |
53 | + rule.append(compose_udev_equality("ENV{DM_NAME}", dname)) |
54 | + rule.append("SYMLINK+=\"disk/by-dname/%s\"" % dname) |
55 | + util.ensure_dir(rules_dir) |
56 | + with open(os.path.join(rules_dir, volume), "w") as fp: |
57 | + fp.write(', '.join(rule)) |
58 | + |
59 | + |
60 | def get_path_to_storage_volume(volume, storage_config): |
61 | # Get path to block device for volume. Volume param should refer to id of |
62 | # volume in storage config |
63 | @@ -404,6 +449,10 @@ |
64 | elif ptable == "msdos": |
65 | util.subp(["parted", disk, "--script", "mklabel", "msdos"]) |
66 | |
67 | + # Make the name if needed |
68 | + if info.get('name'): |
69 | + make_dname(info.get('id'), storage_config) |
70 | + |
71 | |
72 | def partition_handler(info, storage_config): |
73 | device = info.get('device') |
74 | @@ -494,6 +543,9 @@ |
75 | wipe_volume( |
76 | get_path_to_storage_volume(info.get('id'), storage_config), |
77 | info.get('wipe')) |
78 | + # Make the name if needed |
79 | + if storage_config.get(device).get('name'): |
80 | + make_dname(info.get('id'), storage_config) |
81 | |
82 | |
83 | def format_handler(info, storage_config): |
84 | @@ -687,6 +739,8 @@ |
85 | raise ValueError("Partition tables on top of lvm logical volumes is \ |
86 | not supported") |
87 | |
88 | + make_dname(info.get('id'), storage_config) |
89 | + |
90 | |
91 | def dm_crypt_handler(info, storage_config): |
92 | state = util.load_command_environment() |
93 | @@ -778,6 +832,9 @@ |
94 | # Create the raid device |
95 | util.subp(" ".join(cmd), shell=True) |
96 | |
97 | + # Make dname rule for this dev |
98 | + make_dname(info.get('id'), storage_config) |
99 | + |
100 | # A mdadm.conf will be created in the same directory as the fstab in the |
101 | # configuration. This will then be copied onto the installed system later. |
102 | # The file must also be written onto the running system to enable it to run |
103 | @@ -831,6 +888,10 @@ |
104 | fp.write(path) |
105 | fp.close() |
106 | |
107 | + if info.get('name'): |
108 | + # Make dname rule for this dev |
109 | + make_dname(info.get('id'), storage_config) |
110 | + |
111 | if info.get('ptable'): |
112 | raise ValueError("Partition tables on top of lvm logical volumes is \ |
113 | not supported") |
114 | |
115 | === modified file 'curtin/commands/curthooks.py' |
116 | --- curtin/commands/curthooks.py 2015-08-06 23:20:36 +0000 |
117 | +++ curtin/commands/curthooks.py 2015-08-12 19:16:20 +0000 |
118 | @@ -415,6 +415,16 @@ |
119 | shutil.copy(interfaces, eni) |
120 | |
121 | |
122 | +def copy_dname_rules(rules_d, target): |
123 | + if not rules_d: |
124 | + LOG.warn("no udev rules directory to copy") |
125 | + return |
126 | + for rule in os.listdir(rules_d): |
127 | + target_file = os.path.join( |
128 | + target, "etc/udev/rules.d", "%s.rules" % rule) |
129 | + shutil.copy(os.path.join(rules_d, rule), target_file) |
130 | + |
131 | + |
132 | def restore_dist_interfaces(cfg, target): |
133 | # cloud images have a link of /etc/network/interfaces into /run |
134 | eni = os.path.sep.join([target, 'etc/network/interfaces']) |
135 | @@ -611,6 +621,11 @@ |
136 | if os.path.exists(mdadm_location): |
137 | copy_mdadm_conf(mdadm_location, target) |
138 | |
139 | + # If udev dname rules were created, copy them to target |
140 | + udev_rules_d = os.path.join(state['scratch'], "rules.d") |
141 | + if os.path.isdir(udev_rules_d): |
142 | + copy_dname_rules(udev_rules_d, target) |
143 | + |
144 | # As a rule, ARMv7 systems don't use grub. This may change some |
145 | # day, but for now, assume no. They do require the initramfs |
146 | # to be updated, and this also triggers boot loader setup via |
147 | |
148 | === modified file 'examples/tests/basic.yaml' |
149 | --- examples/tests/basic.yaml 2015-08-06 23:20:36 +0000 |
150 | +++ examples/tests/basic.yaml 2015-08-12 19:16:20 +0000 |
151 | @@ -6,6 +6,7 @@ |
152 | ptable: msdos |
153 | model: QEMU HARDDISK |
154 | path: /dev/vdb |
155 | + name: main_disk |
156 | - id: sda1 |
157 | type: partition |
158 | number: 1 |
159 | |
160 | === added file 'examples/tests/lvm.yaml' |
161 | --- examples/tests/lvm.yaml 1970-01-01 00:00:00 +0000 |
162 | +++ examples/tests/lvm.yaml 2015-08-12 19:16:20 +0000 |
163 | @@ -0,0 +1,70 @@ |
164 | +storage: |
165 | + version: 1 |
166 | + config: |
167 | + - id: sda |
168 | + type: disk |
169 | + ptable: msdos |
170 | + model: QEMU HARDDISK |
171 | + path: /dev/vdb |
172 | + name: main_disk |
173 | + - id: sda1 |
174 | + type: partition |
175 | + size: 3GB |
176 | + device: sda |
177 | + flag: boot |
178 | + - id: sda_extended |
179 | + type: partition |
180 | + size: 5G |
181 | + flag: extended |
182 | + device: sda |
183 | + - id: sda2 |
184 | + type: partition |
185 | + size: 2G |
186 | + flag: logical |
187 | + device: sda |
188 | + - id: sda3 |
189 | + type: partition |
190 | + size: 2G |
191 | + flag: logical |
192 | + device: sda |
193 | + - id: volgroup1 |
194 | + name: vg1 |
195 | + type: lvm_volgroup |
196 | + devices: |
197 | + - sda2 |
198 | + - sda3 |
199 | + - id: lvmpart1 |
200 | + name: lv1 |
201 | + size: 1G |
202 | + type: lvm_partition |
203 | + volgroup: volgroup1 |
204 | + - id: lvmpart2 |
205 | + name: lv2 |
206 | + type: lvm_partition |
207 | + volgroup: volgroup1 |
208 | + - id: sda1_root |
209 | + type: format |
210 | + fstype: ext4 |
211 | + volume: sda1 |
212 | + - id: lv1_fs |
213 | + name: storage |
214 | + type: format |
215 | + fstype: fat32 |
216 | + volume: lvmpart1 |
217 | + - id: lv2_fs |
218 | + name: storage |
219 | + type: format |
220 | + fstype: ext3 |
221 | + volume: lvmpart2 |
222 | + - id: sda1_mount |
223 | + type: mount |
224 | + path: / |
225 | + device: sda1_root |
226 | + - id: lv1_mount |
227 | + type: mount |
228 | + path: /srv/data |
229 | + device: lv1_fs |
230 | + - id: lv2_mount |
231 | + type: mount |
232 | + path: /srv/backup |
233 | + device: lv2_fs |
234 | |
235 | === modified file 'examples/tests/mdadm_bcache.yaml' |
236 | --- examples/tests/mdadm_bcache.yaml 2015-08-10 16:54:19 +0000 |
237 | +++ examples/tests/mdadm_bcache.yaml 2015-08-12 19:16:20 +0000 |
238 | @@ -6,6 +6,7 @@ |
239 | ptable: gpt |
240 | model: QEMU HARDDISK |
241 | path: /dev/vdb |
242 | + name: main_disk |
243 | - id: bios_boot_partition |
244 | type: partition |
245 | size: 1MB |
246 | @@ -42,6 +43,7 @@ |
247 | - sda4 |
248 | - id: bcache0 |
249 | type: bcache |
250 | + name: cached_array |
251 | backing_device: mddevice |
252 | cache_device: sda5 |
253 | - id: sda1_root |
254 | |
255 | === modified file 'tests/vmtests/test_basic.py' |
256 | --- tests/vmtests/test_basic.py 2015-08-06 16:27:22 +0000 |
257 | +++ tests/vmtests/test_basic.py 2015-08-12 19:16:20 +0000 |
258 | @@ -7,10 +7,10 @@ |
259 | |
260 | class TestBasicAbs(VMBaseClass): |
261 | __test__ = False |
262 | + interactive = False |
263 | conf_file = "examples/tests/basic.yaml" |
264 | install_timeout = 600 |
265 | boot_timeout = 120 |
266 | - interactive = False |
267 | user_data = textwrap.dedent("""\ |
268 | #cloud-config |
269 | password: passw0rd |
270 | @@ -23,6 +23,7 @@ |
271 | - blkid -o export /dev/vda1 > /media/output/blkid_output_vda1 |
272 | - blkid -o export /dev/vda2 > /media/output/blkid_output_vda2 |
273 | - cat /etc/fstab > /media/output/fstab |
274 | + - ls /dev/disk/by-dname/ > /media/output/ls_dname |
275 | power_state: |
276 | mode: poweroff |
277 | """) |
278 | @@ -30,12 +31,18 @@ |
279 | def test_output_files_exist(self): |
280 | self.output_files_exist( |
281 | ["blkid_output_vda", "blkid_output_vda1", "blkid_output_vda2", |
282 | - "fstab"]) |
283 | + "fstab", "ls_dname"]) |
284 | |
285 | def test_ptable(self): |
286 | blkid_info = self.get_blkid_data("blkid_output_vda") |
287 | self.assertEquals(blkid_info["PTTYPE"], "dos") |
288 | |
289 | + def test_dname(self): |
290 | + with open(os.path.join(self.td.mnt, "ls_dname"), "r") as fp: |
291 | + contents = fp.read().splitlines() |
292 | + for link in ["main_disk", "main_disk-part1", "main_disk-part2"]: |
293 | + self.assertIn(link, contents) |
294 | + |
295 | def test_partitions(self): |
296 | with open(os.path.join(self.td.mnt, "fstab")) as fp: |
297 | fstab_lines = fp.readlines() |
298 | |
299 | === added file 'tests/vmtests/test_lvm.py' |
300 | --- tests/vmtests/test_lvm.py 1970-01-01 00:00:00 +0000 |
301 | +++ tests/vmtests/test_lvm.py 2015-08-12 19:16:20 +0000 |
302 | @@ -0,0 +1,80 @@ |
303 | +from . import VMBaseClass |
304 | +from unittest import TestCase |
305 | + |
306 | +import textwrap |
307 | +import os |
308 | + |
309 | + |
310 | +class TestMdadmBcacheAbs(VMBaseClass): |
311 | + __test__ = False |
312 | + conf_file = "examples/tests/lvm.yaml" |
313 | + install_timeout = 600 |
314 | + boot_timeout = 100 |
315 | + interactive = False |
316 | + user_data = textwrap.dedent("""\ |
317 | + #cloud-config |
318 | + password: passw0rd |
319 | + chpasswd: { expire: False } |
320 | + bootcmd: |
321 | + - mkdir /media/output |
322 | + - mount /dev/vdb /media/output |
323 | + runcmd: |
324 | + - cat /etc/fstab > /media/output/fstab |
325 | + - ls /dev/disk/by-dname > /media/output/ls_dname |
326 | + - pvdisplay -C --separator = -o vg_name,pv_name --noheadings > \ |
327 | + /media/output/pvs |
328 | + - lvdisplay -C --separator = -o lv_name,vg_name --noheadings > \ |
329 | + /media/output/lvs |
330 | + power_state: |
331 | + mode: poweroff |
332 | + """) |
333 | + |
334 | + def test_fstab(self): |
335 | + with open(os.path.join(self.td.mnt, "fstab")) as fp: |
336 | + fstab_lines = fp.readlines() |
337 | + fstab_entry = None |
338 | + for line in fstab_lines: |
339 | + if "/dev/vg1/lv1" in line: |
340 | + fstab_entry = line |
341 | + break |
342 | + self.assertIsNotNone(fstab_entry) |
343 | + self.assertEqual(fstab_entry.split(' ')[1], "/srv/data") |
344 | + |
345 | + def test_lvs(self): |
346 | + with open(os.path.join(self.td.mnt, "lvs"), "r") as fp: |
347 | + lv_data = list(i.strip() for i in fp.readlines()) |
348 | + self.assertIn("lv1=vg1", lv_data) |
349 | + self.assertIn("lv2=vg1", lv_data) |
350 | + |
351 | + def test_pvs(self): |
352 | + with open(os.path.join(self.td.mnt, "pvs"), "r") as fp: |
353 | + lv_data = list(i.strip() for i in fp.readlines()) |
354 | + self.assertIn("vg1=/dev/vda5", lv_data) |
355 | + self.assertIn("vg1=/dev/vda6", lv_data) |
356 | + |
357 | + def test_output_files_exist(self): |
358 | + self.output_files_exist( |
359 | + ["fstab", "ls_dname"]) |
360 | + |
361 | + def test_dname(self): |
362 | + with open(os.path.join(self.td.mnt, "ls_dname"), "r") as fp: |
363 | + contents = fp.read().splitlines() |
364 | + for link in list(("main_disk-part%s" % i for i in (1, 2, 5, 6))): |
365 | + self.assertIn(link, contents) |
366 | + self.assertIn("main_disk", contents) |
367 | + self.assertIn("vg1-lv1", contents) |
368 | + self.assertIn("vg1-lv2", contents) |
369 | + |
370 | + |
371 | +class WilyTestLvm(TestMdadmBcacheAbs, TestCase): |
372 | + __test__ = True |
373 | + repo = "maas-daily" |
374 | + release = "wily" |
375 | + arch = "amd64" |
376 | + |
377 | + |
378 | +class VividTestLvm(TestMdadmBcacheAbs, TestCase): |
379 | + __test__ = True |
380 | + repo = "maas-daily" |
381 | + release = "vivid" |
382 | + arch = "amd64" |
383 | |
384 | === modified file 'tests/vmtests/test_mdadm_bcache.py' |
385 | --- tests/vmtests/test_mdadm_bcache.py 2015-08-06 16:27:22 +0000 |
386 | +++ tests/vmtests/test_mdadm_bcache.py 2015-08-12 19:16:20 +0000 |
387 | @@ -23,6 +23,7 @@ |
388 | - mdadm --detail --scan > /media/output/mdadm_status |
389 | - bcache-super-show /dev/vda6 > /media/output/bcache_super_vda6 |
390 | - ls /sys/fs/bcache > /media/output/bcache_ls |
391 | + - ls /dev/disk/by-dname > /media/output/ls_dname |
392 | power_state: |
393 | mode: poweroff |
394 | """) |
395 | @@ -47,6 +48,15 @@ |
396 | self.output_files_exist( |
397 | ["fstab", "mdadm_status", "bcache_super_vda6", "bcache_ls"]) |
398 | |
399 | + def test_dname(self): |
400 | + with open(os.path.join(self.td.mnt, "ls_dname"), "r") as fp: |
401 | + contents = fp.read().splitlines() |
402 | + for link in list(("main_disk-part%s" % i for i in range(1, 6))): |
403 | + self.assertIn(link, contents) |
404 | + self.assertIn("md0", contents) |
405 | + self.assertIn("cached_array", contents) |
406 | + self.assertIn("main_disk", contents) |
407 | + |
408 | def test_bcache_status(self): |
409 | bcache_cset_uuid = None |
410 | with open(os.path.join(self.td.mnt, "bcache_super_vda6"), "r") as fp: |