Merge lp:~blake-rouse/maas/fix-1509536-part1 into lp:~maas-committers/maas/trunk
- fix-1509536-part1
- Merge into trunk
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 |
Related bugs: |
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
Part1 of fixing bug: https:/
Blake Rouse (blake-rouse) wrote : | # |
Thanks for the review.
MAAS Lander (maas-lander) wrote : | # |
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://
Ign http://
Get:2 http://
Hit http://
Hit http://
Get:3 http://
Get:4 http://
Get:5 http://
Get:6 http://
Get:7 http://
Get:8 http://
Get:9 http://
Hit http://
Hit http://
Get:10 http://
Get:11 http://
Get:12 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Ign http://
Ign http://
Fetched 2,551 kB in 4s (600 kB/s)
Reading package lists...
sudo DEBIAN_
--
Preview Diff
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( |
Looks good. Just one thing I'd fix about your utility function. My pet peeve is putting more code in forms.py. ;-)