Address issues raised in adding member_of to GET /a-c
In an earlier patch [0], there were some valid criticisms noted. They were not critical enough to require holding off on that patch, so they are being addressed here in a follow-up patch. [0] I5857e927a830914c96e040936804e322baccc24c Blueprint: alloc-candidates-member-of Change-Id: I762dc4a70613056f1bd9ba7bf11c3a4588bdac70
This commit is contained in:
parent
17ad34ff19
commit
77d3fc3838
@ -200,22 +200,8 @@ def list_resource_providers(req):
|
||||
for attr in qpkeys:
|
||||
if attr in req.GET:
|
||||
value = req.GET[attr]
|
||||
# special case member_of to always make its value a
|
||||
# list, either by accepting the single value, or if it
|
||||
# starts with 'in:' splitting on ','.
|
||||
# NOTE(cdent): This will all change when we start using
|
||||
# JSONSchema validation of query params.
|
||||
if attr == 'member_of':
|
||||
if value.startswith('in:'):
|
||||
value = value[3:].split(',')
|
||||
else:
|
||||
value = [value]
|
||||
# Make sure the values are actually UUIDs.
|
||||
for aggr_uuid in value:
|
||||
if not uuidutils.is_uuid_like(aggr_uuid):
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
_('Invalid uuid value: %(uuid)s') %
|
||||
{'uuid': aggr_uuid})
|
||||
value = util.normalize_member_of_qs_param(value)
|
||||
elif attr == 'resources':
|
||||
value = util.normalize_resources_qs_param(value)
|
||||
elif attr == 'required':
|
||||
|
@ -59,7 +59,7 @@ VERSIONS = [
|
||||
'1.19', # Include generation and conflict detection in provider aggregates
|
||||
# APIs
|
||||
'1.20', # Return 200 with provider payload from POST /resource_providers
|
||||
'1.21', # Support ?member_of=<agg UUIDs> queryparam on
|
||||
'1.21', # Support ?member_of=in:<agg UUIDs> queryparam on
|
||||
# GET /allocation_candidates
|
||||
'1.22', # Support forbidden traits in the required parameter of
|
||||
# GET /resource_providers and GET /allocation_candidates
|
||||
|
@ -1229,7 +1229,9 @@ def _get_all_with_shared(ctx, resources, member_of=None):
|
||||
# AND sharing_disk_gb.resource_provider_id IN ($RPS_SHARING_DISK)
|
||||
# INNER JOIN resource_provider_aggregates AS member_aggs
|
||||
# ON rp.id = member_aggs.resource_provider_id
|
||||
# AND member_aggs.aggregate_id IN ($MEMBER_OF)
|
||||
# INNER JOIN placement_aggregates AS p_aggs
|
||||
# ON member_aggs.aggregate_id = p_aggs.id
|
||||
# AND p_aggs.uuid IN ($MEMBER_OF)
|
||||
# WHERE (
|
||||
# (
|
||||
# COALESCE(usage_vcpu.used, 0) + $AMOUNT_VCPU <=
|
||||
|
@ -258,9 +258,10 @@ a subsequent GET.
|
||||
|
||||
Add support for the `member_of` query parameter to the `GET
|
||||
/allocation_candidates` API. It accepts a comma-separated list of UUIDs for
|
||||
aggregates. If this parameter is provided, the only resource providers returned
|
||||
will be those in one of the specified aggregates that meet the other parts of
|
||||
the request.
|
||||
aggregates. Note that if more than one aggregate UUID is passed, the
|
||||
comma-separated list must be prefixed with the "in:" operator. If this
|
||||
parameter is provided, the only resource providers returned will be those in
|
||||
one of the specified aggregates that meet the other parts of the request.
|
||||
|
||||
1.22 Support forbidden traits on resource providers and allocations candidates
|
||||
------------------------------------------------------------------------------
|
||||
|
@ -347,33 +347,36 @@ def normalize_traits_qs_param(val, allow_forbidden=False):
|
||||
return ret
|
||||
|
||||
|
||||
def normalize_member_of_qs_param(val):
|
||||
"""Parse a member_of query string parameter value.
|
||||
def normalize_member_of_qs_param(value):
|
||||
"""We need to handle member_of as a special case to always make its value a
|
||||
list, either by accepting the single value, or if it starts with 'in:'
|
||||
splitting on ','.
|
||||
|
||||
Valid values are either a single UUID, or the prefix 'in:' followed by two
|
||||
or more comma-separated UUIDs.
|
||||
NOTE(cdent): This will all change when we start using
|
||||
JSONSchema validation of query params.
|
||||
|
||||
:param val: A member_of query parameter of either a single UUID, or a
|
||||
comma-separated string of two or more UUIDs.
|
||||
:return: A list of UUIDs
|
||||
:raises `webob.exc.HTTPBadRequest` if the val parameter is not in the
|
||||
:param value: A member_of query parameter of either a single UUID, or a
|
||||
comma-separated string of one or more UUIDs, prefixed with
|
||||
the "in:" operator.
|
||||
:return: A set of UUIDs
|
||||
:raises `webob.exc.HTTPBadRequest` if the value parameter is not in the
|
||||
expected format.
|
||||
"""
|
||||
# Ensure that multiple values are prefixed with "in:"
|
||||
if "," in val and not val.startswith("in:"):
|
||||
if "," in value and not value.startswith("in:"):
|
||||
msg = _("Multiple values for 'member_of' must be prefixed with the "
|
||||
"'in:' keyword. Got: %s") % val
|
||||
"'in:' keyword. Got: %s") % value
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
if val.startswith("in:"):
|
||||
ret = val[3:].split(",")
|
||||
if value.startswith('in:'):
|
||||
value = set(value[3:].split(','))
|
||||
else:
|
||||
ret = [val]
|
||||
# Ensure the UUIDs are valid
|
||||
if not all([uuidutils.is_uuid_like(agg) for agg in ret]):
|
||||
msg = _("Invalid query string parameters: Expected 'member_of' "
|
||||
"parameter to contain valid UUID(s). Got: %s") % val
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
return ret
|
||||
value = set([value])
|
||||
# Make sure the values are actually UUIDs.
|
||||
for aggr_uuid in value:
|
||||
if not uuidutils.is_uuid_like(aggr_uuid):
|
||||
msg = _("Invalid query string parameters: Expected 'member_of' "
|
||||
"parameter to contain valid UUID(s). Got: %s") % value
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
return value
|
||||
|
||||
|
||||
def parse_qs_request_groups(qsdict, allow_forbidden=False):
|
||||
@ -383,7 +386,7 @@ def parse_qs_request_groups(qsdict, allow_forbidden=False):
|
||||
The input qsdict represents a query string of the form:
|
||||
|
||||
?resources=$RESOURCE_CLASS_NAME:$AMOUNT,$RESOURCE_CLASS_NAME:$AMOUNT
|
||||
&required=$TRAIT_NAME,$TRAIT_NAME&member_of=$AGG_UUID
|
||||
&required=$TRAIT_NAME,$TRAIT_NAME&member_of=in:$AGG1_UUID,$AGG2_UUID
|
||||
&resources1=$RESOURCE_CLASS_NAME:$AMOUNT,RESOURCE_CLASS_NAME:$AMOUNT
|
||||
&required1=$TRAIT_NAME,$TRAIT_NAME&member_of1=$AGG_UUID
|
||||
&resources2=$RESOURCE_CLASS_NAME:$AMOUNT,RESOURCE_CLASS_NAME:$AMOUNT
|
||||
|
@ -25,8 +25,7 @@ tests:
|
||||
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&member_of=INVALID_UUID
|
||||
status: 400
|
||||
response_strings:
|
||||
- Invalid query string parameters
|
||||
- Expected 'member_of' parameter to contain valid UUID(s)
|
||||
- Expected 'member_of' parameter to contain valid UUID(s).
|
||||
|
||||
- name: get allocation candidates no 'in:' for multiple member_of
|
||||
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&member_of=$ENVIRON['AGGA_UUID'],$ENVIRON['AGGB_UUID']
|
||||
@ -38,8 +37,13 @@ tests:
|
||||
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&member_of=in:$ENVIRON['AGGA_UUID'],INVALID_UUID
|
||||
status: 400
|
||||
response_strings:
|
||||
- Invalid query string parameters
|
||||
- Expected 'member_of' parameter to contain valid UUID(s)
|
||||
- Expected 'member_of' parameter to contain valid UUID(s).
|
||||
|
||||
- name: get allocation candidates multiple member_of with 'in:' but no aggregates
|
||||
GET: /allocation_candidates?&member_of=in:&resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100
|
||||
status: 400
|
||||
response_strings:
|
||||
- Expected 'member_of' parameter to contain valid UUID(s).
|
||||
|
||||
- name: get allocation candidates with no match for member_of
|
||||
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&member_of=$ENVIRON['AGGA_UUID']
|
||||
@ -86,3 +90,21 @@ tests:
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.allocation_requests.`len`: 0
|
||||
|
||||
- name: get current compute node 1 state
|
||||
GET: /resource_providers/$ENVIRON['CN1_UUID']
|
||||
|
||||
- name: now associate the first compute node with both aggA and aggC
|
||||
PUT: /resource_providers/$ENVIRON['CN1_UUID']/aggregates
|
||||
data:
|
||||
aggregates:
|
||||
- $ENVIRON['AGGA_UUID']
|
||||
- $ENVIRON['AGGC_UUID']
|
||||
resource_provider_generation: $HISTORY['get current compute node 1 state'].$RESPONSE['$.generation']
|
||||
|
||||
- name: verify that the member_of call for aggs A and B still returns 2 allocation_candidates
|
||||
GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&member_of=in:$ENVIRON['AGGA_UUID'],$ENVIRON['AGGB_UUID']
|
||||
status: 200
|
||||
response_json_paths:
|
||||
$.allocation_requests.`len`: 2
|
||||
status: 200
|
||||
|
@ -53,7 +53,7 @@ tests:
|
||||
GET: '/resource_providers?member_of=not+a+uuid'
|
||||
status: 400
|
||||
response_strings:
|
||||
- 'Invalid uuid value: not a uuid'
|
||||
- Expected 'member_of' parameter to contain valid UUID(s).
|
||||
response_json_paths:
|
||||
$.errors[0].title: Bad Request
|
||||
|
||||
|
@ -32,7 +32,7 @@ Request
|
||||
- resources: resources_query_required
|
||||
- limit: allocation_candidates_limit
|
||||
- required: allocation_candidates_required
|
||||
- member_of: member_of
|
||||
- member_of: member_of_1_21
|
||||
|
||||
Response (microversions 1.12 - )
|
||||
--------------------------------
|
||||
|
@ -62,7 +62,7 @@ allocation_candidates_required:
|
||||
*collectively* contain all of the required traits. **Starting from
|
||||
microversion 1.22** traits which are forbidden from any resource provider
|
||||
may be expressed by prefixing a trait with a ``!``.
|
||||
member_of:
|
||||
member_of: &member_of
|
||||
type: string
|
||||
in: query
|
||||
required: false
|
||||
@ -75,6 +75,9 @@ member_of:
|
||||
member_of=5e08ea53-c4c6-448e-9334-ac4953de3cfa
|
||||
member_of=in:42896e0d-205d-4fe3-bd1e-100924931787,5e08ea53-c4c6-448e-9334-ac4953de3cfa
|
||||
min_version: 1.3
|
||||
member_of_1_21:
|
||||
<<: *member_of
|
||||
min_version: 1.21
|
||||
project_id: &project_id
|
||||
type: string
|
||||
in: query
|
||||
|
Loading…
Reference in New Issue
Block a user