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
=== modified file 'src/maasserver/api/tests/test_machines.py'
--- src/maasserver/api/tests/test_machines.py 2017-04-05 21:06:53 +0000
+++ src/maasserver/api/tests/test_machines.py 2017-04-11 16:17:53 +0000
@@ -686,7 +686,7 @@
686 status=available_status, owner=None, with_boot_disk=False)686 status=available_status, owner=None, with_boot_disk=False)
687 disk_1 = factory.make_PhysicalBlockDevice(687 disk_1 = factory.make_PhysicalBlockDevice(
688 node=machine, size=(random.randint(8, 16) * (1000 ** 3)),688 node=machine, size=(random.randint(8, 16) * (1000 ** 3)),
689 tags=['local'])689 tags=['local'], formatted_root=True)
690 disk_2 = factory.make_ISCSIBlockDevice(690 disk_2 = factory.make_ISCSIBlockDevice(
691 node=machine, size=(random.randint(8, 16) * (1000 ** 3)),691 node=machine, size=(random.randint(8, 16) * (1000 ** 3)),
692 tags=['iscsi'])692 tags=['iscsi'])
@@ -1146,11 +1146,9 @@
1146 """Storage label is returned alongside machine data"""1146 """Storage label is returned alongside machine data"""
1147 machine = factory.make_Node(1147 machine = factory.make_Node(
1148 status=NODE_STATUS.READY, with_boot_disk=False)1148 status=NODE_STATUS.READY, with_boot_disk=False)
1149 # The ID may always be '1', which won't be interesting for testing.
1150 for _ in range(1, random.choice([1, 3, 5])):
1151 factory.make_PhysicalBlockDevice()
1152 factory.make_PhysicalBlockDevice(1149 factory.make_PhysicalBlockDevice(
1153 node=machine, size=11 * (1000 ** 3), tags=['ssd'])1150 node=machine, size=11 * (1000 ** 3), tags=['ssd'],
1151 formatted_root=True)
1154 response = self.client.post(reverse('machines_handler'), {1152 response = self.client.post(reverse('machines_handler'), {
1155 'op': 'allocate',1153 'op': 'allocate',
1156 'storage': 'needed:10(ssd)',1154 'storage': 'needed:10(ssd)',
@@ -1169,11 +1167,9 @@
1169 """Storage label is returned alongside machine data"""1167 """Storage label is returned alongside machine data"""
1170 machine = factory.make_Node(1168 machine = factory.make_Node(
1171 status=NODE_STATUS.READY, with_boot_disk=False)1169 status=NODE_STATUS.READY, with_boot_disk=False)
1172 # The ID may always be '1', which won't be interesting for testing.
1173 for _ in range(1, random.choice([1, 3, 5])):
1174 factory.make_PhysicalBlockDevice()
1175 factory.make_PhysicalBlockDevice(1170 factory.make_PhysicalBlockDevice(
1176 node=machine, size=11 * (1000 ** 3), tags=['ssd'])1171 node=machine, size=11 * (1000 ** 3), tags=['ssd'],
1172 formatted_root=True)
1177 response = self.client.post(reverse('machines_handler'), {1173 response = self.client.post(reverse('machines_handler'), {
1178 'op': 'allocate',1174 'op': 'allocate',
1179 'storage': 'needed:10(ssd)',1175 'storage': 'needed:10(ssd)',
11801176
=== modified file 'src/maasserver/node_constraint_filter_forms.py'
--- src/maasserver/node_constraint_filter_forms.py 2017-04-05 13:41:28 +0000
+++ src/maasserver/node_constraint_filter_forms.py 2017-04-11 16:17:53 +0000
@@ -27,12 +27,11 @@
27import maasserver.forms as maasserver_forms27import maasserver.forms as maasserver_forms
28from maasserver.models import (28from maasserver.models import (
29 BlockDevice,29 BlockDevice,
30 Filesystem,
30 Interface,31 Interface,
31 PhysicalBlockDevice,
32 Pod,32 Pod,
33 Subnet,33 Subnet,
34 Tag,34 Tag,
35 VirtualBlockDevice,
36 VLAN,35 VLAN,
37 Zone,36 Zone,
38)37)
@@ -319,71 +318,70 @@
319 root_device = True # The 1st constraint refers to the node's 1st device318 root_device = True # The 1st constraint refers to the node's 1st device
320 for constraint_name, size, tags in constraints:319 for constraint_name, size, tags in constraints:
321 if root_device:320 if root_device:
322 # Sort the `PhysicalBlockDevice`s by id because we consider the321 # This branch of the if is only used on first iteration.
323 # first device as the root device.
324 root_device = False322 root_device = False
325 matched_devices = PhysicalBlockDevice.objects.all()323
324 # Use only block devices that are mounted as '/'. Either the
325 # block device has root sitting on it or its on a partition on
326 # that block device.
327 filesystems = Filesystem.objects.filter(
328 mount_point='/', acquired=False)
329 filesystems = filesystems.filter(
330 Q(block_device__size__gte=size) |
331 Q(partition__partition_table__block_device__size__gte=size))
332 if tags is not None:
333 filesystems = filesystems.filter(
334 Q(block_device__tags__contains=tags) |
335 Q(**{
336 'partition__partition_table__block_device'
337 '__tags__contains': tags
338 }))
326 if node_ids is not None:339 if node_ids is not None:
327 matched_devices = matched_devices.filter(node_id__in=node_ids)340 filesystems = filesystems.filter(
328 matched_devices = matched_devices.order_by('id').values(341 Q(block_device__node_id__in=node_ids) |
329 'id', 'node_id', 'size', 'tags')342 Q(**{
343 'partition__partition_table__block_device'
344 '__node_id__in': node_ids
345 }))
346 filesystems = filesystems.prefetch_related(
347 'block_device', 'partition__partition_table__block_device')
330348
331 # Only keep the first device for every node. This is done to make349 # Only keep the first device for every node. This is done to make
332 # sure filtering out the size and tags is not done to all the350 # sure filtering out the size and tags is not done to all the
333 # block devices. This should only be done to the first block351 # block devices. This should only be done to the first block
334 # device.352 # device.
335 found_nodes = set()353 found_nodes = set()
336 devices = []354 matched_devices = []
337 for device in matched_devices:355 for filesystem in filesystems:
338 if device['node_id'] in found_nodes:356 if filesystem.block_device is not None:
357 device = filesystem.block_device
358 else:
359 device = (
360 filesystem.partition.partition_table.block_device)
361 if device.node_id in found_nodes:
339 continue362 continue
340 devices.append(device)363 matched_devices.append(device)
341 found_nodes.add(device['node_id'])364 found_nodes.add(device.node_id)
342365 else:
343 # Remove the devices that are not of correct size and the devices366 # Query for any block device the closest size and, if specified,
344 # that are missing the correct tags or label.367 # the given tags. # The block device must also be unused in the
345 devices = [368 # storage model.
346 device369 matched_devices = BlockDevice.objects.filter(size__gte=size)
347 for device in devices370 matched_devices = matched_devices.filter(
348 if device['size'] >= size371 filesystem__isnull=True, partitiontable__isnull=True)
349 ]
350 if tags is not None:372 if tags is not None:
351 tags = set(tags)373 matched_devices = matched_devices.filter(tags__contains=tags)
352 devices = [
353 device
354 for device in devices
355 if tags.issubset(set(device['tags']))
356 ]
357 matched_devices = devices
358 else:
359 # Query for the `PhysicalBlockDevice`s and `ISCSIBlockDevice`'s
360 # that have the closest size and, if specified, the given tags.
361 if tags is None:
362 matched_devices = BlockDevice.objects.filter(
363 size__gte=size).order_by('size')
364 else:
365 matched_devices = BlockDevice.objects.filter_by_tags(
366 tags).filter(size__gte=size)
367 if node_ids is not None:374 if node_ids is not None:
368 matched_devices = matched_devices.filter(375 matched_devices = matched_devices.filter(
369 node_id__in=node_ids)376 node_id__in=node_ids)
370 matched_devices = [377 matched_devices = list(matched_devices.order_by('size'))
371 {
372 'id': device.id,
373 'node_id': device.node_id,
374 'size': device.size,
375 'tags': device.tags,
376 }
377 for device in matched_devices.order_by('size')
378 if not isinstance(device.actual_instance, VirtualBlockDevice)
379 ]
380378
381 # Loop through all the returned devices. Insert only the first379 # Loop through all the returned devices. Insert only the first
382 # device from each node into `matches`.380 # device from each node into `matches`.
383 matched_in_loop = []381 matched_in_loop = []
384 for device in matched_devices:382 for device in matched_devices:
385 device_id = device['id']383 device_id = device.id
386 device_node_id = device['node_id']384 device_node_id = device.node_id
387385
388 if device_node_id in matched_in_loop:386 if device_node_id in matched_in_loop:
389 continue387 continue
390388
=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py 2017-04-10 21:49:47 +0000
+++ src/maasserver/testing/factory.py 2017-04-11 16:17:53 +0000
@@ -1793,7 +1793,8 @@
17931793
1794 def make_PhysicalBlockDevice(1794 def make_PhysicalBlockDevice(
1795 self, node=None, name=None, size=None, block_size=None,1795 self, node=None, name=None, size=None, block_size=None,
1796 tags=None, model=None, serial=None, id_path=None):1796 tags=None, model=None, serial=None, id_path=None,
1797 formatted_root=False):
1797 if node is None:1798 if node is None:
1798 node = self.make_Node()1799 node = self.make_Node()
1799 if name is None:1800 if name is None:
@@ -1819,9 +1820,15 @@
1819 else:1820 else:
1820 model = ""1821 model = ""
1821 serial = ""1822 serial = ""
1822 return PhysicalBlockDevice.objects.create(1823 block_device = PhysicalBlockDevice.objects.create(
1823 node=node, name=name, size=size, block_size=block_size,1824 node=node, name=name, size=size, block_size=block_size,
1824 tags=tags, model=model, serial=serial, id_path=id_path)1825 tags=tags, model=model, serial=serial, id_path=id_path)
1826 if formatted_root:
1827 partition = self.make_Partition(
1828 partition_table=(
1829 self.make_PartitionTable(block_device=block_device)))
1830 self.make_Filesystem(mount_point='/', partition=partition)
1831 return block_device
18251832
1826 def make_PartitionTable(1833 def make_PartitionTable(
1827 self, table_type=None, block_device=None, node=None,1834 self, table_type=None, block_device=None, node=None,
18281835
=== modified file 'src/maasserver/tests/test_node_constraint_filter_forms.py'
--- src/maasserver/tests/test_node_constraint_filter_forms.py 2017-03-15 20:40:52 +0000
+++ src/maasserver/tests/test_node_constraint_filter_forms.py 2017-04-11 16:17:53 +0000
@@ -6,11 +6,12 @@
6__all__ = []6__all__ = []
77
8from random import randint8from random import randint
9from unittest import skip
109
11from django import forms10from django import forms
12from django.core.exceptions import ValidationError11from django.core.exceptions import ValidationError
13from maasserver.enum import (12from maasserver.enum import (
13 FILESYSTEM_GROUP_TYPE,
14 FILESYSTEM_TYPE,
14 INTERFACE_TYPE,15 INTERFACE_TYPE,
15 IPADDRESS_TYPE,16 IPADDRESS_TYPE,
16 NODE_STATUS,17 NODE_STATUS,
@@ -835,34 +836,50 @@
835 ['Malformed storage constraint, "abc".']}),836 ['Malformed storage constraint, "abc".']}),
836 (form.is_valid(), form.errors))837 (form.is_valid(), form.errors))
837838
838 def test_storage_single_contraint_only_matches_physical_devices(self):839 def test_storage_matches_disk_with_root_mount_on_disk(self):
839 node1 = factory.make_Node(with_boot_disk=False)840 node1 = factory.make_Node(with_boot_disk=False)
840 factory.make_PhysicalBlockDevice(node=node1)841 factory.make_PhysicalBlockDevice(node=node1)
841 node2 = factory.make_Node(with_boot_disk=False)842 block_device = factory.make_PhysicalBlockDevice(node=node1)
842 factory.make_BlockDevice(node=node2)843 factory.make_Filesystem(mount_point='/', block_device=block_device)
844 node2 = factory.make_Node(with_boot_disk=False)
845 factory.make_PhysicalBlockDevice(node=node2)
846 self.assertConstrainedNodes([node1], {'storage': '0'})
847
848 def test_storage_matches_disk_with_root_mount_on_partition(self):
849 node1 = factory.make_Node(with_boot_disk=False)
850 factory.make_PhysicalBlockDevice(
851 node=node1, formatted_root=True)
852 node2 = factory.make_Node(with_boot_disk=False)
853 block_device = factory.make_PhysicalBlockDevice(node=node2)
854 partition_table = factory.make_PartitionTable(
855 block_device=block_device)
856 partition = factory.make_Partition(partition_table=partition_table)
857 factory.make_Filesystem(mount_point='/srv', partition=partition)
843 self.assertConstrainedNodes([node1], {'storage': '0'})858 self.assertConstrainedNodes([node1], {'storage': '0'})
844859
845 def test_storage_single_contraint_matches_all_sizes_larger(self):860 def test_storage_single_contraint_matches_all_sizes_larger(self):
846 node1 = factory.make_Node(with_boot_disk=False)861 node1 = factory.make_Node(with_boot_disk=False)
847 # 1gb block device862 # 1gb block device
848 factory.make_PhysicalBlockDevice(863 factory.make_PhysicalBlockDevice(
849 node=node1, size=1 * (1000 ** 3))864 node=node1, size=1 * (1000 ** 3), formatted_root=True)
850 node2 = factory.make_Node(with_boot_disk=False)865 node2 = factory.make_Node(with_boot_disk=False)
851 # 4gb block device866 # 4gb block device
852 factory.make_PhysicalBlockDevice(867 factory.make_PhysicalBlockDevice(
853 node=node2, size=4 * (1000 ** 3))868 node=node2, size=4 * (1000 ** 3), formatted_root=True)
854 node3 = factory.make_Node(with_boot_disk=False)869 node3 = factory.make_Node(with_boot_disk=False)
855 # 8gb block device870 # 8gb block device
856 factory.make_PhysicalBlockDevice(871 factory.make_PhysicalBlockDevice(
857 node=node3, size=8 * (1000 ** 3))872 node=node3, size=8 * (1000 ** 3), formatted_root=True)
858 # all nodes with physical devices larger than 2gb873 # all nodes with physical devices larger than 2gb
859 self.assertConstrainedNodes([node2, node3], {'storage': '2'})874 self.assertConstrainedNodes([node2, node3], {'storage': '2'})
860875
861 def test_storage_single_contraint_matches_on_tags(self):876 def test_storage_single_contraint_matches_on_tags(self):
862 node1 = factory.make_Node(with_boot_disk=False)877 node1 = factory.make_Node(with_boot_disk=False)
863 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd'])878 factory.make_PhysicalBlockDevice(
879 node=node1, tags=['ssd'], formatted_root=True)
864 node2 = factory.make_Node(with_boot_disk=False)880 node2 = factory.make_Node(with_boot_disk=False)
865 factory.make_PhysicalBlockDevice(node=node2, tags=['rotary'])881 factory.make_PhysicalBlockDevice(
882 node=node2, tags=['rotary'], formatted_root=True)
866 self.assertConstrainedNodes([node1], {'storage': '0(ssd)'})883 self.assertConstrainedNodes([node1], {'storage': '0(ssd)'})
867884
868 def test_storage_single_contraint_matches_decimal_size(self):885 def test_storage_single_contraint_matches_decimal_size(self):
@@ -871,56 +888,153 @@
871 factory.make_PhysicalBlockDevice(888 factory.make_PhysicalBlockDevice(
872 node=node1, size=2 * (1000 ** 3))889 node=node1, size=2 * (1000 ** 3))
873 factory.make_PhysicalBlockDevice(890 factory.make_PhysicalBlockDevice(
874 node=node1, size=4 * (1000 ** 3))891 node=node1, size=4 * (1000 ** 3), formatted_root=True)
875 node2 = factory.make_Node(with_boot_disk=False)892 node2 = factory.make_Node(with_boot_disk=False)
876 # 1gb block device893 # 1gb block device
877 factory.make_PhysicalBlockDevice(894 factory.make_PhysicalBlockDevice(
878 node=node2, size=1 * (1000 ** 3))895 node=node2, size=1 * (1000 ** 3), formatted_root=True)
879 self.assertConstrainedNodes([node1], {'storage': '1.5'})896 self.assertConstrainedNodes([node1], {'storage': '1.5'})
880897
881 def test_storage_multi_contraint_only_matches_physical_devices(self):898 def test_storage_single_contraint_allows_root_on_virtual(self):
882 node1 = factory.make_Node(with_boot_disk=False)899 node1 = factory.make_Node(with_boot_disk=False)
883 factory.make_PhysicalBlockDevice(node=node1)900 physical = factory.make_PhysicalBlockDevice(node=node1)
884 factory.make_PhysicalBlockDevice(node=node1)901 partition_table = factory.make_PartitionTable(block_device=physical)
885 node2 = factory.make_Node(with_boot_disk=False)902 partition = factory.make_Partition(partition_table=partition_table)
886 factory.make_BlockDevice(node=node2)903 pv = factory.make_Filesystem(
887 factory.make_BlockDevice(node=node2)904 fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition)
888 self.assertConstrainedNodes([node1], {'storage': '0,0'})905 vg = factory.make_FilesystemGroup(
889906 filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG)
890 def test_storage_multi_contraint_matches_all_sizes_larger(self):907 virtual = factory.make_VirtualBlockDevice(
891 node1 = factory.make_Node(with_boot_disk=False)908 filesystem_group=vg, node=node1)
892 # 1gb, 2gb, 3gb block device909 factory.make_Filesystem(mount_point='/', block_device=virtual)
893 factory.make_PhysicalBlockDevice(910 self.assertConstrainedNodes([node1], {'storage': '0'})
894 node=node1, size=1 * (1000 ** 3))911
895 factory.make_PhysicalBlockDevice(912 def test_storage_single_contraint_size_on_virtual(self):
896 node=node1, size=2 * (1000 ** 3))913 node1 = factory.make_Node(with_boot_disk=False)
897 factory.make_PhysicalBlockDevice(914 physical = factory.make_PhysicalBlockDevice(
898 node=node1, size=3 * (1000 ** 3))915 node=node1, size=(6 * (1000 ** 3)))
899 node2 = factory.make_Node(with_boot_disk=False)916 partition_table = factory.make_PartitionTable(block_device=physical)
900 # 5gb, 6gb, 7gb block device917 partition = factory.make_Partition(
901 factory.make_PhysicalBlockDevice(918 partition_table=partition_table, size=(5.5 * (1000 ** 3)))
902 node=node2, size=5 * (1000 ** 3))919 pv = factory.make_Filesystem(
903 factory.make_PhysicalBlockDevice(920 fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition)
904 node=node2, size=6 * (1000 ** 3))921 vg = factory.make_FilesystemGroup(
905 factory.make_PhysicalBlockDevice(922 filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG)
906 node=node2, size=7 * (1000 ** 3))923 virtual = factory.make_VirtualBlockDevice(
907 node3 = factory.make_Node(with_boot_disk=False)924 filesystem_group=vg, node=node1, size=(5 * (1000 ** 3)))
908 # 8gb, 9gb, 10gb block device925 factory.make_Filesystem(mount_point='/', block_device=virtual)
909 factory.make_PhysicalBlockDevice(926 self.assertConstrainedNodes([node1], {'storage': '4'})
910 node=node3, size=8 * (1000 ** 3))927
911 factory.make_PhysicalBlockDevice(928 def test_storage_multi_contraint_matches_physical_and_unused(self):
912 node=node3, size=9 * (1000 ** 3))929 node1 = factory.make_Node(with_boot_disk=False)
913 factory.make_PhysicalBlockDevice(930 factory.make_PhysicalBlockDevice(
914 node=node3, size=10 * (1000 ** 3))931 node=node1, formatted_root=True)
915 # all nodes with physical devices larger than 2gb932 # 1gb, 2gb, 3gb block device
916 self.assertConstrainedNodes([node2, node3], {'storage': '4,4,4'})933 factory.make_PhysicalBlockDevice(
934 node=node1, size=1 * (1000 ** 3))
935 factory.make_PhysicalBlockDevice(
936 node=node1, size=2 * (1000 ** 3))
937 factory.make_PhysicalBlockDevice(
938 node=node1, size=3 * (1000 ** 3))
939 node2 = factory.make_Node(with_boot_disk=False)
940 factory.make_PhysicalBlockDevice(
941 node=node2, formatted_root=True)
942 # 5gb, 6gb, 7gb block device
943 factory.make_PhysicalBlockDevice(
944 node=node2, size=5 * (1000 ** 3))
945 factory.make_PhysicalBlockDevice(
946 node=node2, size=6 * (1000 ** 3))
947 factory.make_PhysicalBlockDevice(
948 node=node2, size=7 * (1000 ** 3))
949 node3 = factory.make_Node(with_boot_disk=False)
950 factory.make_PhysicalBlockDevice(
951 node=node3, formatted_root=True)
952 # 8gb, 9gb, 10gb block device
953 factory.make_PhysicalBlockDevice(
954 node=node3, size=8 * (1000 ** 3))
955 factory.make_PhysicalBlockDevice(
956 node=node3, size=9 * (1000 ** 3))
957 factory.make_PhysicalBlockDevice(
958 node=node3, size=10 * (1000 ** 3))
959 # all nodes with physical devices larger than 2gb
960 self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'})
961
962 def test_storage_multi_contraint_matches_virtual_and_unused(self):
963 node1 = factory.make_Node(with_boot_disk=False)
964 factory.make_PhysicalBlockDevice(
965 node=node1, formatted_root=True)
966 # 1gb, 2gb, 3gb block device
967 factory.make_VirtualBlockDevice(
968 node=node1, size=1 * (1000 ** 3))
969 factory.make_VirtualBlockDevice(
970 node=node1, size=2 * (1000 ** 3))
971 factory.make_VirtualBlockDevice(
972 node=node1, size=3 * (1000 ** 3))
973 node2 = factory.make_Node(with_boot_disk=False)
974 factory.make_PhysicalBlockDevice(
975 node=node2, formatted_root=True)
976 # 5gb, 6gb, 7gb block device
977 factory.make_VirtualBlockDevice(
978 node=node2, size=5 * (1000 ** 3))
979 factory.make_VirtualBlockDevice(
980 node=node2, size=6 * (1000 ** 3))
981 factory.make_VirtualBlockDevice(
982 node=node2, size=7 * (1000 ** 3))
983 node3 = factory.make_Node(with_boot_disk=False)
984 factory.make_PhysicalBlockDevice(
985 node=node3, formatted_root=True)
986 # 8gb, 9gb, 10gb block device
987 factory.make_VirtualBlockDevice(
988 node=node3, size=8 * (1000 ** 3))
989 factory.make_VirtualBlockDevice(
990 node=node3, size=9 * (1000 ** 3))
991 factory.make_VirtualBlockDevice(
992 node=node3, size=10 * (1000 ** 3))
993 # all nodes with physical devices larger than 2gb
994 self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'})
995
996 def test_storage_multi_contraint_matches_iscsi_and_unused(self):
997 node1 = factory.make_Node(with_boot_disk=False)
998 factory.make_PhysicalBlockDevice(
999 node=node1, formatted_root=True)
1000 # 1gb, 2gb, 3gb block device
1001 factory.make_ISCSIBlockDevice(
1002 node=node1, size=1 * (1000 ** 3))
1003 factory.make_ISCSIBlockDevice(
1004 node=node1, size=2 * (1000 ** 3))
1005 factory.make_ISCSIBlockDevice(
1006 node=node1, size=3 * (1000 ** 3))
1007 node2 = factory.make_Node(with_boot_disk=False)
1008 factory.make_PhysicalBlockDevice(
1009 node=node2, formatted_root=True)
1010 # 5gb, 6gb, 7gb block device
1011 factory.make_ISCSIBlockDevice(
1012 node=node2, size=5 * (1000 ** 3))
1013 factory.make_ISCSIBlockDevice(
1014 node=node2, size=6 * (1000 ** 3))
1015 factory.make_ISCSIBlockDevice(
1016 node=node2, size=7 * (1000 ** 3))
1017 node3 = factory.make_Node(with_boot_disk=False)
1018 factory.make_PhysicalBlockDevice(
1019 node=node3, formatted_root=True)
1020 # 8gb, 9gb, 10gb block device
1021 factory.make_ISCSIBlockDevice(
1022 node=node3, size=8 * (1000 ** 3))
1023 factory.make_ISCSIBlockDevice(
1024 node=node3, size=9 * (1000 ** 3))
1025 factory.make_ISCSIBlockDevice(
1026 node=node3, size=10 * (1000 ** 3))
1027 # all nodes with physical devices larger than 2gb
1028 self.assertConstrainedNodes([node2, node3], {'storage': '0,4,4,4'})
9171029
918 def test_storage_multi_contraint_matches_on_tags(self):1030 def test_storage_multi_contraint_matches_on_tags(self):
919 node1 = factory.make_Node(with_boot_disk=False)1031 node1 = factory.make_Node(with_boot_disk=False)
920 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd'])1032 factory.make_PhysicalBlockDevice(
1033 node=node1, tags=['ssd'], formatted_root=True)
921 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd', 'removable'])1034 factory.make_PhysicalBlockDevice(node=node1, tags=['ssd', 'removable'])
922 node2 = factory.make_Node(with_boot_disk=False)1035 node2 = factory.make_Node(with_boot_disk=False)
923 factory.make_PhysicalBlockDevice(node=node2, tags=['ssd'])1036 factory.make_PhysicalBlockDevice(
1037 node=node2, tags=['ssd'], formatted_root=True)
924 factory.make_PhysicalBlockDevice(node=node2, tags=['ssd', 'sata'])1038 factory.make_PhysicalBlockDevice(node=node2, tags=['ssd', 'sata'])
925 self.assertConstrainedNodes(1039 self.assertConstrainedNodes(
926 [node1], {'storage': '0(ssd),0(ssd,removable)'})1040 [node1], {'storage': '0(ssd),0(ssd,removable)'})
@@ -930,7 +1044,7 @@
930 # 1gb, 2gb block device1044 # 1gb, 2gb block device
931 factory.make_PhysicalBlockDevice(1045 factory.make_PhysicalBlockDevice(
932 node=node1, size=1 * (1000 ** 3),1046 node=node1, size=1 * (1000 ** 3),
933 tags=['ssd'])1047 tags=['ssd'], formatted_root=True)
934 factory.make_PhysicalBlockDevice(1048 factory.make_PhysicalBlockDevice(
935 node=node1, size=2 * (1000 ** 3),1049 node=node1, size=2 * (1000 ** 3),
936 tags=['ssd'])1050 tags=['ssd'])
@@ -938,65 +1052,81 @@
938 # 4gb, 5gb block device1052 # 4gb, 5gb block device
939 factory.make_PhysicalBlockDevice(1053 factory.make_PhysicalBlockDevice(
940 node=node2, size=4 * (1000 ** 3),1054 node=node2, size=4 * (1000 ** 3),
941 tags=['ssd'])1055 tags=['ssd'], formatted_root=True)
942 factory.make_PhysicalBlockDevice(1056 factory.make_PhysicalBlockDevice(
943 node=node2, size=5 * (1000 ** 3),1057 node=node2, size=5 * (1000 ** 3),
944 tags=['ssd'])1058 tags=['ssd'])
945 self.assertConstrainedNodes(1059 self.assertConstrainedNodes(
946 [node2], {'storage': '3(ssd),3(ssd)'})1060 [node2], {'storage': '3(ssd),3(ssd)'})
9471061
948 def test_storage_first_constraint_matches_first_blockdevice(self):1062 def test_storage_first_constraint_matches_blockdevice_with_root(self):
949 """1063 """
950 Make sure a constraint like 10(ssd),5,20 will match a node with a1064 Make sure a constraint like 10(ssd),5,20 will match a node with a
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,
952 but not a 5/20/10(ssd) node1066 but not a 5/20/10(ssd) node
953 """1067 """
954 node1 = factory.make_Node(with_boot_disk=False)1068 node1 = factory.make_Node(with_boot_disk=False)
955 factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3))
956 factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3))1069 factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3))
957 factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3),1070 factory.make_PhysicalBlockDevice(
958 tags=['ssd'])1071 node=node1, size=11 * (1000 ** 3), tags=['ssd'])
1072 factory.make_PhysicalBlockDevice(
1073 node=node1, size=6 * (1000 ** 3), formatted_root=True)
959 node2 = factory.make_Node(with_boot_disk=False)1074 node2 = factory.make_Node(with_boot_disk=False)
960 factory.make_PhysicalBlockDevice(node=node2, size=11 * (1000 ** 3),
961 tags=['ssd'])
962 factory.make_PhysicalBlockDevice(node=node2, size=6 * (1000 ** 3))1075 factory.make_PhysicalBlockDevice(node=node2, size=6 * (1000 ** 3))
963 factory.make_PhysicalBlockDevice(node=node2, size=21 * (1000 ** 3))1076 factory.make_PhysicalBlockDevice(node=node2, size=21 * (1000 ** 3))
1077 factory.make_PhysicalBlockDevice(
1078 node=node2, size=11 * (1000 ** 3),
1079 tags=['ssd'], formatted_root=True)
964 self.assertConstrainedNodes(1080 self.assertConstrainedNodes(
965 [node2], {'storage': '10(ssd),5,20'})1081 [node2], {'storage': '10(ssd),5,20'})
9661082
967 def test_storage_multi_contraint_matches_large_disk_count(self):1083 def test_storage_multi_contraint_matches_large_disk_count(self):
968 node1 = factory.make_Node(with_boot_disk=False)1084 node1 = factory.make_Node(with_boot_disk=False)
1085 factory.make_PhysicalBlockDevice(node=node1, formatted_root=True)
969 for _ in range(10):1086 for _ in range(10):
970 factory.make_PhysicalBlockDevice(node=node1)1087 factory.make_PhysicalBlockDevice(node=node1)
971 node2 = factory.make_Node(with_boot_disk=False)1088 node2 = factory.make_Node(with_boot_disk=False)
1089 factory.make_PhysicalBlockDevice(node=node2, formatted_root=True)
972 for _ in range(5):1090 for _ in range(5):
973 factory.make_PhysicalBlockDevice(node=node2)1091 factory.make_PhysicalBlockDevice(node=node2)
974 self.assertConstrainedNodes(1092 self.assertConstrainedNodes(
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'})
9761094
977 @skip(
978 "XXX: allenap 2015-03-17 bug=1433012: This test keeps failing when "
979 "landing unrelated branches, so has been disabled.")
980 def test_storage_with_named_constraints(self):1095 def test_storage_with_named_constraints(self):
981 node1 = factory.make_Node(with_boot_disk=False)1096 node1 = factory.make_Node(with_boot_disk=False)
982 factory.make_PhysicalBlockDevice(node=node1, size=11 * (1000 ** 3),1097 physical = factory.make_PhysicalBlockDevice(
983 tags=['ssd'])1098 node=node1, size=11 * (1000 ** 3))
984 factory.make_PhysicalBlockDevice(node=node1, size=6 * (1000 ** 3),1099 partition_table = factory.make_PartitionTable(block_device=physical)
985 tags=['rotary', '5400rpm'])1100 partition = factory.make_Partition(
986 factory.make_PhysicalBlockDevice(node=node1, size=21 * (1000 ** 3))1101 partition_table=partition_table, size=10 * (1000 ** 3))
987 form = AcquireNodeForm({'storage':1102 pv = factory.make_Filesystem(
988 'root:10(ssd),data:5(rotary,5400rpm),20'})1103 fstype=FILESYSTEM_TYPE.LVM_PV, partition=partition)
1104 vg = factory.make_FilesystemGroup(
1105 filesystems=[pv], group_type=FILESYSTEM_GROUP_TYPE.LVM_VG)
1106 virtual = factory.make_VirtualBlockDevice(
1107 filesystem_group=vg, node=node1, size=9 * (1000 ** 3),
1108 tags=['lvm'])
1109 factory.make_Filesystem(mount_point='/', block_device=virtual)
1110 physical = factory.make_PhysicalBlockDevice(
1111 node=node1, size=6 * (1000 ** 3), tags=['rotary', '5400rpm'])
1112 iscsi = factory.make_ISCSIBlockDevice(
1113 node=node1, size=21 * (1000 ** 3))
1114 form = AcquireNodeForm({
1115 'storage': 'root:8(lvm),physical:5(rotary,5400rpm),iscsi:20'})
989 self.assertTrue(form.is_valid(), form.errors)1116 self.assertTrue(form.is_valid(), form.errors)
990 filtered_nodes, constraint_map = form.filter_nodes(1117 filtered_nodes, constraint_map, _ = form.filter_nodes(
991 Machine.objects.all())1118 Machine.objects.all())
992 node = filtered_nodes[0]1119 node = filtered_nodes[0]
993 constraints = list(constraint_map[node.id])1120 constraints = {
994 disk0 = node.physicalblockdevice_set.get(1121 value: key
995 id=constraints[0]) # 1st constraint with name1122 for key, value in constraint_map[node.id].items()
996 self.assertGreaterEqual(disk0.size, 10 * 1000 ** 3)1123 }
997 disk1 = node.physicalblockdevice_set.get(1124 disk0 = node.blockdevice_set.get(id=constraints['root'])
998 id=constraints[1]) # 2nd constraint with name1125 self.assertEquals(virtual.id, disk0.id)
999 self.assertGreaterEqual(disk1.size, 5 * 1000 ** 3)1126 disk1 = node.blockdevice_set.get(id=constraints['physical'])
1127 self.assertEquals(physical.id, disk1.id)
1128 disk2 = node.blockdevice_set.get(id=constraints['iscsi'])
1129 self.assertEquals(iscsi.id, disk2.id)
10001130
1001 def test_fabrics_constraint(self):1131 def test_fabrics_constraint(self):
1002 fabric1 = factory.make_Fabric(name="fabric1")1132 fabric1 = factory.make_Fabric(name="fabric1")