Merge lp:~blake-rouse/maas/fix-1509536-part1 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4421
Proposed branch: lp:~blake-rouse/maas/fix-1509536-part1
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 1260 lines (+428/-119)
21 files modified
src/maasserver/api/tests/test_blockdevice.py (+7/-7)
src/maasserver/api/tests/test_node.py (+3/-2)
src/maasserver/api/tests/test_nodes.py (+2/-1)
src/maasserver/forms.py (+81/-35)
src/maasserver/models/blockdevice.py (+22/-0)
src/maasserver/models/filesystem.py (+12/-0)
src/maasserver/models/tests/test_blockdevice.py (+22/-1)
src/maasserver/models/tests/test_filesystem.py (+19/-0)
src/maasserver/models/tests/test_node.py (+7/-7)
src/maasserver/models/tests/test_partitiontable.py (+5/-5)
src/maasserver/models/tests/test_physicalblockdevice.py (+4/-4)
src/maasserver/testing/factory.py (+9/-4)
src/maasserver/tests/test_forms_bcache.py (+61/-14)
src/maasserver/tests/test_forms_cacheset.py (+29/-3)
src/maasserver/tests/test_forms_raid.py (+74/-1)
src/maasserver/tests/test_forms_volume_group.py (+30/-0)
src/maasserver/tests/test_node_constraint_filter_forms.py (+25/-25)
src/maasserver/tests/test_preseed_storage.py (+8/-4)
src/maasserver/tests/test_storage_layouts.py (+4/-3)
src/maasserver/websockets/tests/test_listener.py (+2/-1)
src/metadataserver/models/tests/test_commissioningscript.py (+2/-2)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1509536-part1
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+275920@code.launchpad.net

Commit message

Prevent a filesystem to be placed directly on the boot disk. The boot disk requires that a partition be used before a filesystem can be created. When creating a bcache, cache set, volume group, or RAID and the boot_disk is involved auto-create the partition and then add the partition to the operation.

Description of the change

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Looks good. Just one thing I'd fix about your utility function. My pet peeve is putting more code in forms.py. ;-)

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Thanks for the review.

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1000.3 KiB)

