Make scheduler client allow multiple member_of query parameters

This implements support for placement version 1.24, which allows multiple
member_of query parameters to allocation_candidates.

Related to blueprint alloc-candidates-member-of

Change-Id: Id7eecbfe53f3a973d828122cf0149b2e10b8833f
This commit is contained in:
Dan Smith
2018-05-14 07:57:27 -07:00
parent 36345f34c4
commit ac114ecc63
2 changed files with 23 additions and 28 deletions
+19 -24
View File
@@ -345,33 +345,26 @@ class SchedulerReportClient(object):
resource_query = ",".join(
sorted("%s:%s" % (rc, amount)
for (rc, amount) in res.items()))
qs_params = {
'resources': resource_query,
'limit': CONF.scheduler.max_placement_results,
}
qs_params = [
('resources', resource_query),
('limit', CONF.scheduler.max_placement_results),
]
required_traits_params = []
if required_traits:
qs_params['required'] = ",".join(required_traits)
required_traits_params.extend(required_traits)
if forbidden_traits:
# Sorted to make testing easier to manage and for
# predictability.
forbiddens = ',!'.join(sorted(forbidden_traits))
if qs_params['required']:
qs_params['required'] += ',!' + forbiddens
else:
qs_params['required'] = '!' + forbiddens
if aggregates:
# NOTE(danms): In 1.21, placement cannot take an AND'd
# set of aggregates, only an OR'd set. Thus, if we have
# required and optional sets, we must do the naive thing
# and AND ours together. That will not achieve the same
# result, but we can't do it from the client side. When
# placement supports AND'ing multiple sets, we can fix this.
# TODO(danms): Update this when placement can take multiple
# member_of query parameters.
required_agg = set.intersection(*[set(x) for x in aggregates])
qs_params['member_of'] = 'in:' + ','.join(sorted(required_agg))
required_traits_params.extend(
['!%s' % trait for trait in sorted(forbidden_traits)])
if required_traits_params:
qs_params.append(('required', ','.join(required_traits_params)))
version = '1.21'
if aggregates:
for agg_list in aggregates:
qs_params.append(('member_of', 'in:%s' % ','.join(agg_list)))
version = '1.24'
url = "/allocation_candidates?%s" % parse.urlencode(qs_params)
resp = self.get(url, version=version,
global_request_id=context.global_id)
@@ -389,8 +382,10 @@ class SchedulerReportClient(object):
"API for filters %(resources)s, traits %(traits)s, "
"aggregates %(aggregates)s. Got "
"%(status_code)d: %(err_text)s.")
args['traits'] = qs_params.get('required', '(none)')
args['aggregates'] = qs_params.get('aggregates', '(none)')
query_traits = [v for k, v in qs_params if k == 'required']
query_aggs = [v for k, v in qs_params if k == 'member_of']
args['traits'] = query_traits and query_traits[0] or '(none)'
args['aggregates'] = ','.join(query_aggs) or '(none)'
LOG.error(msg, args)
return None, None, None
@@ -1463,7 +1463,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
expected_query = {
'resources': ['MEMORY_MB:1024,VCPU:1'],
'required': ['CUSTOM_TRAIT1,!CUSTOM_TRAIT3,!CUSTOM_TRAIT4'],
'member_of': ['in:agg1,agg2'],
'member_of': ['in:agg1,agg2,agg3', 'in:agg1,agg2'],
'limit': ['1000']
}
@@ -1474,7 +1474,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
self.client.get_allocation_candidates(self.context, resources)
self.ks_adap_mock.get.assert_called_once_with(
mock.ANY, raise_exc=False, microversion='1.21',
mock.ANY, raise_exc=False, microversion='1.24',
headers={'X-Openstack-Request-Id': self.context.global_id})
url = self.ks_adap_mock.get.call_args[0][0]
split_url = parse.urlsplit(url)
@@ -1506,7 +1506,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
self.client.get_allocation_candidates(self.context, resources)
self.ks_adap_mock.get.assert_called_once_with(
mock.ANY, raise_exc=False, microversion='1.21',
mock.ANY, raise_exc=False, microversion='1.24',
headers={'X-Openstack-Request-Id': self.context.global_id})
url = self.ks_adap_mock.get.call_args[0][0]
split_url = parse.urlsplit(url)
@@ -1533,7 +1533,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
res = self.client.get_allocation_candidates(self.context, resources)
self.ks_adap_mock.get.assert_called_once_with(
mock.ANY, raise_exc=False, microversion='1.21',
mock.ANY, raise_exc=False, microversion='1.24',
headers={'X-Openstack-Request-Id': self.context.global_id})
url = self.ks_adap_mock.get.call_args[0][0]
split_url = parse.urlsplit(url)