Merge lp:~wesley-wiedenmeier/curtin/custom-partitioning-layout into lp:~curtin-dev/curtin/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
Reviewer Review Type Date Requested Status
curtin developers Pending
Review via email: mp+267867@code.launchpad.net

Description of the change

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:

Subscribers

People subscribed via source and target branches