The attempt to merge lp:~blake-rouse/maas/fix-1509536-part1 into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com trusty-security InRelease [64.4 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://nova.clouds.archive.ubuntu.com trusty-updates InRelease [64.4 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:3 http://security.ubuntu.com trusty-security/main Sources [97.7 kB]
Get:4 http://security.ubuntu.com trusty-security/universe Sources [31.0 kB]
Get:5 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [241 kB]
Get:6 http://security.ubuntu.com trusty-security/main amd64 Packages [356 kB]
Get:7 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [140 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [117 kB]
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [636 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [324 kB]
Get:11 http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en [309 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en [171 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 2,551 kB in 4s (600 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm pep8 phantomjs postgresql pyflakes python-apt python-bson python-bzrlib python-convoy python-coverage python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lxml python-mock python-netaddr python-netifaces python-nose python-oauth python-openssl python-paramiko python-pexpect python-pip python-pocket-lint python-psycopg2 python-pyinotify python-pyparsing python-seamicroclient python-simplejson python-simplestreams python-sphinx python-subunit python-tempita python-testresources ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/tests/test_blockdevice.py'
2--- src/maasserver/api/tests/test_blockdevice.py 2015-10-21 22:52:59 +0000
3+++ src/maasserver/api/tests/test_blockdevice.py 2015-10-28 01:59:59 +0000
4@@ -55,7 +55,7 @@
5 class TestBlockDevices(APITestCase):
6
7 def test_read(self):
8- node = factory.make_Node()
9+ node = factory.make_Node(with_boot_disk=False)
10
11 # Add three physical block devices
12 physical_block_devices = [
13@@ -104,7 +104,7 @@
14 self.assertItemsEqual(expected_device_ids, result_device_ids)
15
16 def test_read_returns_model(self):
17- node = factory.make_Node()
18+ node = factory.make_Node(with_boot_disk=False)
19 block_device = factory.make_PhysicalBlockDevice(node=node)
20 uri = get_blockdevices_uri(node)
21 response = self.client.get(uri)
22@@ -128,10 +128,10 @@
23 "fstype": filesystem.fstype,
24 "uuid": filesystem.uuid,
25 "mount_point": filesystem.mount_point,
26- }, parsed_devices[0]['filesystem'])
27+ }, parsed_devices[1]['filesystem'])
28
29 def test_read_returns_partition_type(self):
30- node = factory.make_Node()
31+ node = factory.make_Node(with_boot_disk=False)
32 block_device = factory.make_PhysicalBlockDevice(node=node)
33 partition_table = factory.make_PartitionTable(
34 block_device=block_device)
35@@ -146,7 +146,7 @@
36 partition_table.table_type)
37
38 def test_read_returns_partitions(self):
39- node = factory.make_Node()
40+ node = factory.make_Node(with_boot_disk=False)
41 block_size = 1024
42 block_device = factory.make_PhysicalBlockDevice(
43 node=node,
44@@ -176,7 +176,7 @@
45 [p['size'] for p in parsed_device['partitions']])
46
47 def test_read_returns_filesystems_on_partitions(self):
48- node = factory.make_Node()
49+ node = factory.make_Node(with_boot_disk=False)
50 block_size = 1024
51 block_device = factory.make_PhysicalBlockDevice(
52 node=node,
53@@ -224,7 +224,7 @@
54 """Checks it's possible to add a physical block device using the POST
55 method"""
56 self.become_admin()
57- node = factory.make_Node()
58+ node = factory.make_Node(with_boot_disk=False)
59 uri = get_blockdevices_uri(node)
60 response = self.client.post(uri, {
61 'name': 'sda',
62
63=== modified file 'src/maasserver/api/tests/test_node.py'
64--- src/maasserver/api/tests/test_node.py 2015-10-23 18:55:36 +0000
65+++ src/maasserver/api/tests/test_node.py 2015-10-28 01:59:59 +0000
66@@ -286,7 +286,7 @@
67 self.assertEqual(None, parsed_result["owner"])
68
69 def test_GET_returns_physical_block_devices(self):
70- node = factory.make_Node()
71+ node = factory.make_Node(with_boot_disk=False)
72 devices = [
73 factory.make_PhysicalBlockDevice(node=node)
74 for _ in range(3)
75@@ -2083,7 +2083,8 @@
76
77 def test__400_when_no_boot_disk(self):
78 self.become_admin()
79- node = factory.make_Node(status=NODE_STATUS.READY)
80+ node = factory.make_Node(
81+ status=NODE_STATUS.READY, with_boot_disk=False)
82 response = self.client.post(
83 self.get_node_uri(node), {
84 'op': 'set_storage_layout',
85
86=== modified file 'src/maasserver/api/tests/test_nodes.py'
87--- src/maasserver/api/tests/test_nodes.py 2015-10-06 00:57:03 +0000
88+++ src/maasserver/api/tests/test_nodes.py 2015-10-28 01:59:59 +0000
89@@ -1137,7 +1137,8 @@
90
91 def test_POST_acquire_allocates_node_by_storage(self):
92 """Storage label is returned alongside node data"""
93- node = factory.make_Node(status=NODE_STATUS.READY)
94+ node = factory.make_Node(
95+ status=NODE_STATUS.READY, with_boot_disk=False)
96 factory.make_PhysicalBlockDevice(
97 node=node, size=11 * (1000 ** 3), tags=['ssd'])
98 response = self.client.post(reverse('nodes_handler'), {
99
100=== modified file 'src/maasserver/forms.py'
101--- src/maasserver/forms.py 2015-10-26 17:02:57 +0000
102+++ src/maasserver/forms.py 2015-10-28 01:59:59 +0000
103@@ -3492,6 +3492,17 @@
104 ]
105
106
107+def _move_boot_disk_to_partitions(block_devices, partitions):
108+ """Removes the boot disk from the block_devices, creates a partition
109+ on the boot disk and adds it to partitions."""
110+ for block_device in block_devices:
111+ partition = block_device.create_partition_if_boot_disk()
112+ if partition is not None:
113+ block_devices.remove(block_device)
114+ partitions.append(partition)
115+ return
116+
117+
118 class CreateCacheSetForm(Form):
119 """For validaing and saving a new Bcache Cache Set."""
120
121@@ -3526,8 +3537,14 @@
122 if self.cleaned_data['cache_device']:
123 cache_device = BlockDevice.objects.get(
124 id=self.cleaned_data['cache_device'])
125- return CacheSet.objects.get_or_create_cache_set_for_block_device(
126- cache_device)
127+ partition = cache_device.create_partition_if_boot_disk()
128+ if partition is not None:
129+ return CacheSet.objects.get_or_create_cache_set_for_partition(
130+ partition)
131+ else:
132+ return (
133+ CacheSet.objects.get_or_create_cache_set_for_block_device(
134+ cache_device))
135 elif self.cleaned_data['cache_partition']:
136 cache_partition = Partition.objects.get(
137 id=self.cleaned_data['cache_partition'])
138@@ -3537,7 +3554,7 @@
139 def _set_up_field_choices(self):
140 """Sets up choices for `cache_device` and `cache_partition` fields."""
141 # Select the unused, non-partitioned block devices of this node.
142- free_block_devices = list(
143+ free_block_devices = (
144 BlockDevice.objects.get_free_block_devices_for_node(self.node))
145 block_device_choices = [
146 (bd.id, bd.name)
147@@ -3594,8 +3611,13 @@
148 if self.cleaned_data['cache_device']:
149 filesystem = self.cache_set.get_filesystem()
150 filesystem.partition = None
151- filesystem.block_device = BlockDevice.objects.get(
152+ block_device = BlockDevice.objects.get(
153 id=self.cleaned_data['cache_device'])
154+ partition = block_device.create_partition_if_boot_disk()
155+ if partition is not None:
156+ filesystem.partition = partition
157+ else:
158+ filesystem.block_device = block_device
159 filesystem.save()
160 elif self.cleaned_data['cache_partition']:
161 filesystem = self.cache_set.get_filesystem()
162@@ -3680,6 +3702,10 @@
163 if self.cleaned_data['backing_device']:
164 backing_device = BlockDevice.objects.get(
165 id=self.cleaned_data['backing_device'])
166+ partition = backing_device.create_partition_if_boot_disk()
167+ if partition is not None:
168+ backing_partition = partition
169+ backing_device = None
170 elif self.cleaned_data['backing_partition']:
171 backing_partition = Partition.objects.get(
172 id=self.cleaned_data['backing_partition'])
173@@ -3695,7 +3721,7 @@
174 """Sets up choices for `cache_set`, `backing_device`,
175 and `backing_partition` fields."""
176 # Select the unused, non-partitioned block devices of this node.
177- free_block_devices = list(
178+ free_block_devices = (
179 BlockDevice.objects.get_free_block_devices_for_node(self.node))
180 block_device_choices = [
181 (bd.id, bd.name)
182@@ -3754,9 +3780,16 @@
183 # Remove previous cache
184 self.bcache.filesystems.filter(
185 fstype=FILESYSTEM_TYPE.BCACHE_BACKING).delete()
186- # Create a new one on this device.
187- self.bcache.filesystems.add(Filesystem.objects.create(
188- block_device=device, fstype=FILESYSTEM_TYPE.BCACHE_BACKING))
189+ # Create a new one on this device or on the partition on this
190+ # device if the device is the boot disk.
191+ partition = device.create_partition_if_boot_disk()
192+ if partition is not None:
193+ filesystem = Filesystem.objects.create(
194+ partition=partition, fstype=FILESYSTEM_TYPE.BCACHE_BACKING)
195+ else:
196+ filesystem = Filesystem.objects.create(
197+ block_device=device, fstype=FILESYSTEM_TYPE.BCACHE_BACKING)
198+ self.bcache.filesystems.add(filesystem)
199 elif self.cleaned_data['backing_partition']:
200 partition = Partition.objects.get(
201 id=int(self.cleaned_data['backing_partition']))
202@@ -3788,8 +3821,9 @@
203 # the ones currently used by bcache and exclude the virtual block
204 # device created by the cache.
205 free_block_devices = (
206- BlockDevice.objects.get_free_block_devices_for_node(
207- self.node).exclude(id=self.bcache.virtual_device.id))
208+ BlockDevice.objects.get_free_block_devices_for_node(self.node))
209+ free_block_devices = free_block_devices.exclude(
210+ id=self.bcache.virtual_device.id)
211 current_block_devices = self.bcache.filesystems.exclude(
212 block_device=None)
213 block_device_choices = [
214@@ -3858,8 +3892,7 @@
215 """
216 # Select the unused, non-partitioned block devices of this node.
217 free_block_devices = (
218- BlockDevice.objects.get_free_block_devices_for_node(
219- self.node))
220+ BlockDevice.objects.get_free_block_devices_for_node(self.node))
221 block_device_choices = [
222 (bd.id, bd.name)
223 for bd in free_block_devices
224@@ -3908,15 +3941,16 @@
225
226 This implementation of `save` does not support the `commit` argument.
227 """
228-
229- block_devices = BlockDevice.objects.filter(
230- id__in=self.cleaned_data['block_devices'])
231- partitions = Partition.objects.filter(
232- id__in=self.cleaned_data['partitions'])
233- spare_devices = BlockDevice.objects.filter(
234- id__in=self.cleaned_data['spare_devices'])
235- spare_partitions = Partition.objects.filter(
236- id__in=self.cleaned_data['spare_partitions'])
237+ block_devices = list(BlockDevice.objects.filter(
238+ id__in=self.cleaned_data['block_devices']))
239+ partitions = list(Partition.objects.filter(
240+ id__in=self.cleaned_data['partitions']))
241+ _move_boot_disk_to_partitions(block_devices, partitions)
242+ spare_devices = list(BlockDevice.objects.filter(
243+ id__in=self.cleaned_data['spare_devices']))
244+ spare_partitions = list(Partition.objects.filter(
245+ id__in=self.cleaned_data['spare_partitions']))
246+ _move_boot_disk_to_partitions(spare_devices, spare_partitions)
247
248 return RAID.objects.create_raid(
249 name=self.cleaned_data['name'],
250@@ -4077,15 +4111,23 @@
251
252 for device_id in self.cleaned_data['add_block_devices']:
253 if device_id not in current_block_device_ids:
254- self.raid.add_device(
255- BlockDevice.objects.get(id=device_id),
256- FILESYSTEM_TYPE.RAID)
257+ block_device = BlockDevice.objects.get(id=device_id)
258+ partition = block_device.create_partition_if_boot_disk()
259+ if partition is not None:
260+ self.raid.add_partition(partition, FILESYSTEM_TYPE.RAID)
261+ else:
262+ self.raid.add_device(block_device, FILESYSTEM_TYPE.RAID)
263
264 for device_id in self.cleaned_data['add_spare_devices']:
265 if device_id not in current_block_device_ids:
266- self.raid.add_device(
267- BlockDevice.objects.get(id=device_id),
268- FILESYSTEM_TYPE.RAID_SPARE)
269+ block_device = BlockDevice.objects.get(id=device_id)
270+ partition = block_device.create_partition_if_boot_disk()
271+ if partition is not None:
272+ self.raid.add_partition(
273+ partition, FILESYSTEM_TYPE.RAID_SPARE)
274+ else:
275+ self.raid.add_device(
276+ block_device, FILESYSTEM_TYPE.RAID_SPARE)
277
278 for partition_id in self.cleaned_data['add_partitions']:
279 if partition_id not in current_partition_ids:
280@@ -4134,8 +4176,7 @@
281 """
282 # Select the unused, non-partitioned block devices of this node.
283 free_block_devices = (
284- BlockDevice.objects.get_free_block_devices_for_node(
285- self.node))
286+ BlockDevice.objects.get_free_block_devices_for_node(self.node))
287 self.fields['block_devices'].choices = [
288 (bd.id, bd.name)
289 for bd in free_block_devices
290@@ -4179,13 +4220,16 @@
291
292 This implementation of `save` does not support the `commit` argument.
293 """
294- block_device_ids = self.cleaned_data['block_devices']
295- partition_ids = self.cleaned_data['partitions']
296+ block_devices = list(BlockDevice.objects.filter(
297+ id__in=self.cleaned_data['block_devices']))
298+ partitions = list(Partition.objects.filter(
299+ id__in=self.cleaned_data['partitions']))
300+ _move_boot_disk_to_partitions(block_devices, partitions)
301 return VolumeGroup.objects.create_volume_group(
302 name=self.cleaned_data['name'],
303 uuid=self.cleaned_data.get('uuid'),
304- block_devices=BlockDevice.objects.filter(id__in=block_device_ids),
305- partitions=Partition.objects.filter(id__in=partition_ids))
306+ block_devices=block_devices,
307+ partitions=partitions)
308
309
310 class UpdateVolumeGroupForm(Form):
311@@ -4221,8 +4265,7 @@
312 node = self.volume_group.get_node()
313 # Select the unused, non-partitioned block devices of this node.
314 free_block_devices = (
315- BlockDevice.objects.get_free_block_devices_for_node(
316- node))
317+ BlockDevice.objects.get_free_block_devices_for_node(node))
318 self.fields['add_block_devices'].choices = [
319 (bd.id, bd.name)
320 for bd in free_block_devices
321@@ -4301,6 +4344,9 @@
322 partitions = partitions + list(
323 Partition.objects.filter(id__in=add_partition_ids))
324
325+ # Move the boot disk to the partitions if it exists.
326+ _move_boot_disk_to_partitions(block_devices, partitions)
327+
328 # Update the block devices and partitions in the volume group.
329 self.volume_group.update_block_devices_and_partitions(
330 block_devices, partitions)
331
332=== modified file 'src/maasserver/models/blockdevice.py'
333--- src/maasserver/models/blockdevice.py 2015-10-20 18:44:39 +0000
334+++ src/maasserver/models/blockdevice.py 2015-10-28 01:59:59 +0000
335@@ -273,6 +273,28 @@
336 return partitiontable.get_available_size()
337 return self.size
338
339+ def is_boot_disk(self):
340+ """Return true if block device is the boot disk."""
341+ boot_disk = self.node.get_boot_disk()
342+ return boot_disk.id == self.id
343+
344+ def create_partition_if_boot_disk(self):
345+ """Creates a partition that uses the whole disk if this block device
346+ is the boot disk."""
347+ if self.is_boot_disk():
348+ # Cannot already have partition table.
349+ partition_table = self.get_partitiontable()
350+ if partition_table is not None:
351+ raise ValueError(
352+ "Cannot call create_partition_if_boot_disk when a "
353+ "partition table already exists on the block device.")
354+ # Circular imports.
355+ from maasserver.models.partitiontable import PartitionTable
356+ partition_table = PartitionTable.objects.create(block_device=self)
357+ return partition_table.add_partition()
358+ else:
359+ return None
360+
361 def delete(self):
362 """Delete the block device.
363
364
365=== modified file 'src/maasserver/models/filesystem.py'
366--- src/maasserver/models/filesystem.py 2015-09-24 16:22:12 +0000
367+++ src/maasserver/models/filesystem.py 2015-10-28 01:59:59 +0000
368@@ -175,6 +175,18 @@
369 raise ValidationError(
370 "BCACHE_CACHE must be inside of a cache_set.")
371
372+ # You cannot place a filesystem directly on the boot_disk. It requires
373+ # a partition to be used.
374+ if self.block_device is not None:
375+ node = self.block_device.node
376+ boot_disk = node.get_boot_disk()
377+ if boot_disk is not None and boot_disk.id == self.block_device.id:
378+ # This is the boot disk for the node.
379+ raise ValidationError(
380+ "Cannot place filesystem directly on the boot disk. "
381+ "Create a partition on the boot disk first and then "
382+ "format the partition.")
383+
384 def save(self, *args, **kwargs):
385 if not self.uuid:
386 self.uuid = uuid4()
387
388=== modified file 'src/maasserver/models/tests/test_blockdevice.py'
389--- src/maasserver/models/tests/test_blockdevice.py 2015-09-24 16:22:12 +0000
390+++ src/maasserver/models/tests/test_blockdevice.py 2015-10-28 01:59:59 +0000
391@@ -230,7 +230,7 @@
392 ValueError, BlockDevice.objects.filter_by_tags, object())
393
394 def test_get_free_block_devices_for_node(self):
395- node = factory.make_Node()
396+ node = factory.make_Node(with_boot_disk=False)
397 free_devices = [
398 factory.make_BlockDevice(node=node)
399 for _ in range(3)
400@@ -411,6 +411,27 @@
401 block_device.delete()
402 self.assertIsNone(reload_object(block_device))
403
404+ def test_create_partition_if_boot_disk_returns_None_if_not_boot_disk(self):
405+ node = factory.make_Node()
406+ not_boot_disk = factory.make_PhysicalBlockDevice(node=node)
407+ self.assertIsNone(not_boot_disk.create_partition_if_boot_disk())
408+
409+ def test_create_partition_if_boot_disk_raises_ValueError(self):
410+ node = factory.make_Node(with_boot_disk=False)
411+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
412+ factory.make_PartitionTable(block_device=boot_disk)
413+ with ExpectedException(ValueError):
414+ boot_disk.create_partition_if_boot_disk()
415+
416+ def test_create_partition_if_boot_disk_creates_partition(self):
417+ node = factory.make_Node(with_boot_disk=False)
418+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
419+ partition = boot_disk.create_partition_if_boot_disk()
420+ self.assertIsNotNone(partition)
421+ self.assertEquals(
422+ boot_disk.get_available_size(), 0,
423+ "Should create a partition for the entire disk.")
424+
425
426 class TestBlockDevicePostSaveCallsSave(MAASServerTestCase):
427 """Tests for the `BlockDevice` post_save signal to call save on group."""
428
429=== modified file 'src/maasserver/models/tests/test_filesystem.py'
430--- src/maasserver/models/tests/test_filesystem.py 2015-09-24 16:22:12 +0000
431+++ src/maasserver/models/tests/test_filesystem.py 2015-10-28 01:59:59 +0000
432@@ -126,3 +126,22 @@
433 partition = factory.make_Partition()
434 filesystem = factory.make_Filesystem(partition=partition)
435 self.assertEquals(partition, filesystem.get_parent())
436+
437+ def test_cannot_create_filesystem_directly_on_boot_disk(self):
438+ node = factory.make_Node(with_boot_disk=False)
439+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
440+ with ExpectedException(
441+ ValidationError,
442+ re.escape(
443+ "{'__all__': [u'Cannot place filesystem directly on the "
444+ "boot disk. Create a partition on the boot disk first "
445+ "and then format the partition.']}")):
446+ factory.make_Filesystem(block_device=boot_disk)
447+
448+ def test_can_create_filesystem_on_partition_on_boot_disk(self):
449+ node = factory.make_Node(with_boot_disk=False)
450+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
451+ partition_table = factory.make_PartitionTable(block_device=boot_disk)
452+ partition = factory.make_Partition(partition_table=partition_table)
453+ # Test is that an error is not raised.
454+ factory.make_Filesystem(partition=partition)
455
456=== modified file 'src/maasserver/models/tests/test_node.py'
457--- src/maasserver/models/tests/test_node.py 2015-10-23 17:53:22 +0000
458+++ src/maasserver/models/tests/test_node.py 2015-10-28 01:59:59 +0000
459@@ -191,30 +191,30 @@
460 self.assertEqual('2', node.display_memory())
461
462 def test_physicalblockdevice_set_returns_physicalblockdevices(self):
463- node = factory.make_Node()
464+ node = factory.make_Node(with_boot_disk=False)
465 device = factory.make_PhysicalBlockDevice(node=node)
466 factory.make_BlockDevice(node=node)
467 factory.make_PhysicalBlockDevice()
468 self.assertItemsEqual([device], node.physicalblockdevice_set.all())
469
470 def test_storage_returns_size_of_physicalblockdevices_in_mb(self):
471- node = factory.make_Node()
472+ node = factory.make_Node(with_boot_disk=False)
473 for _ in range(3):
474 factory.make_PhysicalBlockDevice(node=node, size=50 * (1000 ** 2))
475 self.assertEqual(50 * 3, node.storage)
476
477 def test_display_storage_returns_decimal_less_than_1000(self):
478- node = factory.make_Node()
479+ node = factory.make_Node(with_boot_disk=False)
480 factory.make_PhysicalBlockDevice(node=node, size=500 * (1000 ** 2))
481 self.assertEqual('0.5', node.display_storage())
482
483 def test_display_storage_returns_value_divided_by_1000(self):
484- node = factory.make_Node()
485+ node = factory.make_Node(with_boot_disk=False)
486 factory.make_PhysicalBlockDevice(node=node, size=2000 * (1000 ** 2))
487 self.assertEqual('2', node.display_storage())
488
489 def test_get_boot_disk_returns_set_boot_disk(self):
490- node = factory.make_Node()
491+ node = factory.make_Node(with_boot_disk=False)
492 # First disk.
493 factory.make_PhysicalBlockDevice(node=node)
494 boot_disk = factory.make_PhysicalBlockDevice(node=node)
495@@ -223,7 +223,7 @@
496 self.assertEquals(boot_disk, node.get_boot_disk())
497
498 def test_get_boot_disk_returns_first(self):
499- node = factory.make_Node()
500+ node = factory.make_Node(with_boot_disk=False)
501 boot_disk = factory.make_PhysicalBlockDevice(node=node)
502 # Second disk.
503 factory.make_PhysicalBlockDevice(node=node)
504@@ -231,7 +231,7 @@
505 self.assertEquals(boot_disk, node.get_boot_disk())
506
507 def test_get_boot_disk_returns_None(self):
508- node = factory.make_Node()
509+ node = factory.make_Node(with_boot_disk=False)
510 self.assertIsNone(node.get_boot_disk())
511
512 def test_get_bios_boot_method_returns_pxe(self):
513
514=== modified file 'src/maasserver/models/tests/test_partitiontable.py'
515--- src/maasserver/models/tests/test_partitiontable.py 2015-10-26 21:09:15 +0000
516+++ src/maasserver/models/tests/test_partitiontable.py 2015-10-28 01:59:59 +0000
517@@ -138,27 +138,27 @@
518 ignore_partitions=ignore_partitions))
519
520 def test_save_sets_table_type_to_mbr_for_boot_when_type_miss_match(self):
521- node = factory.make_Node(bios_boot_method="pxe")
522+ node = factory.make_Node(with_boot_disk=False, bios_boot_method="pxe")
523 boot_disk = factory.make_PhysicalBlockDevice(node=node)
524 partition_table = factory.make_PartitionTable(
525 block_device=BlockDevice.objects.get(id=boot_disk.id))
526 self.assertEquals(PARTITION_TABLE_TYPE.MBR, partition_table.table_type)
527
528 def test_save_sets_table_type_to_gpt_for_uefi_boot(self):
529- node = factory.make_Node(bios_boot_method="uefi")
530+ node = factory.make_Node(with_boot_disk=False, bios_boot_method="uefi")
531 boot_disk = factory.make_PhysicalBlockDevice(node=node)
532 partition_table = factory.make_PartitionTable(block_device=boot_disk)
533 self.assertEquals(PARTITION_TABLE_TYPE.GPT, partition_table.table_type)
534
535 def test_save_sets_table_type_to_gpt_for_none_boot_disk(self):
536- node = factory.make_Node(bios_boot_method="pxe")
537+ node = factory.make_Node(with_boot_disk=False, bios_boot_method="pxe")
538 factory.make_PhysicalBlockDevice(node=node)
539 other_disk = factory.make_PhysicalBlockDevice(node=node)
540 partition_table = factory.make_PartitionTable(block_device=other_disk)
541 self.assertEquals(PARTITION_TABLE_TYPE.GPT, partition_table.table_type)
542
543 def test_save_force_mbr_on_boot_disk_pxe(self):
544- node = factory.make_Node(bios_boot_method="pxe")
545+ node = factory.make_Node(with_boot_disk=False, bios_boot_method="pxe")
546 boot_disk = factory.make_PhysicalBlockDevice(node=node)
547 error = self.assertRaises(
548 ValidationError,
549@@ -171,7 +171,7 @@
550 }, error.error_dict)
551
552 def test_save_force_mbr_on_boot_disk_pxe_force_gpt_on_boot_disk_uefi(self):
553- node = factory.make_Node(bios_boot_method="uefi")
554+ node = factory.make_Node(with_boot_disk=False, bios_boot_method="uefi")
555 boot_disk = factory.make_PhysicalBlockDevice(node=node)
556 error = self.assertRaises(
557 ValidationError,
558
559=== modified file 'src/maasserver/models/tests/test_physicalblockdevice.py'
560--- src/maasserver/models/tests/test_physicalblockdevice.py 2015-09-24 19:54:30 +0000
561+++ src/maasserver/models/tests/test_physicalblockdevice.py 2015-10-28 01:59:59 +0000
562@@ -59,7 +59,7 @@
563 self.assertRaises(ValidationError, blockdevice.save)
564
565 def test_number_of_physical_devices_for_returns_correct_count(self):
566- node = factory.make_Node()
567+ node = factory.make_Node(with_boot_disk=False)
568 num_of_devices = random.randint(2, 4)
569 for _ in range(num_of_devices):
570 factory.make_PhysicalBlockDevice(node=node)
571@@ -68,7 +68,7 @@
572 PhysicalBlockDevice.objects.number_of_physical_devices_for(node))
573
574 def test_number_of_physical_devices_for_filters_on_node(self):
575- node = factory.make_Node()
576+ node = factory.make_Node(with_boot_disk=False)
577 num_of_devices = random.randint(2, 4)
578 for _ in range(num_of_devices):
579 factory.make_PhysicalBlockDevice(node=node)
580@@ -79,7 +79,7 @@
581 PhysicalBlockDevice.objects.number_of_physical_devices_for(node))
582
583 def test_total_size_of_physical_devices_for_returns_sum_of_size(self):
584- node = factory.make_Node()
585+ node = factory.make_Node(with_boot_disk=False)
586 sizes = [
587 random.randint(MIN_BLOCK_DEVICE_SIZE, MIN_BLOCK_DEVICE_SIZE * 2)
588 for _ in range(3)
589@@ -92,7 +92,7 @@
590 node))
591
592 def test_total_size_of_physical_devices_for_filters_on_node(self):
593- node = factory.make_Node()
594+ node = factory.make_Node(with_boot_disk=False)
595 sizes = [
596 random.randint(MIN_BLOCK_DEVICE_SIZE, MIN_BLOCK_DEVICE_SIZE * 2)
597 for _ in range(3)
598
599=== modified file 'src/maasserver/testing/factory.py'
600--- src/maasserver/testing/factory.py 2015-10-21 20:40:41 +0000
601+++ src/maasserver/testing/factory.py 2015-10-28 01:59:59 +0000
602@@ -261,7 +261,7 @@
603 routers=None, zone=None, networks=None, boot_type=None,
604 sortable_name=False, power_type=None, power_parameters=None,
605 power_state=None, power_state_updated=undefined, disable_ipv4=None,
606- with_boot_disk=False, vlan=None, **kwargs):
607+ with_boot_disk=True, vlan=None, **kwargs):
608 """Make a :class:`Node`.
609
610 :param sortable_name: If `True`, use a that will sort consistently
611@@ -312,7 +312,7 @@
612 node.networks.add(*networks)
613 if interface:
614 self.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan)
615- if with_boot_disk:
616+ if installable and with_boot_disk:
617 self.make_PhysicalBlockDevice(node=node)
618
619 # Update the 'updated'/'created' fields with a call to 'update'
620@@ -1300,8 +1300,10 @@
621 def make_CacheSet(self, block_device=None, partition=None, node=None):
622 if node is None:
623 node = self.make_Node()
624- if block_device is None:
625- if partition is None:
626+ if partition is None and block_device is None:
627+ if self.pick_bool():
628+ partition = self.make_Partition(node=node)
629+ else:
630 block_device = self.make_PhysicalBlockDevice(node=node)
631 if block_device is not None:
632 return CacheSet.objects.get_or_create_cache_set_for_block_device(
633@@ -1328,6 +1330,9 @@
634 if filesystems is None:
635 if node is None:
636 node = self.make_Node()
637+ if node.physicalblockdevice_set.count() == 0:
638+ # Add the boot disk and leave it as is.
639+ self.make_PhysicalBlockDevice(node=node)
640 if group_type == FILESYSTEM_GROUP_TYPE.LVM_VG:
641 for _ in range(num_lvm_devices):
642 block_device = self.make_PhysicalBlockDevice(
643
644=== modified file 'src/maasserver/tests/test_forms_bcache.py'
645--- src/maasserver/tests/test_forms_bcache.py 2015-09-24 16:22:12 +0000
646+++ src/maasserver/tests/test_forms_bcache.py 2015-10-28 01:59:59 +0000
647@@ -40,7 +40,7 @@
648 {'cache_mode': [u'This field is required.']}, form.errors)
649
650 def test_choices_are_being_populated_correctly(self):
651- node = factory.make_Node()
652+ node = factory.make_Node(with_boot_disk=False)
653 # Make 10 block devices.
654 bds = [
655 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)
656@@ -145,6 +145,28 @@
657 bcache.filesystems.get(fstype=FILESYSTEM_TYPE.BCACHE_BACKING))
658 self.assertEqual(FILESYSTEM_GROUP_TYPE.BCACHE, bcache.group_type)
659
660+ def test_bcache_creation_on_boot_disk(self):
661+ node = factory.make_Node(with_boot_disk=False)
662+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
663+ cache_set = factory.make_CacheSet(node=node)
664+ form = CreateBcacheForm(node=node, data={
665+ 'name': 'bcache0',
666+ 'cache_set': cache_set.id,
667+ 'backing_device': boot_disk.id,
668+ 'cache_mode': CACHE_MODE_TYPE.WRITEBACK,
669+ })
670+
671+ self.assertTrue(form.is_valid(), form.errors)
672+ bcache = form.save()
673+ self.assertEqual('bcache0', bcache.name)
674+ self.assertEqual(cache_set, bcache.cache_set)
675+ self.assertEqual(FILESYSTEM_GROUP_TYPE.BCACHE, bcache.group_type)
676+ boot_partition = (
677+ boot_disk.get_partitiontable().partitions.first())
678+ self.assertEqual(
679+ boot_partition.get_effective_filesystem(),
680+ bcache.filesystems.get(fstype=FILESYSTEM_TYPE.BCACHE_BACKING))
681+
682 def test_bcache_creation_with_invalid_names_fails(self):
683 node = factory.make_Node()
684 uuid = unicode(uuid4())
685@@ -218,25 +240,25 @@
686 class TestUpdateBcacheForm(MAASServerTestCase):
687
688 def test_choices_are_being_populated_correctly(self):
689- node = factory.make_Node()
690+ node = factory.make_Node(with_boot_disk=False)
691 device_size = 1 * 1000 ** 4
692- # Make 3 cache sets.
693- cache_sets = [
694- factory.make_CacheSet(node=node)
695- for _ in range(3)
696- ]
697- cache_set_choices = [
698- cache_set.id
699- for cache_set in cache_sets
700- ] + [
701- cache_set.name
702- for cache_set in cache_sets
703- ]
704 # Make 10 block devices.
705 bds = [
706 factory.make_PhysicalBlockDevice(node=node, size=device_size)
707 for _ in range(10)
708 ]
709+ # Make 3 cache sets.
710+ cache_sets = [
711+ factory.make_CacheSet(node=node)
712+ for _ in range(3)
713+ ]
714+ cache_set_choices = [
715+ cache_set.id
716+ for cache_set in cache_sets
717+ ] + [
718+ cache_set.name
719+ for cache_set in cache_sets
720+ ]
721 # Partition the last 5 devices with a single partition.
722 partitions = [
723 factory.make_PartitionTable(block_device=bd).add_partition()
724@@ -328,3 +350,28 @@
725 self.assertIn(
726 'is not one of the available choices.',
727 form.errors['backing_device'][0])
728+
729+ def test_bcache_update_with_boot_disk(self):
730+ node = factory.make_Node(with_boot_disk=False)
731+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
732+ cache_set = factory.make_CacheSet(node=node)
733+ filesystems = [
734+ factory.make_Filesystem(
735+ partition=factory.make_PartitionTable(
736+ block_device=factory.make_PhysicalBlockDevice(
737+ node=node)).add_partition(),
738+ fstype=FILESYSTEM_TYPE.BCACHE_BACKING)
739+ ]
740+ bcache = factory.make_FilesystemGroup(
741+ group_type=FILESYSTEM_GROUP_TYPE.BCACHE, cache_set=cache_set,
742+ filesystems=filesystems)
743+ form = UpdateBcacheForm(bcache=bcache, data={
744+ 'backing_device': boot_disk.id
745+ })
746+ self.assertTrue(form.is_valid(), form.errors)
747+ bcache = form.save()
748+ boot_partition = (
749+ boot_disk.get_partitiontable().partitions.first())
750+ self.assertEqual(
751+ boot_partition.get_effective_filesystem(),
752+ bcache.filesystems.get(fstype=FILESYSTEM_TYPE.BCACHE_BACKING))
753
754=== modified file 'src/maasserver/tests/test_forms_cacheset.py'
755--- src/maasserver/tests/test_forms_cacheset.py 2015-09-24 16:22:12 +0000
756+++ src/maasserver/tests/test_forms_cacheset.py 2015-10-28 01:59:59 +0000
757@@ -35,7 +35,7 @@
758 form.errors)
759
760 def test_choices_are_being_populated_correctly(self):
761- node = factory.make_Node()
762+ node = factory.make_Node(with_boot_disk=False)
763 # Make 10 block devices.
764 bds = [
765 factory.make_PhysicalBlockDevice(node=node)
766@@ -82,6 +82,18 @@
767 cache_set = form.save()
768 self.assertEquals(cache_device, cache_set.get_device())
769
770+ def test_cache_set_creation_with_boot_disk(self):
771+ node = factory.make_Node(with_boot_disk=False)
772+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
773+ form = CreateCacheSetForm(node=node, data={
774+ 'cache_device': boot_disk.id,
775+ })
776+
777+ self.assertTrue(form.is_valid(), form.errors)
778+ cache_set = form.save()
779+ boot_partition = boot_disk.get_partitiontable().partitions.first()
780+ self.assertEquals(boot_partition, cache_set.get_device())
781+
782 def test_cache_set_creation_with_partition(self):
783 node = factory.make_Node()
784 block_device = factory.make_PhysicalBlockDevice(node=node)
785@@ -120,7 +132,7 @@
786 class TestUpdateCacheSetForm(MAASServerTestCase):
787
788 def test_choices_are_being_populated_correctly(self):
789- node = factory.make_Node()
790+ node = factory.make_Node(with_boot_disk=False)
791 # Make 10 block devices.
792 bds = [
793 factory.make_PhysicalBlockDevice(node=node)
794@@ -148,7 +160,7 @@
795 for bd in bds
796 if bd.get_partitiontable() is None
797 ]
798- cache_set = factory.make_CacheSet(block_device=bds[0])
799+ cache_set = factory.make_CacheSet(block_device=bds[1])
800 form = UpdateCacheSetForm(cache_set=cache_set, data={})
801 # Should allow all devices and partitions, including the one currently
802 # in use on the cache set.
803@@ -172,6 +184,20 @@
804 self.assertEquals(new_cache_device, cache_set.get_device())
805 self.assertIsNone(partition.get_effective_filesystem())
806
807+ def test_save_updates_the_cache_set_with_boot_disk(self):
808+ node = factory.make_Node(with_boot_disk=False)
809+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
810+ partition = factory.make_Partition(node=node)
811+ cache_set = factory.make_CacheSet(partition=partition)
812+ form = UpdateCacheSetForm(cache_set=cache_set, data={
813+ "cache_device": boot_disk.id,
814+ })
815+ self.assertTrue(form.is_valid(), form.errors)
816+ cache_set = form.save()
817+ boot_partition = boot_disk.get_partitiontable().partitions.first()
818+ self.assertEquals(boot_partition, cache_set.get_device())
819+ self.assertIsNone(partition.get_effective_filesystem())
820+
821 def test_save_updates_the_cache_set_with_partition(self):
822 node = factory.make_Node()
823 cache_device = factory.make_PhysicalBlockDevice(node=node)
824
825=== modified file 'src/maasserver/tests/test_forms_raid.py'
826--- src/maasserver/tests/test_forms_raid.py 2015-08-14 13:48:59 +0000
827+++ src/maasserver/tests/test_forms_raid.py 2015-10-28 01:59:59 +0000
828@@ -71,7 +71,7 @@
829 form.errors)
830
831 def test_choices_are_being_populated_correctly(self):
832- node = factory.make_Node()
833+ node = factory.make_Node(with_boot_disk=False)
834 bds = [
835 factory.make_PhysicalBlockDevice(node=node, size=10 * 1000 ** 4)
836 for _ in range(10)
837@@ -209,6 +209,51 @@
838 for fs in raid.filesystems.exclude(partition=None)
839 ])
840
841+ def test_raid_creation_on_boot_disk(self):
842+ node = factory.make_Node(with_boot_disk=False)
843+ bds = [
844+ factory.make_PhysicalBlockDevice(node=node)
845+ for _ in range(10)
846+ ]
847+ for bd in bds[5:]:
848+ factory.make_PartitionTable(block_device=bd)
849+ block_devices = [
850+ bd.id
851+ for bd in bds
852+ if bd.get_partitiontable() is None
853+ ]
854+ partitions = [
855+ bd.get_partitiontable().add_partition().id
856+ for bd in bds[5:]
857+ ]
858+ form = CreateRaidForm(node=node, data={
859+ 'name': 'md1',
860+ 'level': FILESYSTEM_GROUP_TYPE.RAID_6,
861+ 'block_devices': block_devices,
862+ 'partitions': partitions,
863+ })
864+ self.assertTrue(form.is_valid(), form.errors)
865+ raid = form.save()
866+ self.assertEqual('md1', raid.name)
867+ self.assertEqual(FILESYSTEM_GROUP_TYPE.RAID_6, raid.group_type)
868+ block_devices = [
869+ bd.id
870+ for bd in bds
871+ if bd.get_partitiontable() is None and not bd.is_boot_disk()
872+ ]
873+ self.assertItemsEqual(
874+ block_devices,
875+ [fs.block_device.id
876+ for fs in raid.filesystems.exclude(block_device=None)])
877+ partitions = [
878+ bd.get_partitiontable().partitions.first().id
879+ for bd in [bds[0]] + bds[5:]
880+ ]
881+ self.assertItemsEqual(
882+ partitions,
883+ [fs.partition.id
884+ for fs in raid.filesystems.exclude(partition=None)])
885+
886 def test_raid_creation_without_storage_fails(self):
887 node = factory.make_Node()
888 for level in [
889@@ -255,6 +300,20 @@
890 form = UpdateRaidForm(raid, data={'add_block_devices': bd_names})
891 self.assertTrue(form.is_valid(), form.errors)
892
893+ def test_add_valid_boot_disk(self):
894+ node = factory.make_Node(with_boot_disk=False)
895+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
896+ raid = factory.make_FilesystemGroup(
897+ group_type=FILESYSTEM_GROUP_TYPE.RAID_6, node=node)
898+ raid = RAID.objects.get(id=raid.id)
899+ form = UpdateRaidForm(raid, data={'add_block_devices': [boot_disk.id]})
900+ self.assertTrue(form.is_valid(), form.errors)
901+ raid = form.save()
902+ boot_partition = boot_disk.get_partitiontable().partitions.first()
903+ self.assertEquals(
904+ boot_partition.get_effective_filesystem().filesystem_group.id,
905+ raid.id)
906+
907 def test_add_valid_partition(self):
908 raid = factory.make_FilesystemGroup(
909 group_type=FILESYSTEM_GROUP_TYPE.RAID_6)
910@@ -273,6 +332,20 @@
911 form = UpdateRaidForm(raid, data={'add_spare_devices': bd_ids})
912 self.assertTrue(form.is_valid(), form.errors)
913
914+ def test_add_valid_spare_boot_disk(self):
915+ node = factory.make_Node(with_boot_disk=False)
916+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
917+ raid = factory.make_FilesystemGroup(
918+ group_type=FILESYSTEM_GROUP_TYPE.RAID_6, node=node)
919+ raid = RAID.objects.get(id=raid.id)
920+ form = UpdateRaidForm(raid, data={'add_spare_devices': [boot_disk.id]})
921+ self.assertTrue(form.is_valid(), form.errors)
922+ raid = form.save()
923+ boot_partition = boot_disk.get_partitiontable().partitions.first()
924+ self.assertEquals(
925+ boot_partition.get_effective_filesystem().filesystem_group.id,
926+ raid.id)
927+
928 def test_add_valid_spare_partition(self):
929 raid = factory.make_FilesystemGroup(
930 group_type=FILESYSTEM_GROUP_TYPE.RAID_6)
931
932=== modified file 'src/maasserver/tests/test_forms_volume_group.py'
933--- src/maasserver/tests/test_forms_volume_group.py 2015-09-25 14:39:44 +0000
934+++ src/maasserver/tests/test_forms_volume_group.py 2015-10-28 01:59:59 +0000
935@@ -144,6 +144,21 @@
936 ]
937 self.assertItemsEqual(block_devices, block_devices_in_vg)
938
939+ def test_creates_volume_group_with_boot_disk(self):
940+ node = factory.make_Node(with_boot_disk=False)
941+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
942+ data = {
943+ 'name': factory.make_name("vg"),
944+ 'block_devices': [boot_disk.id],
945+ }
946+ form = CreateVolumeGroupForm(node, data=data)
947+ self.assertTrue(form.is_valid(), form._errors)
948+ volume_group = form.save()
949+ boot_partition = boot_disk.get_partitiontable().partitions.first()
950+ self.assertEquals(
951+ boot_partition.get_effective_filesystem().filesystem_group.id,
952+ volume_group.id)
953+
954 def test_creates_volume_group_with_block_devices_by_name(self):
955 node = factory.make_Node()
956 block_devices = [
957@@ -322,6 +337,21 @@
958 volume_group.id,
959 block_device.get_effective_filesystem().filesystem_group.id)
960
961+ def test_adds_boot_disk(self):
962+ node = factory.make_Node(with_boot_disk=False)
963+ boot_disk = factory.make_PhysicalBlockDevice(node=node)
964+ volume_group = factory.make_VolumeGroup(node=node)
965+ data = {
966+ 'add_block_devices': [boot_disk.id],
967+ }
968+ form = UpdateVolumeGroupForm(volume_group, data=data)
969+ self.assertTrue(form.is_valid(), form._errors)
970+ volume_group = form.save()
971+ boot_partition = boot_disk.get_partitiontable().partitions.first()
972+ self.assertEquals(
973+ boot_partition.get_effective_filesystem().filesystem_group.id,
974+ volume_group.id)
975+
976 def test_adds_block_device_by_name(self):
977 node = factory.make_Node()
978 volume_group = factory.make_VolumeGroup(node=node)
979
980=== modified file 'src/maasserver/tests/test_node_constraint_filter_forms.py'
981--- src/maasserver/tests/test_node_constraint_filter_forms.py 2015-09-02 06:08:25 +0000
982+++ src/maasserver/tests/test_node_constraint_filter_forms.py 2015-10-28 01:59:59 +0000
983@@ -703,22 +703,22 @@
984 (form.is_valid(), form.errors))
985
986 def test_storage_single_contraint_only_matches_physical_devices(self):
987- node1 = factory.make_Node()
988+ node1 = factory.make_Node(with_boot_disk=False)
989 factory.make_PhysicalBlockDevice(node=node1)
990- node2 = factory.make_Node()
991+ node2 = factory.make_Node(with_boot_disk=False)
992 factory.make_BlockDevice(node=node2)
993 self.assertConstrainedNodes([node1], {'storage': '0'})
994
995 def test_storage_single_contraint_matches_all_sizes_larger(self):
996- node1 = factory.make_Node()
997+ node1 = factory.make_Node(with_boot_disk=False)
998 # 1gb block device
999 factory.make_PhysicalBlockDevice(
1000 node=node1, size=1 * (1000 ** 3))
1001- node2 = factory.make_Node()
1002+ node2 = factory.make_Node(with_boot_disk=False)
1003 # 4gb block device
1004 factory.make_PhysicalBlockDevice(
1005 node=node2, size=4 * (1000 ** 3))
1006- node3 = factory.make_Node()
1007+ node3 = factory.make_Node(with_boot_disk=False)
1008 # 8gb block device
1009 factory.make_PhysicalBlockDevice(
1010 node=node3, size=8 * (1000 ** 3))
1011@@ -726,36 +726,36 @@
1012 self.assertConstrainedNodes([node2, node3], {'storage': '2'})
1013
1014 def test_storage_single_contraint_matches_on_tags(self):
1015- node1 = factory.make_Node()
1016+ node1 = factory.make_Node(with_boot_disk=False)
1017 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd'])
1018- node2 = factory.make_Node()
1019+ node2 = factory.make_Node(with_boot_disk=False)
1020 factory.make_PhysicalBlockDevice(node=node2, tags=['rotary'])
1021 self.assertConstrainedNodes([node1], {'storage': '0(ssd)'})
1022
1023 def test_storage_single_contraint_matches_decimal_size(self):
1024- node1 = factory.make_Node()
1025+ node1 = factory.make_Node(with_boot_disk=False)
1026 # 2gb, 4gb block device
1027 factory.make_PhysicalBlockDevice(
1028 node=node1, size=2 * (1000 ** 3))
1029 factory.make_PhysicalBlockDevice(
1030 node=node1, size=4 * (1000 ** 3))
1031- node2 = factory.make_Node()
1032+ node2 = factory.make_Node(with_boot_disk=False)
1033 # 1gb block device
1034 factory.make_PhysicalBlockDevice(
1035 node=node2, size=1 * (1000 ** 3))
1036 self.assertConstrainedNodes([node1], {'storage': '1.5'})
1037
1038 def test_storage_multi_contraint_only_matches_physical_devices(self):
1039- node1 = factory.make_Node()
1040- factory.make_PhysicalBlockDevice(node=node1)
1041- factory.make_PhysicalBlockDevice(node=node1)
1042- node2 = factory.make_Node()
1043+ node1 = factory.make_Node(with_boot_disk=False)
1044+ factory.make_PhysicalBlockDevice(node=node1)
1045+ factory.make_PhysicalBlockDevice(node=node1)
1046+ node2 = factory.make_Node(with_boot_disk=False)
1047 factory.make_BlockDevice(node=node2)
1048 factory.make_BlockDevice(node=node2)
1049 self.assertConstrainedNodes([node1], {'storage': '0,0'})
1050
1051 def test_storage_multi_contraint_matches_all_sizes_larger(self):
1052- node1 = factory.make_Node()
1053+ node1 = factory.make_Node(with_boot_disk=False)
1054 # 1gb, 2gb, 3gb block device
1055 factory.make_PhysicalBlockDevice(
1056 node=node1, size=1 * (1000 ** 3))
1057@@ -763,7 +763,7 @@
1058 node=node1, size=2 * (1000 ** 3))
1059 factory.make_PhysicalBlockDevice(
1060 node=node1, size=3 * (1000 ** 3))
1061- node2 = factory.make_Node()
1062+ node2 = factory.make_Node(with_boot_disk=False)
1063 # 5gb, 6gb, 7gb block device
1064 factory.make_PhysicalBlockDevice(
1065 node=node2, size=5 * (1000 ** 3))
1066@@ -771,7 +771,7 @@
1067 node=node2, size=6 * (1000 ** 3))
1068 factory.make_PhysicalBlockDevice(
1069 node=node2, size=7 * (1000 ** 3))
1070- node3 = factory.make_Node()
1071+ node3 = factory.make_Node(with_boot_disk=False)
1072 # 8gb, 9gb, 10gb block device
1073 factory.make_PhysicalBlockDevice(
1074 node=node3, size=8 * (1000 ** 3))
1075@@ -783,17 +783,17 @@
1076 self.assertConstrainedNodes([node2, node3], {'storage': '4,4,4'})
1077
1078 def test_storage_multi_contraint_matches_on_tags(self):
1079- node1 = factory.make_Node()
1080+ node1 = factory.make_Node(with_boot_disk=False)
1081 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd'])
1082 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd', 'removable'])
1083- node2 = factory.make_Node()
1084+ node2 = factory.make_Node(with_boot_disk=False)
1085 factory.make_PhysicalBlockDevice(node=node2, tags=['ssd'])
1086 factory.make_PhysicalBlockDevice(node=node2, tags=['ssd', 'sata'])
1087 self.assertConstrainedNodes(
1088 [node1], {'storage': '0(ssd),0(ssd,removable)'})
1089
1090 def test_storage_multi_contraint_matches_on_size_and_tags(self):
1091- node1 = factory.make_Node()
1092+ node1 = factory.make_Node(with_boot_disk=False)
1093 # 1gb, 2gb block device
1094 factory.make_PhysicalBlockDevice(
1095 node=node1, size=1 * (1000 ** 3),
1096@@ -801,7 +801,7 @@
1097 factory.make_PhysicalBlockDevice(
1098 node=node1, size=2 * (1000 ** 3),
1099 tags=['ssd'])
1100- node2 = factory.make_Node()
1101+ node2 = factory.make_Node(with_boot_disk=False)
1102 # 4gb, 5gb block device
1103 factory.make_PhysicalBlockDevice(
1104 node=node2, size=4 * (1000 ** 3),
1105@@ -818,12 +818,12 @@
1106 11(ssd) first device, a 21 second device and a 10 third device,
1107 but not a 5/20/10(ssd) node
1108 """
1109- node1 = factory.make_Node()
1110+ node1 = factory.make_Node(with_boot_disk=False)
1111 factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3))
1112 factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3))
1113 factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3),
1114 tags=['ssd'])
1115- node2 = factory.make_Node()
1116+ node2 = factory.make_Node(with_boot_disk=False)
1117 factory.make_PhysicalBlockDevice(node=node2, size=11 * (1000 ** 3),
1118 tags=['ssd'])
1119 factory.make_PhysicalBlockDevice(node=node2, size=6 * (1000 ** 3))
1120@@ -832,10 +832,10 @@
1121 [node2], {'storage': '10(ssd),5,20'})
1122
1123 def test_storage_multi_contraint_matches_large_disk_count(self):
1124- node1 = factory.make_Node()
1125+ node1 = factory.make_Node(with_boot_disk=False)
1126 for _ in range(10):
1127 factory.make_PhysicalBlockDevice(node=node1)
1128- node2 = factory.make_Node()
1129+ node2 = factory.make_Node(with_boot_disk=False)
1130 for _ in range(5):
1131 factory.make_PhysicalBlockDevice(node=node2)
1132 self.assertConstrainedNodes(
1133@@ -845,7 +845,7 @@
1134 "XXX: allenap 2015-03-17 bug=1433012: This test keeps failing when "
1135 "landing unrelated branches, so has been disabled.")
1136 def test_storage_with_named_constraints(self):
1137- node1 = factory.make_Node()
1138+ node1 = factory.make_Node(with_boot_disk=False)
1139 factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3),
1140 tags=['ssd'])
1141 factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3),
1142
1143=== modified file 'src/maasserver/tests/test_preseed_storage.py'
1144--- src/maasserver/tests/test_preseed_storage.py 2015-09-25 14:39:44 +0000
1145+++ src/maasserver/tests/test_preseed_storage.py 2015-10-28 01:59:59 +0000
1146@@ -136,7 +136,8 @@
1147
1148 def test__renders_expected_output(self):
1149 node = factory.make_Node(
1150- status=NODE_STATUS.ALLOCATED, bios_boot_method="uefi")
1151+ status=NODE_STATUS.ALLOCATED, bios_boot_method="uefi",
1152+ with_boot_disk=False)
1153 boot_disk = factory.make_PhysicalBlockDevice(
1154 node=node, size=8 * 1024 ** 3, name="sda",
1155 model="QEMU HARDDISK", serial="QM00001") # 8 GiB
1156@@ -289,7 +290,8 @@
1157 """)
1158
1159 def test__renders_expected_output(self):
1160- node = factory.make_Node(status=NODE_STATUS.ALLOCATED)
1161+ node = factory.make_Node(
1162+ status=NODE_STATUS.ALLOCATED, with_boot_disk=False)
1163 boot_disk = factory.make_PhysicalBlockDevice(
1164 node=node, size=8 * 1024 ** 3, name="sda",
1165 model="QEMU HARDDISK", serial="QM00001") # 8 GiB
1166@@ -385,7 +387,8 @@
1167 """)
1168
1169 def test__renders_expected_output(self):
1170- node = factory.make_Node(status=NODE_STATUS.ALLOCATED)
1171+ node = factory.make_Node(
1172+ status=NODE_STATUS.ALLOCATED, with_boot_disk=False)
1173 boot_disk = factory.make_PhysicalBlockDevice(
1174 node=node, size=8 * 1024 ** 3, name="sda",
1175 model="QEMU HARDDISK", serial="QM00001") # 8 GiB
1176@@ -591,7 +594,8 @@
1177
1178 def test__renders_expected_output(self):
1179 node = factory.make_Node(
1180- status=NODE_STATUS.ALLOCATED, bios_boot_method="uefi")
1181+ status=NODE_STATUS.ALLOCATED, bios_boot_method="uefi",
1182+ with_boot_disk=False)
1183 boot_disk = factory.make_PhysicalBlockDevice(
1184 node=node, size=8 * 1024 ** 3, name="sda",
1185 model="QEMU HARDDISK", serial="QM00001") # 8 GiB
1186
1187=== modified file 'src/maasserver/tests/test_storage_layouts.py'
1188--- src/maasserver/tests/test_storage_layouts.py 2015-10-11 06:12:21 +0000
1189+++ src/maasserver/tests/test_storage_layouts.py 2015-10-28 01:59:59 +0000
1190@@ -62,6 +62,7 @@
1191
1192 def make_Node_with_uefi_boot_method(*args, **kwargs):
1193 kwargs['bios_boot_method'] = "uefi"
1194+ kwargs['with_boot_disk'] = False
1195 return factory.make_Node(*args, **kwargs)
1196
1197
1198@@ -458,7 +459,7 @@
1199 ], layout.fields.keys())
1200
1201 def test__creates_layout_with_mbr_defaults(self):
1202- node = factory.make_Node()
1203+ node = factory.make_Node(with_boot_disk=False)
1204 boot_disk = factory.make_PhysicalBlockDevice(
1205 node=node, size=LARGE_BLOCK_DEVICE)
1206 layout = FlatStorageLayout(node)
1207@@ -486,7 +487,7 @@
1208 ))
1209
1210 def test__creates_layout_with_maximum_mbr_partition_size(self):
1211- node = factory.make_Node()
1212+ node = factory.make_Node(with_boot_disk=False)
1213 boot_disk = factory.make_PhysicalBlockDevice(
1214 node=node, size=3 * (1024 ** 4))
1215 layout = FlatStorageLayout(node)
1216@@ -990,7 +991,7 @@
1217 ))
1218
1219 def test__creates_layout_with_multiple_mbr_partitions(self):
1220- node = factory.make_Node()
1221+ node = factory.make_Node(with_boot_disk=False)
1222 boot_disk = factory.make_PhysicalBlockDevice(
1223 node=node, size=7 * (1024 ** 4))
1224 layout = LVMStorageLayout(node)
1225
1226=== modified file 'src/maasserver/websockets/tests/test_listener.py'
1227--- src/maasserver/websockets/tests/test_listener.py 2015-10-01 12:17:36 +0000
1228+++ src/maasserver/websockets/tests/test_listener.py 2015-10-28 01:59:59 +0000
1229@@ -423,6 +423,7 @@
1230 def create_node(self, params=None):
1231 if params is None:
1232 params = {}
1233+ params['with_boot_disk'] = False
1234 return factory.make_Node(**params)
1235
1236 @transactional
1237@@ -441,7 +442,7 @@
1238 def create_device_with_parent(self, params=None):
1239 if params is None:
1240 params = {}
1241- parent = factory.make_Node()
1242+ parent = factory.make_Node(with_boot_disk=False)
1243 params["installable"] = False
1244 params["parent"] = parent
1245 device = factory.make_Node(**params)
1246
1247=== modified file 'src/metadataserver/models/tests/test_commissioningscript.py'
1248--- src/metadataserver/models/tests/test_commissioningscript.py 2015-09-24 16:22:12 +0000
1249+++ src/metadataserver/models/tests/test_commissioningscript.py 2015-10-28 01:59:59 +0000
1250@@ -1100,8 +1100,8 @@
1251
1252 def test__creates_physical_block_device_only_for_node(self):
1253 device = self.make_block_device()
1254- node = factory.make_Node()
1255- other_node = factory.make_Node()
1256+ node = factory.make_Node(with_boot_disk=False)
1257+ other_node = factory.make_Node(with_boot_disk=False)
1258 json_output = json.dumps([device]).encode('utf-8')
1259 update_node_physical_block_devices(node, json_output, 0)
1260 self.assertEquals(