Merge lp:~blake-rouse/maas/fix-1674148 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: 5958
Proposed branch: lp:~blake-rouse/maas/fix-1674148
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 594 lines (+266/-135)
4 files modified
src/maasserver/api/tests/test_machines.py (+5/-9)
src/maasserver/node_constraint_filter_forms.py (+47/-49)
src/maasserver/testing/factory.py (+9/-2)
src/maasserver/tests/test_node_constraint_filter_forms.py (+205/-75)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1674148
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+322378@code.launchpad.net

Commit message

Fix storage constraints to map the root disk to the disk with '/' on it. Non root constraints map to block devices that are unused, but can be a virtual block device.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm!

review: Approve

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_machines.py'
2--- src/maasserver/api/tests/test_machines.py 2017-04-05 21:06:53 +0000
3+++ src/maasserver/api/tests/test_machines.py 2017-04-11 16:17:53 +0000
4@@ -686,7 +686,7 @@
5 status=available_status, owner=None, with_boot_disk=False)
6 disk_1 = factory.make_PhysicalBlockDevice(
7 node=machine, size=(random.randint(8, 16) * (1000 ** 3)),
8- tags=['local'])
9+ tags=['local'], formatted_root=True)
10 disk_2 = factory.make_ISCSIBlockDevice(
11 node=machine, size=(random.randint(8, 16) * (1000 ** 3)),
12 tags=['iscsi'])
13@@ -1146,11 +1146,9 @@
14 """Storage label is returned alongside machine data"""
15 machine = factory.make_Node(
16 status=NODE_STATUS.READY, with_boot_disk=False)
17- # The ID may always be '1', which won't be interesting for testing.
18- for _ in range(1, random.choice([1, 3, 5])):
19- factory.make_PhysicalBlockDevice()
20 factory.make_PhysicalBlockDevice(
21- node=machine, size=11 * (1000 ** 3), tags=['ssd'])
22+ node=machine, size=11 * (1000 ** 3), tags=['ssd'],
23+ formatted_root=True)
24 response = self.client.post(reverse('machines_handler'), {
25 'op': 'allocate',
26 'storage': 'needed:10(ssd)',
27@@ -1169,11 +1167,9 @@
28 """Storage label is returned alongside machine data"""
29 machine = factory.make_Node(
30 status=NODE_STATUS.READY, with_boot_disk=False)
31- # The ID may always be '1', which won't be interesting for testing.
32- for _ in range(1, random.choice([1, 3, 5])):
33- factory.make_PhysicalBlockDevice()
34 factory.make_PhysicalBlockDevice(
35- node=machine, size=11 * (1000 ** 3), tags=['ssd'])
36+ node=machine, size=11 * (1000 ** 3), tags=['ssd'],
37+ formatted_root=True)
38 response = self.client.post(reverse('machines_handler'), {
39 'op': 'allocate',
40 'storage': 'needed:10(ssd)',
41
42=== modified file 'src/maasserver/node_constraint_filter_forms.py'
43--- src/maasserver/node_constraint_filter_forms.py 2017-04-05 13:41:28 +0000
44+++ src/maasserver/node_constraint_filter_forms.py 2017-04-11 16:17:53 +0000
45@@ -27,12 +27,11 @@
46 import maasserver.forms as maasserver_forms
47 from maasserver.models import (
48 BlockDevice,
49+ Filesystem,
50 Interface,
51- PhysicalBlockDevice,
52 Pod,
53 Subnet,
54 Tag,
55- VirtualBlockDevice,
56 VLAN,
57 Zone,
58 )
59@@ -319,71 +318,70 @@
60 root_device = True # The 1st constraint refers to the node's 1st device
61 for constraint_name, size, tags in constraints:
62 if root_device:
63- # Sort the `PhysicalBlockDevice`s by id because we consider the
64- # first device as the root device.
65+ # This branch of the if is only used on first iteration.
66 root_device = False
67- matched_devices = PhysicalBlockDevice.objects.all()
68+
69+ # Use only block devices that are mounted as '/'. Either the
70+ # block device has root sitting on it or its on a partition on
71+ # that block device.
72+ filesystems = Filesystem.objects.filter(
73+ mount_point='/', acquired=False)
74+ filesystems = filesystems.filter(
75+ Q(block_device__size__gte=size) |
76+ Q(partition__partition_table__block_device__size__gte=size))
77+ if tags is not None:
78+ filesystems = filesystems.filter(
79+ Q(block_device__tags__contains=tags) |
80+ Q(**{
81+ 'partition__partition_table__block_device'
82+ '__tags__contains': tags
83+ }))
84 if node_ids is not None:
85- matched_devices = matched_devices.filter(node_id__in=node_ids)
86- matched_devices = matched_devices.order_by('id').values(
87- 'id', 'node_id', 'size', 'tags')
88+ filesystems = filesystems.filter(
89+ Q(block_device__node_id__in=node_ids) |
90+ Q(**{
91+ 'partition__partition_table__block_device'
92+ '__node_id__in': node_ids
93+ }))
94+ filesystems = filesystems.prefetch_related(
95+ 'block_device', 'partition__partition_table__block_device')
96
97 # Only keep the first device for every node. This is done to make
98 # sure filtering out the size and tags is not done to all the
99 # block devices. This should only be done to the first block
100 # device.
101 found_nodes = set()
102- devices = []
103- for device in matched_devices:
104- if device['node_id'] in found_nodes:
105+ matched_devices = []
106+ for filesystem in filesystems:
107+ if filesystem.block_device is not None:
108+ device = filesystem.block_device
109+ else:
110+ device = (
111+ filesystem.partition.partition_table.block_device)
112+ if device.node_id in found_nodes:
113 continue
114- devices.append(device)
115- found_nodes.add(device['node_id'])
116-
117- # Remove the devices that are not of correct size and the devices
118- # that are missing the correct tags or label.
119- devices = [
120- device
121- for device in devices
122- if device['size'] >= size
123- ]
124+ matched_devices.append(device)
125+ found_nodes.add(device.node_id)
126+ else:
127+ # Query for any block device the closest size and, if specified,
128+ # the given tags. # The block device must also be unused in the
129+ # storage model.
130+ matched_devices = BlockDevice.objects.filter(size__gte=size)
131+ matched_devices = matched_devices.filter(
132+ filesystem__isnull=True, partitiontable__isnull=True)
133 if tags is not None:
134- tags = set(tags)
135- devices = [
136- device
137- for device in devices
138- if tags.issubset(set(device['tags']))
139- ]
140- matched_devices = devices
141- else:
142- # Query for the `PhysicalBlockDevice`s and `ISCSIBlockDevice`'s
143- # that have the closest size and, if specified, the given tags.
144- if tags is None:
145- matched_devices = BlockDevice.objects.filter(
146- size__gte=size).order_by('size')
147- else:
148- matched_devices = BlockDevice.objects.filter_by_tags(
149- tags).filter(size__gte=size)
150+ matched_devices = matched_devices.filter(tags__contains=tags)
151 if node_ids is not None:
152 matched_devices = matched_devices.filter(
153 node_id__in=node_ids)
154- matched_devices = [
155- {
156- 'id': device.id,
157- 'node_id': device.node_id,
158- 'size': device.size,
159- 'tags': device.tags,
160- }
161- for device in matched_devices.order_by('size')
162- if not isinstance(device.actual_instance, VirtualBlockDevice)
163- ]
164+ matched_devices = list(matched_devices.order_by('size'))
165
166 # Loop through all the returned devices. Insert only the first
167 # device from each node into `matches`.
168 matched_in_loop = []
169 for device in matched_devices:
170- device_id = device['id']
171- device_node_id = device['node_id']
172+ device_id = device.id
173+ device_node_id = device.node_id
174
175 if device_node_id in matched_in_loop:
176 continue
177
178=== modified file 'src/maasserver/testing/factory.py'
179--- src/maasserver/testing/factory.py 2017-04-10 21:49:47 +0000
180+++ src/maasserver/testing/factory.py 2017-04-11 16:17:53 +0000
181@@ -1793,7 +1793,8 @@
182
183 def make_PhysicalBlockDevice(
184 self, node=None, name=None, size=None, block_size=None,
185- tags=None, model=None, serial=None, id_path=None):
186+ tags=None, model=None, serial=None, id_path=None,
187+ formatted_root=False):
188 if node is None:
189 node = self.make_Node()
190 if name is None:
191@@ -1819,9 +1820,15 @@
192 else:
193 model = ""
194 serial = ""
195- return PhysicalBlockDevice.objects.create(
196+ block_device = PhysicalBlockDevice.objects.create(
197 node=node, name=name, size=size, block_size=block_size,
198 tags=tags, model=model, serial=serial, id_path=id_path)
199+ if formatted_root:
200+ partition = self.make_Partition(
201+ partition_table=(
202+ self.make_PartitionTable(block_device=block_device)))
203+ self.make_Filesystem(mount_point='/', partition=partition)
204+ return block_device
205
206 def make_PartitionTable(
207 self, table_type=None, block_device=None, node=None,
208
209=== modified file 'src/maasserver/tests/test_node_constraint_filter_forms.py'
210--- src/maasserver/tests/test_node_constraint_filter_forms.py 2017-03-15 20:40:52 +0000
211+++ src/maasserver/tests/test_node_constraint_filter_forms.py 2017-04-11 16:17:53 +0000
212@@ -6,11 +6,12 @@
213 __all__ = []
214
215 from random import randint
216-from unittest import skip
217
218 from django import forms
219 from django.core.exceptions import ValidationError
220 from maasserver.enum import (
221+ FILESYSTEM_GROUP_TYPE,
222+ FILESYSTEM_TYPE,
223 INTERFACE_TYPE,
224 IPADDRESS_TYPE,
225 NODE_STATUS,
226@@ -835,34 +836,50 @@
227 ['Malformed storage constraint, "abc".']}),
228 (form.is_valid(), form.errors))
229
230- def test_storage_single_contraint_only_matches_physical_devices(self):
231+ def test_storage_matches_disk_with_root_mount_on_disk(self):
232 node1 = factory.make_Node(with_boot_disk=False)
233 factory.make_PhysicalBlockDevice(node=node1)
234- node2 = factory.make_Node(with_boot_disk=False)
235- factory.make_BlockDevice(node=node2)
236+ block_device = factory.make_PhysicalBlockDevice(node=node1)
237+ factory.make_Filesystem(mount_point='/', block_device=block_device)
238+ node2 = factory.make_Node(with_boot_disk=False)
239+ factory.make_PhysicalBlockDevice(node=node2)
240+ self.assertConstrainedNodes([node1], {'storage': '0'})
241+
242+ def test_storage_matches_disk_with_root_mount_on_partition(self):
243+ node1 = factory.make_Node(with_boot_disk=False)
244+ factory.make_PhysicalBlockDevice(
245+ node=node1, formatted_root=True)
246+ node2 = factory.make_Node(with_boot_disk=False)
247+ block_device = factory.make_PhysicalBlockDevice(node=node2)
248+ partition_table = factory.make_PartitionTable(
249+ block_device=block_device)
250+ partition = factory.make_Partition(partition_table=partition_table)
251+ factory.make_Filesystem(mount_point='/srv', partition=partition)
252 self.assertConstrainedNodes([node1], {'storage': '0'})
253
254 def test_storage_single_contraint_matches_all_sizes_larger(self):
255 node1 = factory.make_Node(with_boot_disk=False)
256 # 1gb block device
257 factory.make_PhysicalBlockDevice(
258- node=node1, size=1 * (1000 ** 3))
259+ node=node1, size=1 * (1000 ** 3), formatted_root=True)
260 node2 = factory.make_Node(with_boot_disk=False)
261 # 4gb block device
262 factory.make_PhysicalBlockDevice(
263- node=node2, size=4 * (1000 ** 3))
264+ node=node2, size=4 * (1000 ** 3), formatted_root=True)
265 node3 = factory.make_Node(with_boot_disk=False)
266 # 8gb block device
267 factory.make_PhysicalBlockDevice(
268- node=node3, size=8 * (1000 ** 3))
269+ node=node3, size=8 * (1000 ** 3), formatted_root=True)
270 # all nodes with physical devices larger than 2gb
271 self.assertConstrainedNodes([node2, node3], {'storage': '2'})
272
273 def test_storage_single_contraint_matches_on_tags(self):
274 node1 = factory.make_Node(with_boot_disk=False)
275- factory.make_PhysicalBlockDevice(node=node1, tags=['ssd'])
276+ factory.make_PhysicalBlockDevice(
277+ node=node1, tags=['ssd'], formatted_root=True)
278 node2 = factory.make_Node(with_boot_disk=False)
279- factory.make_PhysicalBlockDevice(node=node2, tags=['rotary'])
280+ factory.make_PhysicalBlockDevice(
281+ node=node2, tags=['rotary'], formatted_root=True)
282 self.assertConstrainedNodes([node1], {'storage': '0(ssd)'})
283
284 def test_storage_single_contraint_matches_decimal_size(self):
285@@ -871,56 +888,153 @@
286 factory.make_PhysicalBlockDevice(
287 node=node1, size=2 * (1000 ** 3))
288 factory.make_PhysicalBlockDevice(
289- node=node1, size=4 * (1000 ** 3))
290+ node=node1, size=4 * (1000 ** 3), formatted_root=True)
291 node2 = factory.make_Node(with_boot_disk=False)
292 # 1gb block device
293 factory.make_PhysicalBlockDevice(
294- node=node2, size=1 * (1000 ** 3))
295+ node=node2, size=1 * (1000 ** 3), formatted_root=True)
296 self.assertConstrainedNodes([node1], {'storage': '1.5'})
297
298- def test_storage_multi_contraint_only_matches_physical_devices(self):
299- node1 = factory.make_Node(with_boot_disk=False)
300- factory.make_PhysicalBlockDevice(node=node1)
301- factory.make_PhysicalBlockDevice(node=node1)
302- node2 = factory.make_Node(with_boot_disk=False)
303- factory.make_BlockDevice(node=node2)
304- factory.make_BlockDevice(node=node2)
305- self.assertConstrainedNodes([node1], {'storage': '0,0'})
306-
307- def test_storage_multi_contraint_matches_all_sizes_larger(self):
308- node1 = factory.make_Node(with_boot_disk=False)
309- # 1gb, 2gb, 3gb block device
310- factory.make_PhysicalBlockDevice(
311- node=node1, size=1 * (1000 ** 3))
312- factory.make_PhysicalBlockDevice(
313- node=node1, size=2 * (1000 ** 3))
314- factory.make_PhysicalBlockDevice(
315- node=node1, size=3 * (1000 ** 3))
316- node2 = factory.make_Node(with_boot_disk=False)
317- # 5gb, 6gb, 7gb block device
318- factory.make_PhysicalBlockDevice(
319- node=node2, size=5 * (1000 ** 3))
320- factory.make_PhysicalBlockDevice(
321- node=node2, size=6 * (1000 ** 3))
322- factory.make_PhysicalBlockDevice(
323- node=node2, size=7 * (1000 ** 3))
324- node3 = factory.make_Node(with_boot_disk=False)
325- # 8gb, 9gb, 10gb block device
326- factory.make_PhysicalBlockDevice(
327- node=node3, size=8 * (1000 ** 3))
328- factory.make_PhysicalBlockDevice(
329- node=node3, size=9 * (1000 ** 3))
330- factory.make_PhysicalBlockDevice(
331- node=node3, size=10 * (1000 ** 3))
332- # all nodes with physical devices larger than 2gb
333- self.assertConstrainedNodes([node2, node3], {'storage': '4,4,4'})
334+ def test_storage_single_contraint_allows_root_on_virtual(self):
335+ node1 = factory.make_Node(with_boot_disk=False)
336+ physical = factory.make_PhysicalBlockDevice(node=node1)
337+ partition_table = factory.make_PartitionTable(block_device=physical)
338+ partition = factory.make_Partition(partition_table=partition_table)
339+ pv = factory.make_Filesystem(
340+ fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition)
341+ vg = factory.make_FilesystemGroup(
342+ filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG)
343+ virtual = factory.make_VirtualBlockDevice(
344+ filesystem_group=vg, node=node1)
345+ factory.make_Filesystem(mount_point='/', block_device=virtual)
346+ self.assertConstrainedNodes([node1], {'storage': '0'})
347+
348+ def test_storage_single_contraint_size_on_virtual(self):
349+ node1 = factory.make_Node(with_boot_disk=False)
350+ physical = factory.make_PhysicalBlockDevice(
351+ node=node1, size=(6 * (1000 ** 3)))
352+ partition_table = factory.make_PartitionTable(block_device=physical)
353+ partition = factory.make_Partition(
354+ partition_table=partition_table, size=(5.5 * (1000 ** 3)))
355+ pv = factory.make_Filesystem(
356+ fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition)
357+ vg = factory.make_FilesystemGroup(
358+ filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG)
359+ virtual = factory.make_VirtualBlockDevice(
360+ filesystem_group=vg, node=node1, size=(5 * (1000 ** 3)))
361+ factory.make_Filesystem(mount_point='/', block_device=virtual)
362+ self.assertConstrainedNodes([node1], {'storage': '4'})
363+
364+ def test_storage_multi_contraint_matches_physical_and_unused(self):
365+ node1 = factory.make_Node(with_boot_disk=False)
366+ factory.make_PhysicalBlockDevice(
367+ node=node1, formatted_root=True)
368+ # 1gb, 2gb, 3gb block device
369+ factory.make_PhysicalBlockDevice(
370+ node=node1, size=1 * (1000 ** 3))
371+ factory.make_PhysicalBlockDevice(
372+ node=node1, size=2 * (1000 ** 3))
373+ factory.make_PhysicalBlockDevice(
374+ node=node1, size=3 * (1000 ** 3))
375+ node2 = factory.make_Node(with_boot_disk=False)
376+ factory.make_PhysicalBlockDevice(
377+ node=node2, formatted_root=True)
378+ # 5gb, 6gb, 7gb block device
379+ factory.make_PhysicalBlockDevice(
380+ node=node2, size=5 * (1000 ** 3))
381+ factory.make_PhysicalBlockDevice(
382+ node=node2, size=6 * (1000 ** 3))
383+ factory.make_PhysicalBlockDevice(
384+ node=node2, size=7 * (1000 ** 3))
385+ node3 = factory.make_Node(with_boot_disk=False)
386+ factory.make_PhysicalBlockDevice(
387+ node=node3, formatted_root=True)
388+ # 8gb, 9gb, 10gb block device
389+ factory.make_PhysicalBlockDevice(
390+ node=node3, size=8 * (1000 ** 3))
391+ factory.make_PhysicalBlockDevice(
392+ node=node3, size=9 * (1000 ** 3))
393+ factory.make_PhysicalBlockDevice(
394+ node=node3, size=10 * (1000 ** 3))
395+ # all nodes with physical devices larger than 2gb
396+ self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'})
397+
398+ def test_storage_multi_contraint_matches_virtual_and_unused(self):
399+ node1 = factory.make_Node(with_boot_disk=False)
400+ factory.make_PhysicalBlockDevice(
401+ node=node1, formatted_root=True)
402+ # 1gb, 2gb, 3gb block device
403+ factory.make_VirtualBlockDevice(
404+ node=node1, size=1 * (1000 ** 3))
405+ factory.make_VirtualBlockDevice(
406+ node=node1, size=2 * (1000 ** 3))
407+ factory.make_VirtualBlockDevice(
408+ node=node1, size=3 * (1000 ** 3))
409+ node2 = factory.make_Node(with_boot_disk=False)
410+ factory.make_PhysicalBlockDevice(
411+ node=node2, formatted_root=True)
412+ # 5gb, 6gb, 7gb block device
413+ factory.make_VirtualBlockDevice(
414+ node=node2, size=5 * (1000 ** 3))
415+ factory.make_VirtualBlockDevice(
416+ node=node2, size=6 * (1000 ** 3))
417+ factory.make_VirtualBlockDevice(
418+ node=node2, size=7 * (1000 ** 3))
419+ node3 = factory.make_Node(with_boot_disk=False)
420+ factory.make_PhysicalBlockDevice(
421+ node=node3, formatted_root=True)
422+ # 8gb, 9gb, 10gb block device
423+ factory.make_VirtualBlockDevice(
424+ node=node3, size=8 * (1000 ** 3))
425+ factory.make_VirtualBlockDevice(
426+ node=node3, size=9 * (1000 ** 3))
427+ factory.make_VirtualBlockDevice(
428+ node=node3, size=10 * (1000 ** 3))
429+ # all nodes with physical devices larger than 2gb
430+ self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'})
431+
432+ def test_storage_multi_contraint_matches_iscsi_and_unused(self):
433+ node1 = factory.make_Node(with_boot_disk=False)
434+ factory.make_PhysicalBlockDevice(
435+ node=node1, formatted_root=True)
436+ # 1gb, 2gb, 3gb block device
437+ factory.make_ISCSIBlockDevice(
438+ node=node1, size=1 * (1000 ** 3))
439+ factory.make_ISCSIBlockDevice(
440+ node=node1, size=2 * (1000 ** 3))
441+ factory.make_ISCSIBlockDevice(
442+ node=node1, size=3 * (1000 ** 3))
443+ node2 = factory.make_Node(with_boot_disk=False)
444+ factory.make_PhysicalBlockDevice(
445+ node=node2, formatted_root=True)
446+ # 5gb, 6gb, 7gb block device
447+ factory.make_ISCSIBlockDevice(
448+ node=node2, size=5 * (1000 ** 3))
449+ factory.make_ISCSIBlockDevice(
450+ node=node2, size=6 * (1000 ** 3))
451+ factory.make_ISCSIBlockDevice(
452+ node=node2, size=7 * (1000 ** 3))
453+ node3 = factory.make_Node(with_boot_disk=False)
454+ factory.make_PhysicalBlockDevice(
455+ node=node3, formatted_root=True)
456+ # 8gb, 9gb, 10gb block device
457+ factory.make_ISCSIBlockDevice(
458+ node=node3, size=8 * (1000 ** 3))
459+ factory.make_ISCSIBlockDevice(
460+ node=node3, size=9 * (1000 ** 3))
461+ factory.make_ISCSIBlockDevice(
462+ node=node3, size=10 * (1000 ** 3))
463+ # all nodes with physical devices larger than 2gb
464+ self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'})
465
466 def test_storage_multi_contraint_matches_on_tags(self):
467 node1 = factory.make_Node(with_boot_disk=False)
468- factory.make_PhysicalBlockDevice(node=node1, tags=['ssd'])
469+ factory.make_PhysicalBlockDevice(
470+ node=node1, tags=['ssd'], formatted_root=True)
471 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd', 'removable'])
472 node2 = factory.make_Node(with_boot_disk=False)
473- factory.make_PhysicalBlockDevice(node=node2, tags=['ssd'])
474+ factory.make_PhysicalBlockDevice(
475+ node=node2, tags=['ssd'], formatted_root=True)
476 factory.make_PhysicalBlockDevice(node=node2, tags=['ssd', 'sata'])
477 self.assertConstrainedNodes(
478 [node1], {'storage': '0(ssd),0(ssd,removable)'})
479@@ -930,7 +1044,7 @@
480 # 1gb, 2gb block device
481 factory.make_PhysicalBlockDevice(
482 node=node1, size=1 * (1000 ** 3),
483- tags=['ssd'])
484+ tags=['ssd'], formatted_root=True)
485 factory.make_PhysicalBlockDevice(
486 node=node1, size=2 * (1000 ** 3),
487 tags=['ssd'])
488@@ -938,65 +1052,81 @@
489 # 4gb, 5gb block device
490 factory.make_PhysicalBlockDevice(
491 node=node2, size=4 * (1000 ** 3),
492- tags=['ssd'])
493+ tags=['ssd'], formatted_root=True)
494 factory.make_PhysicalBlockDevice(
495 node=node2, size=5 * (1000 ** 3),
496 tags=['ssd'])
497 self.assertConstrainedNodes(
498 [node2], {'storage': '3(ssd),3(ssd)'})
499
500- def test_storage_first_constraint_matches_first_blockdevice(self):
501+ def test_storage_first_constraint_matches_blockdevice_with_root(self):
502 """
503 Make sure a constraint like 10(ssd),5,20 will match a node with a
504 11(ssd) first device, a 21 second device and a 10 third device,
505 but not a 5/20/10(ssd) node
506 """
507 node1 = factory.make_Node(with_boot_disk=False)
508- factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3))
509 factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3))
510- factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3),
511- tags=['ssd'])
512+ factory.make_PhysicalBlockDevice(
513+ node=node1, size=11 * (1000 ** 3), tags=['ssd'])
514+ factory.make_PhysicalBlockDevice(
515+ node=node1, size=6 * (1000 ** 3), formatted_root=True)
516 node2 = factory.make_Node(with_boot_disk=False)
517- factory.make_PhysicalBlockDevice(node=node2, size=11 * (1000 ** 3),
518- tags=['ssd'])
519 factory.make_PhysicalBlockDevice(node=node2, size=6 * (1000 ** 3))
520 factory.make_PhysicalBlockDevice(node=node2, size=21 * (1000 ** 3))
521+ factory.make_PhysicalBlockDevice(
522+ node=node2, size=11 * (1000 ** 3),
523+ tags=['ssd'], formatted_root=True)
524 self.assertConstrainedNodes(
525 [node2], {'storage': '10(ssd),5,20'})
526
527 def test_storage_multi_contraint_matches_large_disk_count(self):
528 node1 = factory.make_Node(with_boot_disk=False)
529+ factory.make_PhysicalBlockDevice(node=node1, formatted_root=True)
530 for _ in range(10):
531 factory.make_PhysicalBlockDevice(node=node1)
532 node2 = factory.make_Node(with_boot_disk=False)
533+ factory.make_PhysicalBlockDevice(node=node2, formatted_root=True)
534 for _ in range(5):
535 factory.make_PhysicalBlockDevice(node=node2)
536 self.assertConstrainedNodes(
537 [node1], {'storage': '0,0,0,0,0,0,0,0,0,0'})
538
539- @skip(
540- "XXX: allenap 2015-03-17 bug=1433012: This test keeps failing when "
541- "landing unrelated branches, so has been disabled.")
542 def test_storage_with_named_constraints(self):
543 node1 = factory.make_Node(with_boot_disk=False)
544- factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3),
545- tags=['ssd'])
546- factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3),
547- tags=['rotary', '5400rpm'])
548- factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3))
549- form = AcquireNodeForm({'storage':
550- 'root:10(ssd),data:5(rotary,5400rpm),20'})
551+ physical = factory.make_PhysicalBlockDevice(
552+ node=node1, size=11 * (1000 ** 3))
553+ partition_table = factory.make_PartitionTable(block_device=physical)
554+ partition = factory.make_Partition(
555+ partition_table=partition_table, size=10 * (1000 ** 3))
556+ pv = factory.make_Filesystem(
557+ fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition)
558+ vg = factory.make_FilesystemGroup(
559+ filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG)
560+ virtual = factory.make_VirtualBlockDevice(
561+ filesystem_group=vg, node=node1, size=9 * (1000 ** 3),
562+ tags=['lvm'])
563+ factory.make_Filesystem(mount_point='/', block_device=virtual)
564+ physical = factory.make_PhysicalBlockDevice(
565+ node=node1, size=6 * (1000 ** 3), tags=['rotary', '5400rpm'])
566+ iscsi = factory.make_ISCSIBlockDevice(
567+ node=node1, size=21 * (1000 ** 3))
568+ form = AcquireNodeForm({
569+ 'storage': 'root:8(lvm),physical:5(rotary,5400rpm),iscsi:20'})
570 self.assertTrue(form.is_valid(), form.errors)
571- filtered_nodes, constraint_map = form.filter_nodes(
572+ filtered_nodes, constraint_map, _ = form.filter_nodes(
573 Machine.objects.all())
574 node = filtered_nodes[0]
575- constraints = list(constraint_map[node.id])
576- disk0 = node.physicalblockdevice_set.get(
577- id=constraints[0]) # 1st constraint with name
578- self.assertGreaterEqual(disk0.size, 10 * 1000 ** 3)
579- disk1 = node.physicalblockdevice_set.get(
580- id=constraints[1]) # 2nd constraint with name
581- self.assertGreaterEqual(disk1.size, 5 * 1000 ** 3)
582+ constraints = {
583+ value: key
584+ for key, value in constraint_map[node.id].items()
585+ }
586+ disk0 = node.blockdevice_set.get(id=constraints['root'])
587+ self.assertEquals(virtual.id, disk0.id)
588+ disk1 = node.blockdevice_set.get(id=constraints['physical'])
589+ self.assertEquals(physical.id, disk1.id)
590+ disk2 = node.blockdevice_set.get(id=constraints['iscsi'])
591+ self.assertEquals(iscsi.id, disk2.id)
592
593 def test_fabrics_constraint(self):
594 fabric1 = factory.make_Fabric(name="fabric1")