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 | 686 | status=available_status, owner=None, with_boot_disk=False) | 686 | status=available_status, owner=None, with_boot_disk=False) |
6 | 687 | disk_1 = factory.make_PhysicalBlockDevice( | 687 | disk_1 = factory.make_PhysicalBlockDevice( |
7 | 688 | node=machine, size=(random.randint(8, 16) * (1000 ** 3)), | 688 | node=machine, size=(random.randint(8, 16) * (1000 ** 3)), |
9 | 689 | tags=['local']) | 689 | tags=['local'], formatted_root=True) |
10 | 690 | disk_2 = factory.make_ISCSIBlockDevice( | 690 | disk_2 = factory.make_ISCSIBlockDevice( |
11 | 691 | node=machine, size=(random.randint(8, 16) * (1000 ** 3)), | 691 | node=machine, size=(random.randint(8, 16) * (1000 ** 3)), |
12 | 692 | tags=['iscsi']) | 692 | tags=['iscsi']) |
13 | @@ -1146,11 +1146,9 @@ | |||
14 | 1146 | """Storage label is returned alongside machine data""" | 1146 | """Storage label is returned alongside machine data""" |
15 | 1147 | machine = factory.make_Node( | 1147 | machine = factory.make_Node( |
16 | 1148 | status=NODE_STATUS.READY, with_boot_disk=False) | 1148 | status=NODE_STATUS.READY, with_boot_disk=False) |
17 | 1149 | # The ID may always be '1', which won't be interesting for testing. | ||
18 | 1150 | for _ in range(1, random.choice([1, 3, 5])): | ||
19 | 1151 | factory.make_PhysicalBlockDevice() | ||
20 | 1152 | factory.make_PhysicalBlockDevice( | 1149 | factory.make_PhysicalBlockDevice( |
22 | 1153 | node=machine, size=11 * (1000 ** 3), tags=['ssd']) | 1150 | node=machine, size=11 * (1000 ** 3), tags=['ssd'], |
23 | 1151 | formatted_root=True) | ||
24 | 1154 | response = self.client.post(reverse('machines_handler'), { | 1152 | response = self.client.post(reverse('machines_handler'), { |
25 | 1155 | 'op': 'allocate', | 1153 | 'op': 'allocate', |
26 | 1156 | 'storage': 'needed:10(ssd)', | 1154 | 'storage': 'needed:10(ssd)', |
27 | @@ -1169,11 +1167,9 @@ | |||
28 | 1169 | """Storage label is returned alongside machine data""" | 1167 | """Storage label is returned alongside machine data""" |
29 | 1170 | machine = factory.make_Node( | 1168 | machine = factory.make_Node( |
30 | 1171 | status=NODE_STATUS.READY, with_boot_disk=False) | 1169 | status=NODE_STATUS.READY, with_boot_disk=False) |
31 | 1172 | # The ID may always be '1', which won't be interesting for testing. | ||
32 | 1173 | for _ in range(1, random.choice([1, 3, 5])): | ||
33 | 1174 | factory.make_PhysicalBlockDevice() | ||
34 | 1175 | factory.make_PhysicalBlockDevice( | 1170 | factory.make_PhysicalBlockDevice( |
36 | 1176 | node=machine, size=11 * (1000 ** 3), tags=['ssd']) | 1171 | node=machine, size=11 * (1000 ** 3), tags=['ssd'], |
37 | 1172 | formatted_root=True) | ||
38 | 1177 | response = self.client.post(reverse('machines_handler'), { | 1173 | response = self.client.post(reverse('machines_handler'), { |
39 | 1178 | 'op': 'allocate', | 1174 | 'op': 'allocate', |
40 | 1179 | 'storage': 'needed:10(ssd)', | 1175 | 'storage': 'needed:10(ssd)', |
41 | 1180 | 1176 | ||
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 | 27 | import maasserver.forms as maasserver_forms | 27 | import maasserver.forms as maasserver_forms |
47 | 28 | from maasserver.models import ( | 28 | from maasserver.models import ( |
48 | 29 | BlockDevice, | 29 | BlockDevice, |
49 | 30 | Filesystem, | ||
50 | 30 | Interface, | 31 | Interface, |
51 | 31 | PhysicalBlockDevice, | ||
52 | 32 | Pod, | 32 | Pod, |
53 | 33 | Subnet, | 33 | Subnet, |
54 | 34 | Tag, | 34 | Tag, |
55 | 35 | VirtualBlockDevice, | ||
56 | 36 | VLAN, | 35 | VLAN, |
57 | 37 | Zone, | 36 | Zone, |
58 | 38 | ) | 37 | ) |
59 | @@ -319,71 +318,70 @@ | |||
60 | 319 | root_device = True # The 1st constraint refers to the node's 1st device | 318 | root_device = True # The 1st constraint refers to the node's 1st device |
61 | 320 | for constraint_name, size, tags in constraints: | 319 | for constraint_name, size, tags in constraints: |
62 | 321 | if root_device: | 320 | if root_device: |
65 | 322 | # Sort the `PhysicalBlockDevice`s by id because we consider the | 321 | # This branch of the if is only used on first iteration. |
64 | 323 | # first device as the root device. | ||
66 | 324 | root_device = False | 322 | root_device = False |
68 | 325 | matched_devices = PhysicalBlockDevice.objects.all() | 323 | |
69 | 324 | # Use only block devices that are mounted as '/'. Either the | ||
70 | 325 | # block device has root sitting on it or its on a partition on | ||
71 | 326 | # that block device. | ||
72 | 327 | filesystems = Filesystem.objects.filter( | ||
73 | 328 | mount_point='/', acquired=False) | ||
74 | 329 | filesystems = filesystems.filter( | ||
75 | 330 | Q(block_device__size__gte=size) | | ||
76 | 331 | Q(partition__partition_table__block_device__size__gte=size)) | ||
77 | 332 | if tags is not None: | ||
78 | 333 | filesystems = filesystems.filter( | ||
79 | 334 | Q(block_device__tags__contains=tags) | | ||
80 | 335 | Q(**{ | ||
81 | 336 | 'partition__partition_table__block_device' | ||
82 | 337 | '__tags__contains': tags | ||
83 | 338 | })) | ||
84 | 326 | if node_ids is not None: | 339 | if node_ids is not None: |
88 | 327 | matched_devices = matched_devices.filter(node_id__in=node_ids) | 340 | filesystems = filesystems.filter( |
89 | 328 | matched_devices = matched_devices.order_by('id').values( | 341 | Q(block_device__node_id__in=node_ids) | |
90 | 329 | 'id', 'node_id', 'size', 'tags') | 342 | Q(**{ |
91 | 343 | 'partition__partition_table__block_device' | ||
92 | 344 | '__node_id__in': node_ids | ||
93 | 345 | })) | ||
94 | 346 | filesystems = filesystems.prefetch_related( | ||
95 | 347 | 'block_device', 'partition__partition_table__block_device') | ||
96 | 330 | 348 | ||
97 | 331 | # Only keep the first device for every node. This is done to make | 349 | # Only keep the first device for every node. This is done to make |
98 | 332 | # sure filtering out the size and tags is not done to all the | 350 | # sure filtering out the size and tags is not done to all the |
99 | 333 | # block devices. This should only be done to the first block | 351 | # block devices. This should only be done to the first block |
100 | 334 | # device. | 352 | # device. |
101 | 335 | found_nodes = set() | 353 | found_nodes = set() |
105 | 336 | devices = [] | 354 | matched_devices = [] |
106 | 337 | for device in matched_devices: | 355 | for filesystem in filesystems: |
107 | 338 | if device['node_id'] in found_nodes: | 356 | if filesystem.block_device is not None: |
108 | 357 | device = filesystem.block_device | ||
109 | 358 | else: | ||
110 | 359 | device = ( | ||
111 | 360 | filesystem.partition.partition_table.block_device) | ||
112 | 361 | if device.node_id in found_nodes: | ||
113 | 339 | continue | 362 | continue |
124 | 340 | devices.append(device) | 363 | matched_devices.append(device) |
125 | 341 | found_nodes.add(device['node_id']) | 364 | found_nodes.add(device.node_id) |
126 | 342 | 365 | else: | |
127 | 343 | # Remove the devices that are not of correct size and the devices | 366 | # Query for any block device the closest size and, if specified, |
128 | 344 | # that are missing the correct tags or label. | 367 | # the given tags. # The block device must also be unused in the |
129 | 345 | devices = [ | 368 | # storage model. |
130 | 346 | device | 369 | matched_devices = BlockDevice.objects.filter(size__gte=size) |
131 | 347 | for device in devices | 370 | matched_devices = matched_devices.filter( |
132 | 348 | if device['size'] >= size | 371 | filesystem__isnull=True, partitiontable__isnull=True) |
123 | 349 | ] | ||
133 | 350 | if tags is not None: | 372 | if tags is not None: |
150 | 351 | tags = set(tags) | 373 | matched_devices = matched_devices.filter(tags__contains=tags) |
135 | 352 | devices = [ | ||
136 | 353 | device | ||
137 | 354 | for device in devices | ||
138 | 355 | if tags.issubset(set(device['tags'])) | ||
139 | 356 | ] | ||
140 | 357 | matched_devices = devices | ||
141 | 358 | else: | ||
142 | 359 | # Query for the `PhysicalBlockDevice`s and `ISCSIBlockDevice`'s | ||
143 | 360 | # that have the closest size and, if specified, the given tags. | ||
144 | 361 | if tags is None: | ||
145 | 362 | matched_devices = BlockDevice.objects.filter( | ||
146 | 363 | size__gte=size).order_by('size') | ||
147 | 364 | else: | ||
148 | 365 | matched_devices = BlockDevice.objects.filter_by_tags( | ||
149 | 366 | tags).filter(size__gte=size) | ||
151 | 367 | if node_ids is not None: | 374 | if node_ids is not None: |
152 | 368 | matched_devices = matched_devices.filter( | 375 | matched_devices = matched_devices.filter( |
153 | 369 | node_id__in=node_ids) | 376 | node_id__in=node_ids) |
164 | 370 | matched_devices = [ | 377 | matched_devices = list(matched_devices.order_by('size')) |
155 | 371 | { | ||
156 | 372 | 'id': device.id, | ||
157 | 373 | 'node_id': device.node_id, | ||
158 | 374 | 'size': device.size, | ||
159 | 375 | 'tags': device.tags, | ||
160 | 376 | } | ||
161 | 377 | for device in matched_devices.order_by('size') | ||
162 | 378 | if not isinstance(device.actual_instance, VirtualBlockDevice) | ||
163 | 379 | ] | ||
165 | 380 | 378 | ||
166 | 381 | # Loop through all the returned devices. Insert only the first | 379 | # Loop through all the returned devices. Insert only the first |
167 | 382 | # device from each node into `matches`. | 380 | # device from each node into `matches`. |
168 | 383 | matched_in_loop = [] | 381 | matched_in_loop = [] |
169 | 384 | for device in matched_devices: | 382 | for device in matched_devices: |
172 | 385 | device_id = device['id'] | 383 | device_id = device.id |
173 | 386 | device_node_id = device['node_id'] | 384 | device_node_id = device.node_id |
174 | 387 | 385 | ||
175 | 388 | if device_node_id in matched_in_loop: | 386 | if device_node_id in matched_in_loop: |
176 | 389 | continue | 387 | continue |
177 | 390 | 388 | ||
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 | 1793 | 1793 | ||
183 | 1794 | def make_PhysicalBlockDevice( | 1794 | def make_PhysicalBlockDevice( |
184 | 1795 | self, node=None, name=None, size=None, block_size=None, | 1795 | self, node=None, name=None, size=None, block_size=None, |
186 | 1796 | tags=None, model=None, serial=None, id_path=None): | 1796 | tags=None, model=None, serial=None, id_path=None, |
187 | 1797 | formatted_root=False): | ||
188 | 1797 | if node is None: | 1798 | if node is None: |
189 | 1798 | node = self.make_Node() | 1799 | node = self.make_Node() |
190 | 1799 | if name is None: | 1800 | if name is None: |
191 | @@ -1819,9 +1820,15 @@ | |||
192 | 1819 | else: | 1820 | else: |
193 | 1820 | model = "" | 1821 | model = "" |
194 | 1821 | serial = "" | 1822 | serial = "" |
196 | 1822 | return PhysicalBlockDevice.objects.create( | 1823 | block_device = PhysicalBlockDevice.objects.create( |
197 | 1823 | node=node, name=name, size=size, block_size=block_size, | 1824 | node=node, name=name, size=size, block_size=block_size, |
198 | 1824 | tags=tags, model=model, serial=serial, id_path=id_path) | 1825 | tags=tags, model=model, serial=serial, id_path=id_path) |
199 | 1826 | if formatted_root: | ||
200 | 1827 | partition = self.make_Partition( | ||
201 | 1828 | partition_table=( | ||
202 | 1829 | self.make_PartitionTable(block_device=block_device))) | ||
203 | 1830 | self.make_Filesystem(mount_point='/', partition=partition) | ||
204 | 1831 | return block_device | ||
205 | 1825 | 1832 | ||
206 | 1826 | def make_PartitionTable( | 1833 | def make_PartitionTable( |
207 | 1827 | self, table_type=None, block_device=None, node=None, | 1834 | self, table_type=None, block_device=None, node=None, |
208 | 1828 | 1835 | ||
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 | 6 | __all__ = [] | 6 | __all__ = [] |
214 | 7 | 7 | ||
215 | 8 | from random import randint | 8 | from random import randint |
216 | 9 | from unittest import skip | ||
217 | 10 | 9 | ||
218 | 11 | from django import forms | 10 | from django import forms |
219 | 12 | from django.core.exceptions import ValidationError | 11 | from django.core.exceptions import ValidationError |
220 | 13 | from maasserver.enum import ( | 12 | from maasserver.enum import ( |
221 | 13 | FILESYSTEM_GROUP_TYPE, | ||
222 | 14 | FILESYSTEM_TYPE, | ||
223 | 14 | INTERFACE_TYPE, | 15 | INTERFACE_TYPE, |
224 | 15 | IPADDRESS_TYPE, | 16 | IPADDRESS_TYPE, |
225 | 16 | NODE_STATUS, | 17 | NODE_STATUS, |
226 | @@ -835,34 +836,50 @@ | |||
227 | 835 | ['Malformed storage constraint, "abc".']}), | 836 | ['Malformed storage constraint, "abc".']}), |
228 | 836 | (form.is_valid(), form.errors)) | 837 | (form.is_valid(), form.errors)) |
229 | 837 | 838 | ||
231 | 838 | def test_storage_single_contraint_only_matches_physical_devices(self): | 839 | def test_storage_matches_disk_with_root_mount_on_disk(self): |
232 | 839 | node1 = factory.make_Node(with_boot_disk=False) | 840 | node1 = factory.make_Node(with_boot_disk=False) |
233 | 840 | factory.make_PhysicalBlockDevice(node=node1) | 841 | factory.make_PhysicalBlockDevice(node=node1) |
236 | 841 | node2 = factory.make_Node(with_boot_disk=False) | 842 | block_device = factory.make_PhysicalBlockDevice(node=node1) |
237 | 842 | factory.make_BlockDevice(node=node2) | 843 | factory.make_Filesystem(mount_point='/', block_device=block_device) |
238 | 844 | node2 = factory.make_Node(with_boot_disk=False) | ||
239 | 845 | factory.make_PhysicalBlockDevice(node=node2) | ||
240 | 846 | self.assertConstrainedNodes([node1], {'storage': '0'}) | ||
241 | 847 | |||
242 | 848 | def test_storage_matches_disk_with_root_mount_on_partition(self): | ||
243 | 849 | node1 = factory.make_Node(with_boot_disk=False) | ||
244 | 850 | factory.make_PhysicalBlockDevice( | ||
245 | 851 | node=node1, formatted_root=True) | ||
246 | 852 | node2 = factory.make_Node(with_boot_disk=False) | ||
247 | 853 | block_device = factory.make_PhysicalBlockDevice(node=node2) | ||
248 | 854 | partition_table = factory.make_PartitionTable( | ||
249 | 855 | block_device=block_device) | ||
250 | 856 | partition = factory.make_Partition(partition_table=partition_table) | ||
251 | 857 | factory.make_Filesystem(mount_point='/srv', partition=partition) | ||
252 | 843 | self.assertConstrainedNodes([node1], {'storage': '0'}) | 858 | self.assertConstrainedNodes([node1], {'storage': '0'}) |
253 | 844 | 859 | ||
254 | 845 | def test_storage_single_contraint_matches_all_sizes_larger(self): | 860 | def test_storage_single_contraint_matches_all_sizes_larger(self): |
255 | 846 | node1 = factory.make_Node(with_boot_disk=False) | 861 | node1 = factory.make_Node(with_boot_disk=False) |
256 | 847 | # 1gb block device | 862 | # 1gb block device |
257 | 848 | factory.make_PhysicalBlockDevice( | 863 | factory.make_PhysicalBlockDevice( |
259 | 849 | node=node1, size=1 * (1000 ** 3)) | 864 | node=node1, size=1 * (1000 ** 3), formatted_root=True) |
260 | 850 | node2 = factory.make_Node(with_boot_disk=False) | 865 | node2 = factory.make_Node(with_boot_disk=False) |
261 | 851 | # 4gb block device | 866 | # 4gb block device |
262 | 852 | factory.make_PhysicalBlockDevice( | 867 | factory.make_PhysicalBlockDevice( |
264 | 853 | node=node2, size=4 * (1000 ** 3)) | 868 | node=node2, size=4 * (1000 ** 3), formatted_root=True) |
265 | 854 | node3 = factory.make_Node(with_boot_disk=False) | 869 | node3 = factory.make_Node(with_boot_disk=False) |
266 | 855 | # 8gb block device | 870 | # 8gb block device |
267 | 856 | factory.make_PhysicalBlockDevice( | 871 | factory.make_PhysicalBlockDevice( |
269 | 857 | node=node3, size=8 * (1000 ** 3)) | 872 | node=node3, size=8 * (1000 ** 3), formatted_root=True) |
270 | 858 | # all nodes with physical devices larger than 2gb | 873 | # all nodes with physical devices larger than 2gb |
271 | 859 | self.assertConstrainedNodes([node2, node3], {'storage': '2'}) | 874 | self.assertConstrainedNodes([node2, node3], {'storage': '2'}) |
272 | 860 | 875 | ||
273 | 861 | def test_storage_single_contraint_matches_on_tags(self): | 876 | def test_storage_single_contraint_matches_on_tags(self): |
274 | 862 | node1 = factory.make_Node(with_boot_disk=False) | 877 | node1 = factory.make_Node(with_boot_disk=False) |
276 | 863 | factory.make_PhysicalBlockDevice(node=node1, tags=['ssd']) | 878 | factory.make_PhysicalBlockDevice( |
277 | 879 | node=node1, tags=['ssd'], formatted_root=True) | ||
278 | 864 | node2 = factory.make_Node(with_boot_disk=False) | 880 | node2 = factory.make_Node(with_boot_disk=False) |
280 | 865 | factory.make_PhysicalBlockDevice(node=node2, tags=['rotary']) | 881 | factory.make_PhysicalBlockDevice( |
281 | 882 | node=node2, tags=['rotary'], formatted_root=True) | ||
282 | 866 | self.assertConstrainedNodes([node1], {'storage': '0(ssd)'}) | 883 | self.assertConstrainedNodes([node1], {'storage': '0(ssd)'}) |
283 | 867 | 884 | ||
284 | 868 | def test_storage_single_contraint_matches_decimal_size(self): | 885 | def test_storage_single_contraint_matches_decimal_size(self): |
285 | @@ -871,56 +888,153 @@ | |||
286 | 871 | factory.make_PhysicalBlockDevice( | 888 | factory.make_PhysicalBlockDevice( |
287 | 872 | node=node1, size=2 * (1000 ** 3)) | 889 | node=node1, size=2 * (1000 ** 3)) |
288 | 873 | factory.make_PhysicalBlockDevice( | 890 | factory.make_PhysicalBlockDevice( |
290 | 874 | node=node1, size=4 * (1000 ** 3)) | 891 | node=node1, size=4 * (1000 ** 3), formatted_root=True) |
291 | 875 | node2 = factory.make_Node(with_boot_disk=False) | 892 | node2 = factory.make_Node(with_boot_disk=False) |
292 | 876 | # 1gb block device | 893 | # 1gb block device |
293 | 877 | factory.make_PhysicalBlockDevice( | 894 | factory.make_PhysicalBlockDevice( |
295 | 878 | node=node2, size=1 * (1000 ** 3)) | 895 | node=node2, size=1 * (1000 ** 3), formatted_root=True) |
296 | 879 | self.assertConstrainedNodes([node1], {'storage': '1.5'}) | 896 | self.assertConstrainedNodes([node1], {'storage': '1.5'}) |
297 | 880 | 897 | ||
334 | 881 | def test_storage_multi_contraint_only_matches_physical_devices(self): | 898 | def test_storage_single_contraint_allows_root_on_virtual(self): |
335 | 882 | node1 = factory.make_Node(with_boot_disk=False) | 899 | node1 = factory.make_Node(with_boot_disk=False) |
336 | 883 | factory.make_PhysicalBlockDevice(node=node1) | 900 | physical = factory.make_PhysicalBlockDevice(node=node1) |
337 | 884 | factory.make_PhysicalBlockDevice(node=node1) | 901 | partition_table = factory.make_PartitionTable(block_device=physical) |
338 | 885 | node2 = factory.make_Node(with_boot_disk=False) | 902 | partition = factory.make_Partition(partition_table=partition_table) |
339 | 886 | factory.make_BlockDevice(node=node2) | 903 | pv = factory.make_Filesystem( |
340 | 887 | factory.make_BlockDevice(node=node2) | 904 | fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition) |
341 | 888 | self.assertConstrainedNodes([node1], {'storage': '0,0'}) | 905 | vg = factory.make_FilesystemGroup( |
342 | 889 | 906 | filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG) | |
343 | 890 | def test_storage_multi_contraint_matches_all_sizes_larger(self): | 907 | virtual = factory.make_VirtualBlockDevice( |
344 | 891 | node1 = factory.make_Node(with_boot_disk=False) | 908 | filesystem_group=vg, node=node1) |
345 | 892 | # 1gb, 2gb, 3gb block device | 909 | factory.make_Filesystem(mount_point='/', block_device=virtual) |
346 | 893 | factory.make_PhysicalBlockDevice( | 910 | self.assertConstrainedNodes([node1], {'storage': '0'}) |
347 | 894 | node=node1, size=1 * (1000 ** 3)) | 911 | |
348 | 895 | factory.make_PhysicalBlockDevice( | 912 | def test_storage_single_contraint_size_on_virtual(self): |
349 | 896 | node=node1, size=2 * (1000 ** 3)) | 913 | node1 = factory.make_Node(with_boot_disk=False) |
350 | 897 | factory.make_PhysicalBlockDevice( | 914 | physical = factory.make_PhysicalBlockDevice( |
351 | 898 | node=node1, size=3 * (1000 ** 3)) | 915 | node=node1, size=(6 * (1000 ** 3))) |
352 | 899 | node2 = factory.make_Node(with_boot_disk=False) | 916 | partition_table = factory.make_PartitionTable(block_device=physical) |
353 | 900 | # 5gb, 6gb, 7gb block device | 917 | partition = factory.make_Partition( |
354 | 901 | factory.make_PhysicalBlockDevice( | 918 | partition_table=partition_table, size=(5.5 * (1000 ** 3))) |
355 | 902 | node=node2, size=5 * (1000 ** 3)) | 919 | pv = factory.make_Filesystem( |
356 | 903 | factory.make_PhysicalBlockDevice( | 920 | fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition) |
357 | 904 | node=node2, size=6 * (1000 ** 3)) | 921 | vg = factory.make_FilesystemGroup( |
358 | 905 | factory.make_PhysicalBlockDevice( | 922 | filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG) |
359 | 906 | node=node2, size=7 * (1000 ** 3)) | 923 | virtual = factory.make_VirtualBlockDevice( |
360 | 907 | node3 = factory.make_Node(with_boot_disk=False) | 924 | filesystem_group=vg, node=node1, size=(5 * (1000 ** 3))) |
361 | 908 | # 8gb, 9gb, 10gb block device | 925 | factory.make_Filesystem(mount_point='/', block_device=virtual) |
362 | 909 | factory.make_PhysicalBlockDevice( | 926 | self.assertConstrainedNodes([node1], {'storage': '4'}) |
363 | 910 | node=node3, size=8 * (1000 ** 3)) | 927 | |
364 | 911 | factory.make_PhysicalBlockDevice( | 928 | def test_storage_multi_contraint_matches_physical_and_unused(self): |
365 | 912 | node=node3, size=9 * (1000 ** 3)) | 929 | node1 = factory.make_Node(with_boot_disk=False) |
366 | 913 | factory.make_PhysicalBlockDevice( | 930 | factory.make_PhysicalBlockDevice( |
367 | 914 | node=node3, size=10 * (1000 ** 3)) | 931 | node=node1, formatted_root=True) |
368 | 915 | # all nodes with physical devices larger than 2gb | 932 | # 1gb, 2gb, 3gb block device |
369 | 916 | self.assertConstrainedNodes([node2, node3], {'storage': '4,4,4'}) | 933 | factory.make_PhysicalBlockDevice( |
370 | 934 | node=node1, size=1 * (1000 ** 3)) | ||
371 | 935 | factory.make_PhysicalBlockDevice( | ||
372 | 936 | node=node1, size=2 * (1000 ** 3)) | ||
373 | 937 | factory.make_PhysicalBlockDevice( | ||
374 | 938 | node=node1, size=3 * (1000 ** 3)) | ||
375 | 939 | node2 = factory.make_Node(with_boot_disk=False) | ||
376 | 940 | factory.make_PhysicalBlockDevice( | ||
377 | 941 | node=node2, formatted_root=True) | ||
378 | 942 | # 5gb, 6gb, 7gb block device | ||
379 | 943 | factory.make_PhysicalBlockDevice( | ||
380 | 944 | node=node2, size=5 * (1000 ** 3)) | ||
381 | 945 | factory.make_PhysicalBlockDevice( | ||
382 | 946 | node=node2, size=6 * (1000 ** 3)) | ||
383 | 947 | factory.make_PhysicalBlockDevice( | ||
384 | 948 | node=node2, size=7 * (1000 ** 3)) | ||
385 | 949 | node3 = factory.make_Node(with_boot_disk=False) | ||
386 | 950 | factory.make_PhysicalBlockDevice( | ||
387 | 951 | node=node3, formatted_root=True) | ||
388 | 952 | # 8gb, 9gb, 10gb block device | ||
389 | 953 | factory.make_PhysicalBlockDevice( | ||
390 | 954 | node=node3, size=8 * (1000 ** 3)) | ||
391 | 955 | factory.make_PhysicalBlockDevice( | ||
392 | 956 | node=node3, size=9 * (1000 ** 3)) | ||
393 | 957 | factory.make_PhysicalBlockDevice( | ||
394 | 958 | node=node3, size=10 * (1000 ** 3)) | ||
395 | 959 | # all nodes with physical devices larger than 2gb | ||
396 | 960 | self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'}) | ||
397 | 961 | |||
398 | 962 | def test_storage_multi_contraint_matches_virtual_and_unused(self): | ||
399 | 963 | node1 = factory.make_Node(with_boot_disk=False) | ||
400 | 964 | factory.make_PhysicalBlockDevice( | ||
401 | 965 | node=node1, formatted_root=True) | ||
402 | 966 | # 1gb, 2gb, 3gb block device | ||
403 | 967 | factory.make_VirtualBlockDevice( | ||
404 | 968 | node=node1, size=1 * (1000 ** 3)) | ||
405 | 969 | factory.make_VirtualBlockDevice( | ||
406 | 970 | node=node1, size=2 * (1000 ** 3)) | ||
407 | 971 | factory.make_VirtualBlockDevice( | ||
408 | 972 | node=node1, size=3 * (1000 ** 3)) | ||
409 | 973 | node2 = factory.make_Node(with_boot_disk=False) | ||
410 | 974 | factory.make_PhysicalBlockDevice( | ||
411 | 975 | node=node2, formatted_root=True) | ||
412 | 976 | # 5gb, 6gb, 7gb block device | ||
413 | 977 | factory.make_VirtualBlockDevice( | ||
414 | 978 | node=node2, size=5 * (1000 ** 3)) | ||
415 | 979 | factory.make_VirtualBlockDevice( | ||
416 | 980 | node=node2, size=6 * (1000 ** 3)) | ||
417 | 981 | factory.make_VirtualBlockDevice( | ||
418 | 982 | node=node2, size=7 * (1000 ** 3)) | ||
419 | 983 | node3 = factory.make_Node(with_boot_disk=False) | ||
420 | 984 | factory.make_PhysicalBlockDevice( | ||
421 | 985 | node=node3, formatted_root=True) | ||
422 | 986 | # 8gb, 9gb, 10gb block device | ||
423 | 987 | factory.make_VirtualBlockDevice( | ||
424 | 988 | node=node3, size=8 * (1000 ** 3)) | ||
425 | 989 | factory.make_VirtualBlockDevice( | ||
426 | 990 | node=node3, size=9 * (1000 ** 3)) | ||
427 | 991 | factory.make_VirtualBlockDevice( | ||
428 | 992 | node=node3, size=10 * (1000 ** 3)) | ||
429 | 993 | # all nodes with physical devices larger than 2gb | ||
430 | 994 | self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'}) | ||
431 | 995 | |||
432 | 996 | def test_storage_multi_contraint_matches_iscsi_and_unused(self): | ||
433 | 997 | node1 = factory.make_Node(with_boot_disk=False) | ||
434 | 998 | factory.make_PhysicalBlockDevice( | ||
435 | 999 | node=node1, formatted_root=True) | ||
436 | 1000 | # 1gb, 2gb, 3gb block device | ||
437 | 1001 | factory.make_ISCSIBlockDevice( | ||
438 | 1002 | node=node1, size=1 * (1000 ** 3)) | ||
439 | 1003 | factory.make_ISCSIBlockDevice( | ||
440 | 1004 | node=node1, size=2 * (1000 ** 3)) | ||
441 | 1005 | factory.make_ISCSIBlockDevice( | ||
442 | 1006 | node=node1, size=3 * (1000 ** 3)) | ||
443 | 1007 | node2 = factory.make_Node(with_boot_disk=False) | ||
444 | 1008 | factory.make_PhysicalBlockDevice( | ||
445 | 1009 | node=node2, formatted_root=True) | ||
446 | 1010 | # 5gb, 6gb, 7gb block device | ||
447 | 1011 | factory.make_ISCSIBlockDevice( | ||
448 | 1012 | node=node2, size=5 * (1000 ** 3)) | ||
449 | 1013 | factory.make_ISCSIBlockDevice( | ||
450 | 1014 | node=node2, size=6 * (1000 ** 3)) | ||
451 | 1015 | factory.make_ISCSIBlockDevice( | ||
452 | 1016 | node=node2, size=7 * (1000 ** 3)) | ||
453 | 1017 | node3 = factory.make_Node(with_boot_disk=False) | ||
454 | 1018 | factory.make_PhysicalBlockDevice( | ||
455 | 1019 | node=node3, formatted_root=True) | ||
456 | 1020 | # 8gb, 9gb, 10gb block device | ||
457 | 1021 | factory.make_ISCSIBlockDevice( | ||
458 | 1022 | node=node3, size=8 * (1000 ** 3)) | ||
459 | 1023 | factory.make_ISCSIBlockDevice( | ||
460 | 1024 | node=node3, size=9 * (1000 ** 3)) | ||
461 | 1025 | factory.make_ISCSIBlockDevice( | ||
462 | 1026 | node=node3, size=10 * (1000 ** 3)) | ||
463 | 1027 | # all nodes with physical devices larger than 2gb | ||
464 | 1028 | self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'}) | ||
465 | 917 | 1029 | ||
466 | 918 | def test_storage_multi_contraint_matches_on_tags(self): | 1030 | def test_storage_multi_contraint_matches_on_tags(self): |
467 | 919 | node1 = factory.make_Node(with_boot_disk=False) | 1031 | node1 = factory.make_Node(with_boot_disk=False) |
469 | 920 | factory.make_PhysicalBlockDevice(node=node1, tags=['ssd']) | 1032 | factory.make_PhysicalBlockDevice( |
470 | 1033 | node=node1, tags=['ssd'], formatted_root=True) | ||
471 | 921 | factory.make_PhysicalBlockDevice(node=node1, tags=['ssd', 'removable']) | 1034 | factory.make_PhysicalBlockDevice(node=node1, tags=['ssd', 'removable']) |
472 | 922 | node2 = factory.make_Node(with_boot_disk=False) | 1035 | node2 = factory.make_Node(with_boot_disk=False) |
474 | 923 | factory.make_PhysicalBlockDevice(node=node2, tags=['ssd']) | 1036 | factory.make_PhysicalBlockDevice( |
475 | 1037 | node=node2, tags=['ssd'], formatted_root=True) | ||
476 | 924 | factory.make_PhysicalBlockDevice(node=node2, tags=['ssd', 'sata']) | 1038 | factory.make_PhysicalBlockDevice(node=node2, tags=['ssd', 'sata']) |
477 | 925 | self.assertConstrainedNodes( | 1039 | self.assertConstrainedNodes( |
478 | 926 | [node1], {'storage': '0(ssd),0(ssd,removable)'}) | 1040 | [node1], {'storage': '0(ssd),0(ssd,removable)'}) |
479 | @@ -930,7 +1044,7 @@ | |||
480 | 930 | # 1gb, 2gb block device | 1044 | # 1gb, 2gb block device |
481 | 931 | factory.make_PhysicalBlockDevice( | 1045 | factory.make_PhysicalBlockDevice( |
482 | 932 | node=node1, size=1 * (1000 ** 3), | 1046 | node=node1, size=1 * (1000 ** 3), |
484 | 933 | tags=['ssd']) | 1047 | tags=['ssd'], formatted_root=True) |
485 | 934 | factory.make_PhysicalBlockDevice( | 1048 | factory.make_PhysicalBlockDevice( |
486 | 935 | node=node1, size=2 * (1000 ** 3), | 1049 | node=node1, size=2 * (1000 ** 3), |
487 | 936 | tags=['ssd']) | 1050 | tags=['ssd']) |
488 | @@ -938,65 +1052,81 @@ | |||
489 | 938 | # 4gb, 5gb block device | 1052 | # 4gb, 5gb block device |
490 | 939 | factory.make_PhysicalBlockDevice( | 1053 | factory.make_PhysicalBlockDevice( |
491 | 940 | node=node2, size=4 * (1000 ** 3), | 1054 | node=node2, size=4 * (1000 ** 3), |
493 | 941 | tags=['ssd']) | 1055 | tags=['ssd'], formatted_root=True) |
494 | 942 | factory.make_PhysicalBlockDevice( | 1056 | factory.make_PhysicalBlockDevice( |
495 | 943 | node=node2, size=5 * (1000 ** 3), | 1057 | node=node2, size=5 * (1000 ** 3), |
496 | 944 | tags=['ssd']) | 1058 | tags=['ssd']) |
497 | 945 | self.assertConstrainedNodes( | 1059 | self.assertConstrainedNodes( |
498 | 946 | [node2], {'storage': '3(ssd),3(ssd)'}) | 1060 | [node2], {'storage': '3(ssd),3(ssd)'}) |
499 | 947 | 1061 | ||
501 | 948 | def test_storage_first_constraint_matches_first_blockdevice(self): | 1062 | def test_storage_first_constraint_matches_blockdevice_with_root(self): |
502 | 949 | """ | 1063 | """ |
503 | 950 | Make sure a constraint like 10(ssd),5,20 will match a node with a | 1064 | Make sure a constraint like 10(ssd),5,20 will match a node with a |
504 | 951 | 11(ssd) first device, a 21 second device and a 10 third device, | 1065 | 11(ssd) first device, a 21 second device and a 10 third device, |
505 | 952 | but not a 5/20/10(ssd) node | 1066 | but not a 5/20/10(ssd) node |
506 | 953 | """ | 1067 | """ |
507 | 954 | node1 = factory.make_Node(with_boot_disk=False) | 1068 | node1 = factory.make_Node(with_boot_disk=False) |
508 | 955 | factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3)) | ||
509 | 956 | factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3)) | 1069 | factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3)) |
512 | 957 | factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3), | 1070 | factory.make_PhysicalBlockDevice( |
513 | 958 | tags=['ssd']) | 1071 | node=node1, size=11 * (1000 ** 3), tags=['ssd']) |
514 | 1072 | factory.make_PhysicalBlockDevice( | ||
515 | 1073 | node=node1, size=6 * (1000 ** 3), formatted_root=True) | ||
516 | 959 | node2 = factory.make_Node(with_boot_disk=False) | 1074 | node2 = factory.make_Node(with_boot_disk=False) |
517 | 960 | factory.make_PhysicalBlockDevice(node=node2, size=11 * (1000 ** 3), | ||
518 | 961 | tags=['ssd']) | ||
519 | 962 | factory.make_PhysicalBlockDevice(node=node2, size=6 * (1000 ** 3)) | 1075 | factory.make_PhysicalBlockDevice(node=node2, size=6 * (1000 ** 3)) |
520 | 963 | factory.make_PhysicalBlockDevice(node=node2, size=21 * (1000 ** 3)) | 1076 | factory.make_PhysicalBlockDevice(node=node2, size=21 * (1000 ** 3)) |
521 | 1077 | factory.make_PhysicalBlockDevice( | ||
522 | 1078 | node=node2, size=11 * (1000 ** 3), | ||
523 | 1079 | tags=['ssd'], formatted_root=True) | ||
524 | 964 | self.assertConstrainedNodes( | 1080 | self.assertConstrainedNodes( |
525 | 965 | [node2], {'storage': '10(ssd),5,20'}) | 1081 | [node2], {'storage': '10(ssd),5,20'}) |
526 | 966 | 1082 | ||
527 | 967 | def test_storage_multi_contraint_matches_large_disk_count(self): | 1083 | def test_storage_multi_contraint_matches_large_disk_count(self): |
528 | 968 | node1 = factory.make_Node(with_boot_disk=False) | 1084 | node1 = factory.make_Node(with_boot_disk=False) |
529 | 1085 | factory.make_PhysicalBlockDevice(node=node1, formatted_root=True) | ||
530 | 969 | for _ in range(10): | 1086 | for _ in range(10): |
531 | 970 | factory.make_PhysicalBlockDevice(node=node1) | 1087 | factory.make_PhysicalBlockDevice(node=node1) |
532 | 971 | node2 = factory.make_Node(with_boot_disk=False) | 1088 | node2 = factory.make_Node(with_boot_disk=False) |
533 | 1089 | factory.make_PhysicalBlockDevice(node=node2, formatted_root=True) | ||
534 | 972 | for _ in range(5): | 1090 | for _ in range(5): |
535 | 973 | factory.make_PhysicalBlockDevice(node=node2) | 1091 | factory.make_PhysicalBlockDevice(node=node2) |
536 | 974 | self.assertConstrainedNodes( | 1092 | self.assertConstrainedNodes( |
537 | 975 | [node1], {'storage': '0,0,0,0,0,0,0,0,0,0'}) | 1093 | [node1], {'storage': '0,0,0,0,0,0,0,0,0,0'}) |
538 | 976 | 1094 | ||
539 | 977 | @skip( | ||
540 | 978 | "XXX: allenap 2015-03-17 bug=1433012: This test keeps failing when " | ||
541 | 979 | "landing unrelated branches, so has been disabled.") | ||
542 | 980 | def test_storage_with_named_constraints(self): | 1095 | def test_storage_with_named_constraints(self): |
543 | 981 | node1 = factory.make_Node(with_boot_disk=False) | 1096 | node1 = factory.make_Node(with_boot_disk=False) |
551 | 982 | factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3), | 1097 | physical = factory.make_PhysicalBlockDevice( |
552 | 983 | tags=['ssd']) | 1098 | node=node1, size=11 * (1000 ** 3)) |
553 | 984 | factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3), | 1099 | partition_table = factory.make_PartitionTable(block_device=physical) |
554 | 985 | tags=['rotary', '5400rpm']) | 1100 | partition = factory.make_Partition( |
555 | 986 | factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3)) | 1101 | partition_table=partition_table, size=10 * (1000 ** 3)) |
556 | 987 | form = AcquireNodeForm({'storage': | 1102 | pv = factory.make_Filesystem( |
557 | 988 | 'root:10(ssd),data:5(rotary,5400rpm),20'}) | 1103 | fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition) |
558 | 1104 | vg = factory.make_FilesystemGroup( | ||
559 | 1105 | filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG) | ||
560 | 1106 | virtual = factory.make_VirtualBlockDevice( | ||
561 | 1107 | filesystem_group=vg, node=node1, size=9 * (1000 ** 3), | ||
562 | 1108 | tags=['lvm']) | ||
563 | 1109 | factory.make_Filesystem(mount_point='/', block_device=virtual) | ||
564 | 1110 | physical = factory.make_PhysicalBlockDevice( | ||
565 | 1111 | node=node1, size=6 * (1000 ** 3), tags=['rotary', '5400rpm']) | ||
566 | 1112 | iscsi = factory.make_ISCSIBlockDevice( | ||
567 | 1113 | node=node1, size=21 * (1000 ** 3)) | ||
568 | 1114 | form = AcquireNodeForm({ | ||
569 | 1115 | 'storage': 'root:8(lvm),physical:5(rotary,5400rpm),iscsi:20'}) | ||
570 | 989 | self.assertTrue(form.is_valid(), form.errors) | 1116 | self.assertTrue(form.is_valid(), form.errors) |
572 | 990 | filtered_nodes, constraint_map = form.filter_nodes( | 1117 | filtered_nodes, constraint_map, _ = form.filter_nodes( |
573 | 991 | Machine.objects.all()) | 1118 | Machine.objects.all()) |
574 | 992 | node = filtered_nodes[0] | 1119 | node = filtered_nodes[0] |
582 | 993 | constraints = list(constraint_map[node.id]) | 1120 | constraints = { |
583 | 994 | disk0 = node.physicalblockdevice_set.get( | 1121 | value: key |
584 | 995 | id=constraints[0]) # 1st constraint with name | 1122 | for key, value in constraint_map[node.id].items() |
585 | 996 | self.assertGreaterEqual(disk0.size, 10 * 1000 ** 3) | 1123 | } |
586 | 997 | disk1 = node.physicalblockdevice_set.get( | 1124 | disk0 = node.blockdevice_set.get(id=constraints['root']) |
587 | 998 | id=constraints[1]) # 2nd constraint with name | 1125 | self.assertEquals(virtual.id, disk0.id) |
588 | 999 | self.assertGreaterEqual(disk1.size, 5 * 1000 ** 3) | 1126 | disk1 = node.blockdevice_set.get(id=constraints['physical']) |
589 | 1127 | self.assertEquals(physical.id, disk1.id) | ||
590 | 1128 | disk2 = node.blockdevice_set.get(id=constraints['iscsi']) | ||
591 | 1129 | self.assertEquals(iscsi.id, disk2.id) | ||
592 | 1000 | 1130 | ||
593 | 1001 | def test_fabrics_constraint(self): | 1131 | def test_fabrics_constraint(self): |
594 | 1002 | fabric1 = factory.make_Fabric(name="fabric1") | 1132 | fabric1 = factory.make_Fabric(name="fabric1") |
lgtm!