def test_numbered_only(self): # Crazy ordering and nonsequential numbers don't matter. # It's okay to have a 'resources' without a 'required'. # A trait that's repeated shows up in both spots. qs = ('resources1=VCPU:2,MEMORY_MB:2048' '&required42=CUSTOM_GOLD' '&resources99=DISK_GB:5' '&resources42=CUSTOM_MAGIC:123' '&required1=HW_CPU_X86_VMX,CUSTOM_GOLD') expected = [ pl.RequestGroup( resources={ 'VCPU': 2, 'MEMORY_MB': 2048, }, required_traits={ 'HW_CPU_X86_VMX', 'CUSTOM_GOLD', }, ), pl.RequestGroup( resources={ 'CUSTOM_MAGIC': 123, }, required_traits={ 'CUSTOM_GOLD', }, ), pl.RequestGroup( resources={ 'DISK_GB': 5, }, ), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs))
def test_forbidden_separate_groups_no_conflict(self): qs = ('resources1=CUSTOM_MAGIC:1&required1=CUSTOM_PHYSNET1' '&resources2=CUSTOM_MAGIC:1&required2=!CUSTOM_PHYSNET1') expected = [ pl.RequestGroup( use_same_provider=True, resources={ 'CUSTOM_MAGIC': 1, }, required_traits={ 'CUSTOM_PHYSNET1', } ), pl.RequestGroup( use_same_provider=True, resources={ 'CUSTOM_MAGIC': 1, }, forbidden_traits={ 'CUSTOM_PHYSNET1', } ), ] self.assertRequestGroupsEqual( expected, self.do_parse(qs, version=(1, 22)))
def test_forbidden_two_groups(self): qs = ('resources=VCPU:2,MEMORY_MB:2048&resources1=CUSTOM_MAGIC:1' '&required1=CUSTOM_PHYSNET1,!CUSTOM_PHYSNET2') expected = [ pl.RequestGroup( use_same_provider=False, resources={ 'VCPU': 2, 'MEMORY_MB': 2048, }, ), pl.RequestGroup( resources={ 'CUSTOM_MAGIC': 1, }, required_traits={ 'CUSTOM_PHYSNET1', }, forbidden_traits={ 'CUSTOM_PHYSNET2', } ), ] self.assertRequestGroupsEqual( expected, self.do_parse(qs, version=(1, 22)))
def test_member_of_multiple_aggs_numbered(self): """Numbered resources with multiple member_of query params.""" agg1_uuid = uuidsentinel.agg1 agg2_uuid = uuidsentinel.agg2 agg3_uuid = uuidsentinel.agg3 agg4_uuid = uuidsentinel.agg4 qs = ('resources1=VCPU:2' '&member_of1=%s' '&member_of1=%s' '&resources2=VCPU:2' '&member_of2=in:%s,%s' % ( agg1_uuid, agg2_uuid, agg3_uuid, agg4_uuid)) expected = [ pl.RequestGroup( resources={ 'VCPU': 2, }, member_of=[ set([agg1_uuid]), set([agg2_uuid]) ] ), pl.RequestGroup( resources={ 'VCPU': 2, }, member_of=[ set([agg3_uuid, agg4_uuid]), ] ), ] self.assertRequestGroupsEqual( expected, self.do_parse(qs, version=(1, 24)))
def test_numbered_and_unnumbered(self): qs = ('resources=VCPU:3,MEMORY_MB:4096,DISK_GB:10' '&required=HW_CPU_X86_VMX,CUSTOM_MEM_FLASH,STORAGE_DISK_SSD' '&resources1=SRIOV_NET_VF:2' '&required1=CUSTOM_PHYSNET_PRIVATE' '&resources2=SRIOV_NET_VF:1,NET_INGRESS_BYTES_SEC:20000' ',NET_EGRESS_BYTES_SEC:10000' '&required2=CUSTOM_SWITCH_BIG,CUSTOM_PHYSNET_PROD' '&resources3=CUSTOM_MAGIC:123') expected = [ pl.RequestGroup( use_same_provider=False, resources={ 'VCPU': 3, 'MEMORY_MB': 4096, 'DISK_GB': 10, }, required_traits={ 'HW_CPU_X86_VMX', 'CUSTOM_MEM_FLASH', 'STORAGE_DISK_SSD', }, ), pl.RequestGroup( resources={ 'SRIOV_NET_VF': 2, }, required_traits={ 'CUSTOM_PHYSNET_PRIVATE', }, ), pl.RequestGroup( resources={ 'SRIOV_NET_VF': 1, 'NET_INGRESS_BYTES_SEC': 20000, 'NET_EGRESS_BYTES_SEC': 10000, }, required_traits={ 'CUSTOM_SWITCH_BIG', 'CUSTOM_PHYSNET_PROD', }, ), pl.RequestGroup( resources={ 'CUSTOM_MAGIC': 123, }, ), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs))
def test_forbidden_one_group(self): """When forbidden are allowed this will parse, but otherwise will indicate an invalid trait. """ qs = ('resources=VCPU:2,MEMORY_MB:2048' '&required=CUSTOM_PHYSNET1,!CUSTOM_SWITCH_BIG') expected_forbidden = [ pl.RequestGroup(use_same_provider=False, resources={ 'VCPU': 2, 'MEMORY_MB': 2048, }, required_traits={ 'CUSTOM_PHYSNET1', }, forbidden_traits={ 'CUSTOM_SWITCH_BIG', }), ] expected_message = ( "Invalid query string parameters: Expected 'required' parameter " "value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC. Got: " "CUSTOM_PHYSNET1,!CUSTOM_SWITCH_BIG") exc = self.assertRaises(webob.exc.HTTPBadRequest, self.do_parse, qs) self.assertEqual(expected_message, six.text_type(exc)) self.assertRequestGroupsEqual(expected_forbidden, self.do_parse(qs, version=(1, 22)))
def test_member_of_forbidden_aggs(self): agg1_uuid = uuidsentinel.agg1 agg2_uuid = uuidsentinel.agg2 agg3_uuid = uuidsentinel.agg3 agg4_uuid = uuidsentinel.agg4 qs = ('resources=VCPU:2' '&member_of=%s' '&member_of=%s' '&member_of=!%s' '&member_of=!%s' % (agg1_uuid, agg2_uuid, agg3_uuid, agg4_uuid)) expected = [ pl.RequestGroup( use_same_provider=False, resources={ 'VCPU': 2, }, member_of=[ set([agg1_uuid]), set([agg2_uuid]), ], forbidden_aggs=set([agg3_uuid, agg4_uuid]), ), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs, version=(1, 32)))
def test_member_of_single_agg(self): """Unnumbered resources with one member_of query param.""" agg1_uuid = uuidsentinel.agg1 qs = ('resources=VCPU:2,MEMORY_MB:2048' '&member_of=%s' % agg1_uuid) expected = [ pl.RequestGroup(use_same_provider=False, resources={ 'VCPU': 2, 'MEMORY_MB': 2048, }, member_of=[set([agg1_uuid])]), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs))
def test_unnumbered_resources_only(self): """Validate the bit that can be used for 1.10 and earlier.""" qs = 'resources=VCPU:2,MEMORY_MB:2048,DISK_GB:5,CUSTOM_MAGIC:123' expected = [ pl.RequestGroup( use_same_provider=False, resources={ 'VCPU': 2, 'MEMORY_MB': 2048, 'DISK_GB': 5, 'CUSTOM_MAGIC': 123, }, ), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs))
def test_good_suffix_1_33(self): qs = ('resources_car_HOUSE_10=CUSTOM_MAGIC:1' '&required_car_HOUSE_10=CUSTOM_PHYSNET1') expected = [ pl.RequestGroup(use_same_provider=True, resources={ 'CUSTOM_MAGIC': 1, }, required_traits={ 'CUSTOM_PHYSNET1', }), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs, version=(1, 33))) self.assertRaises(webob.exc.HTTPBadRequest, self.do_parse, qs, version=(1, 22))
def test_member_of_multiple_aggs(self): """Unnumbered resources with multiple member_of query params.""" agg1_uuid = uuidsentinel.agg1 agg2_uuid = uuidsentinel.agg2 qs = ('resources=VCPU:2,MEMORY_MB:2048' '&member_of=%s' '&member_of=%s' % (agg1_uuid, agg2_uuid)) expected = [ pl.RequestGroup(use_same_provider=False, resources={ 'VCPU': 2, 'MEMORY_MB': 2048, }, member_of=[set([agg1_uuid]), set([agg2_uuid])]), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs, version=(1, 24)))
def test_unnumbered_only(self): """Unnumbered resources & traits - no numbered groupings.""" qs = ('resources=VCPU:2,MEMORY_MB:2048' '&required=HW_CPU_X86_VMX,CUSTOM_GOLD') expected = [ pl.RequestGroup( use_same_provider=False, resources={ 'VCPU': 2, 'MEMORY_MB': 2048, }, required_traits={ 'HW_CPU_X86_VMX', 'CUSTOM_GOLD', }, ), ] self.assertRequestGroupsEqual(expected, self.do_parse(qs))
def get_request_group(suffix): if suffix not in by_suffix: rq_grp = placement_lib.RequestGroup(use_same_provider=bool(suffix)) by_suffix[suffix] = rq_grp return by_suffix[suffix]
def test_shared_provider_capacity(self): """Sets up a resource provider that shares DISK_GB inventory via an aggregate, a couple resource providers representing "local disk" compute nodes and ensures the _get_providers_sharing_capacity() function finds that provider and not providers of "local disk". """ # Create the two "local disk" compute node providers cn1 = self._create_provider('cn1') cn2 = self._create_provider('cn2') # Populate the two compute node providers with inventory. One has # DISK_GB. Both should be excluded from the result (one doesn't have # the requested resource; but neither is a sharing provider). for cn in (cn1, cn2): tb.add_inventory(cn, orc.VCPU, 24, allocation_ratio=16.0) tb.add_inventory(cn, orc.MEMORY_MB, 32768, min_unit=64, max_unit=32768, step_size=64, allocation_ratio=1.5) if cn is cn1: tb.add_inventory(cn, orc.DISK_GB, 2000, min_unit=100, max_unit=2000, step_size=10) # Create the shared storage pool ss1 = self._create_provider('shared storage 1') ss2 = self._create_provider('shared storage 2') # Give the shared storage pool some inventory of DISK_GB for ss, disk_amount in ((ss1, 2000), (ss2, 1000)): tb.add_inventory(ss, orc.DISK_GB, disk_amount, min_unit=100, max_unit=2000, step_size=10) # Mark the shared storage pool as having inventory shared among # any provider associated via aggregate tb.set_traits(ss, "MISC_SHARES_VIA_AGGREGATE") # OK, now that has all been set up, let's verify that we get the ID of # the shared storage pool got_ids = res_ctx.get_sharing_providers(self.ctx) self.assertEqual(set([ss1.id, ss2.id]), got_ids) request = placement_lib.RequestGroup( use_same_provider=False, resources={orc.VCPU: 2, orc.MEMORY_MB: 256, orc.DISK_GB: 1500}) has_trees = res_ctx._has_provider_trees(self.ctx) sharing = res_ctx.get_sharing_providers(self.ctx) rg_ctx = res_ctx.RequestGroupSearchContext( self.ctx, request, has_trees, sharing) VCPU_ID = orc.STANDARDS.index(orc.VCPU) DISK_GB_ID = orc.STANDARDS.index(orc.DISK_GB) rps_sharing_vcpu = rg_ctx.get_rps_with_shared_capacity(VCPU_ID) self.assertEqual(set(), rps_sharing_vcpu) rps_sharing_dist = rg_ctx.get_rps_with_shared_capacity(DISK_GB_ID) self.assertEqual(set([ss1.id]), rps_sharing_dist)