Merge "placement: support traits in allocation candidates API"
This commit is contained in:
commit
6167a89df7
@ -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)
|
||||
|
@ -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.
|
||||
]
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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"]
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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: /
|
||||
|
@ -31,6 +31,7 @@ Request
|
||||
|
||||
- resources: resources_query_required
|
||||
- limit: allocation_candidates_limit
|
||||
- required: allocation_candidates_required
|
||||
|
||||
Response (microversions 1.12 - )
|
||||
--------------------------------
|
||||
|
@ -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
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user