Merge "placement: support traits in allocation candidates API"

This commit is contained in:
Zuul 2018-01-27 03:34:12 +00:00 committed by Gerrit Code Review
commit 6167a89df7
11 changed files with 164 additions and 21 deletions

View File

@ -18,6 +18,7 @@ from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import timeutils
import six
import webob
from nova.api.openstack.placement import microversion
@ -117,9 +118,10 @@ def _transform_allocation_requests_list(alloc_reqs):
return results
def _transform_provider_summaries(p_sums):
def _transform_provider_summaries(p_sums, include_traits=False):
"""Turn supplied list of ProviderSummary objects into a dict, keyed by
resource provider UUID, of dicts of provider and inventory information.
resource provider UUID, of dicts of provider and inventory information. The
traits only show up when `include_traits` is `True`.
{
RP_UUID_1: {
@ -132,7 +134,11 @@ def _transform_provider_summaries(p_sums):
'capacity': 4,
'used': 0,
}
}
},
'traits': [
'HW_CPU_X86_AVX512F',
'HW_CPU_X86_AVX512CD'
]
},
RP_UUID_2: {
'resources': {
@ -144,20 +150,32 @@ def _transform_provider_summaries(p_sums):
'capacity': 4,
'used': 0,
}
}
},
'traits': [
'HW_NIC_OFFLOAD_TSO',
'HW_NIC_OFFLOAD_GRO'
]
}
}
"""
return {
ps.resource_provider.uuid: {
'resources': {
psr.resource_class: {
'capacity': psr.capacity,
'used': psr.used,
} for psr in ps.resources
}
} for ps in p_sums
}
ret = {}
for ps in p_sums:
resources = {
psr.resource_class: {
'capacity': psr.capacity,
'used': psr.used,
} for psr in ps.resources
}
ret[ps.resource_provider.uuid] = {'resources': resources}
if include_traits:
ret[ps.resource_provider.uuid]['traits'] = [
t.name for t in ps.traits]
return ret
def _transform_allocation_candidates(alloc_cands, want_version):
@ -175,7 +193,10 @@ def _transform_allocation_candidates(alloc_cands, want_version):
else:
a_reqs = _transform_allocation_requests_list(
alloc_cands.allocation_requests)
p_sums = _transform_provider_summaries(alloc_cands.provider_summaries)
include_traits = want_version.matches((1, 17))
p_sums = _transform_provider_summaries(alloc_cands.provider_summaries,
include_traits)
return {
'allocation_requests': a_reqs,
'provider_summaries': p_sums,
@ -195,7 +216,9 @@ def list_allocation_candidates(req):
context = req.environ['placement.context']
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
get_schema = schema.GET_SCHEMA_1_10
if want_version.matches((1, 16)):
if want_version.matches((1, 17)):
get_schema = schema.GET_SCHEMA_1_17
elif want_version.matches((1, 16)):
get_schema = schema.GET_SCHEMA_1_16
util.validate_query_params(req, get_schema)
@ -213,6 +236,8 @@ def list_allocation_candidates(req):
raise webob.exc.HTTPBadRequest(
_('Invalid resource class in resources parameter: %(error)s') %
{'error': exc})
except exception.TraitNotFound as exc:
raise webob.exc.HTTPBadRequest(six.text_type(exc))
response = req.response
trx_cands = _transform_allocation_candidates(cands, want_version)

View File

@ -58,6 +58,8 @@ VERSIONS = [
# representation and 'in_tree' filter on GET /resource_providers
'1.15', # Include last-modified and cache-control headers
'1.16', # Add 'limit' query parameter to GET /allocation_candidates
'1.17', # Add 'required' query parameter to GET /allocation_candidates and
# return traits in the provider summary.
]

View File

@ -214,3 +214,10 @@ header has been added to prevent inadvertent caching of resources.
Add support for a ``limit`` query parameter when making a
``GET /allocation_candidates`` request. The parameter accepts an integer
value, `N`, which limits the maximum number of candidates returned.
1.17 Add 'required' parameter to the allocation candidates
----------------------------------------------------------
Add the `required` parameter to the `GET /allocation_candidates` API. It
accepts a list of traits separated by `,`. The provider summary in the response
will include the attached traits also.

View File

@ -40,3 +40,9 @@ GET_SCHEMA_1_16['properties']['limit'] = {
"minimum": 1,
"minLength": 1
}
# Add required parameter.
GET_SCHEMA_1_17 = copy.deepcopy(GET_SCHEMA_1_16)
GET_SCHEMA_1_17['properties']['required'] = {
"type": ["string"]
}

View File

@ -306,8 +306,8 @@ def normalize_traits_qs_param(val):
"""
ret = set(substr.strip() for substr in val.split(','))
if not all(trait for trait in ret):
msg = _('Malformed traits parameter. Expected query string value '
'of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC. '
msg = _('Invalid query string parameters: Expected \'required\' '
'parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC. '
'Got: "%s"') % val
raise webob.exc.HTTPBadRequest(msg)
return ret

View File

@ -271,6 +271,10 @@ class SharedStorageFixture(APIFixture):
inv_list = rp_obj.InventoryList(objects=[vcpu_inv, ram_inv])
cn.set_inventory(inv_list)
t_avx_sse = rp_obj.Trait.get_by_name(self.context, "HW_CPU_X86_SSE")
t_avx_sse2 = rp_obj.Trait.get_by_name(self.context, "HW_CPU_X86_SSE2")
cn1.set_traits(rp_obj.TraitList(objects=[t_avx_sse, t_avx_sse2]))
# Populate shared storage provider with DISK_GB inventory
disk_inv = rp_obj.Inventory(
self.context,

View File

@ -170,3 +170,80 @@ tests:
openstack-api-version: placement 1.16
response_json_paths:
$.allocation_requests.`len`: 1
- name: get allocation candidates with required traits in old version
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=HW_CPU_X86_SSE
status: 400
request_headers:
openstack-api-version: placement 1.16
response_strings:
- Invalid query string parameters
- "'required' was unexpected"
- name: get allocation candidates without traits summary in old version
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100
status: 200
request_headers:
openstack-api-version: placement 1.16
response_json_paths:
$.provider_summaries["$ENVIRON['CN1_UUID']"].`len`: 1
$.provider_summaries["$ENVIRON['CN2_UUID']"].`len`: 1
- name: get allocation candidates with invalid trait
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=INVALID_TRAIT
status: 400
request_headers:
openstack-api-version: placement 1.17
response_strings:
- No such trait(s)
- name: get allocation candidates with empty required value
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=
status: 400
request_headers:
openstack-api-version: placement 1.17
response_strings:
- "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC."
- name: get allocation candidates with invalid required value
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=,,
status: 400
request_headers:
openstack-api-version: placement 1.17
response_strings:
- "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC."
- name: get allocation candidates with required trait
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=HW_CPU_X86_SSE
status: 200
request_headers:
openstack-api-version: placement 1.17
response_json_paths:
$.allocation_requests.`len`: 1
$.provider_summaries.`len`: 2
$.provider_summaries["$ENVIRON['CN1_UUID']"].`len`: 2
$.provider_summaries["$ENVIRON['CN1_UUID']"].traits.`sorted`:
- HW_CPU_X86_SSE
- HW_CPU_X86_SSE2
- name: get allocation candidates with multiple required traits
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=HW_CPU_X86_SSE,HW_CPU_X86_SSE2
status: 200
request_headers:
openstack-api-version: placement 1.17
response_json_paths:
$.allocation_requests.`len`: 1
$.provider_summaries.`len`: 2
$.provider_summaries["$ENVIRON['CN1_UUID']"].`len`: 2
$.provider_summaries["$ENVIRON['CN1_UUID']"].traits.`sorted`:
- HW_CPU_X86_SSE
- HW_CPU_X86_SSE2
- name: get allocation candidates with required trait and no matching
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=HW_CPU_X86_SSE3
status: 200
request_headers:
openstack-api-version: placement 1.17
response_json_paths:
$.allocation_requests.`len`: 0
$.provider_summaries.`len`: 0

View File

@ -39,13 +39,13 @@ tests:
response_json_paths:
$.errors[0].title: Not Acceptable
- name: latest microversion is 1.16
- name: latest microversion is 1.17
GET: /
request_headers:
openstack-api-version: placement latest
response_headers:
vary: /OpenStack-API-Version/
openstack-api-version: placement 1.16
openstack-api-version: placement 1.17
- name: other accept header bad version
GET: /

View File

@ -31,6 +31,7 @@ Request
- resources: resources_query_required
- limit: allocation_candidates_limit
- required: allocation_candidates_required
Response (microversions 1.12 - )
--------------------------------

View File

@ -50,6 +50,16 @@ allocation_candidates_limit:
description: >
A positive integer used to limit the maximum number of allocation
candidates returned in the response.
allocation_candidates_required:
type: string
in: query
required: false
min_version: 1.17
description: >
Accepts a list of traits separated by `,`. Allocation requests in the
response will be for resource providers that have capacity for all
requested resources and the set of those resource providers will
*collectively* contain all of the required traits.
member_of:
type: string
in: query
@ -241,7 +251,8 @@ provider_summaries:
required: true
description: >
A dictionary keyed by resource provider UUID,
of dictionaries of inventory/capacity information.
of dictionaries of inventory/capacity information. The list of traits
the resource provider has associated with it is included in version `1.17`.
reserved: &reserved
type: integer
in: body

View File

@ -0,0 +1,10 @@
---
features:
- |
Add ``required`` query parameter to the ``GET /allocation_candidates`` API
in new placement microversion 1.17. The parameter accepts a list of traits
separated by ``,``, which is used to further limit the list of allocation
requests to resource providers that have the capacity to fulfill the
requested resources AND *collectively* have all of the required traits
associated with them. In the same microversion, the candidate attached
traits returned in the provider summary.