Merge lp:~blake-rouse/maas/fix-1674148 into lp:~maas-committers/maas/trunk
- fix-1674148
- Merge into 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 |
Related bugs: |
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.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '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") |
lgtm!