placement: generation in provider aggregate APIs
Placement API microversion 1.19 enhances the payloads for the `GET /resource_providers/{uuid}/aggregates` response and the `PUT /resource_providers/{uuid}/aggregates` request and response to be identical, and to include the ``resource_provider_generation``. As with other generation-aware APIs, if the ``resource_provider_generation`` specified in the `PUT` request does not match the generation known by the server, a 409 Conflict error is returned. Change-Id: I86416e35da1798cdf039b42c9ed7629f0f9c75fc blueprint: placement-aggregate-generation
This commit is contained in:
parent
eb637b9de7
commit
3216f078d4
@ -11,23 +11,33 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
"""Aggregate handlers for Placement API."""
|
"""Aggregate handlers for Placement API."""
|
||||||
|
|
||||||
|
from oslo_db import exception as db_exc
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from oslo_utils import encodeutils
|
from oslo_utils import encodeutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack.placement import microversion
|
from nova.api.openstack.placement import microversion
|
||||||
from nova.api.openstack.placement.objects import resource_provider as rp_obj
|
from nova.api.openstack.placement.objects import resource_provider as rp_obj
|
||||||
from nova.api.openstack.placement.schemas import aggregate as schema
|
from nova.api.openstack.placement.schemas import aggregate as schema
|
||||||
from nova.api.openstack.placement import util
|
from nova.api.openstack.placement import util
|
||||||
from nova.api.openstack.placement import wsgi_wrapper
|
from nova.api.openstack.placement import wsgi_wrapper
|
||||||
|
from nova import exception
|
||||||
|
from nova.i18n import _
|
||||||
|
|
||||||
|
|
||||||
def _send_aggregates(req, aggregate_uuids):
|
_INCLUDE_GENERATION_VERSION = (1, 19)
|
||||||
|
|
||||||
|
|
||||||
|
def _send_aggregates(req, resource_provider, aggregate_uuids):
|
||||||
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
|
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
|
||||||
response = req.response
|
response = req.response
|
||||||
response.status = 200
|
response.status = 200
|
||||||
|
payload = _serialize_aggregates(aggregate_uuids)
|
||||||
|
if want_version.matches(min_version=_INCLUDE_GENERATION_VERSION):
|
||||||
|
payload['resource_provider_generation'] = resource_provider.generation
|
||||||
response.body = encodeutils.to_utf8(
|
response.body = encodeutils.to_utf8(
|
||||||
jsonutils.dumps(_serialize_aggregates(aggregate_uuids)))
|
jsonutils.dumps(payload))
|
||||||
response.content_type = 'application/json'
|
response.content_type = 'application/json'
|
||||||
if want_version.matches((1, 15)):
|
if want_version.matches((1, 15)):
|
||||||
req.response.cache_control = 'no-cache'
|
req.response.cache_control = 'no-cache'
|
||||||
@ -60,7 +70,7 @@ def get_aggregates(req):
|
|||||||
context, uuid)
|
context, uuid)
|
||||||
aggregate_uuids = resource_provider.get_aggregates()
|
aggregate_uuids = resource_provider.get_aggregates()
|
||||||
|
|
||||||
return _send_aggregates(req, aggregate_uuids)
|
return _send_aggregates(req, resource_provider, aggregate_uuids)
|
||||||
|
|
||||||
|
|
||||||
@wsgi_wrapper.PlacementWsgify
|
@wsgi_wrapper.PlacementWsgify
|
||||||
@ -68,10 +78,32 @@ def get_aggregates(req):
|
|||||||
@microversion.version_handler('1.1')
|
@microversion.version_handler('1.1')
|
||||||
def set_aggregates(req):
|
def set_aggregates(req):
|
||||||
context = req.environ['placement.context']
|
context = req.environ['placement.context']
|
||||||
|
want_version = req.environ[microversion.MICROVERSION_ENVIRON]
|
||||||
|
consider_generation = want_version.matches(
|
||||||
|
min_version=_INCLUDE_GENERATION_VERSION)
|
||||||
|
put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_1
|
||||||
|
if consider_generation:
|
||||||
|
put_schema = schema.PUT_AGGREGATES_SCHEMA_V1_19
|
||||||
uuid = util.wsgi_path_item(req.environ, 'uuid')
|
uuid = util.wsgi_path_item(req.environ, 'uuid')
|
||||||
resource_provider = rp_obj.ResourceProvider.get_by_uuid(
|
resource_provider = rp_obj.ResourceProvider.get_by_uuid(
|
||||||
context, uuid)
|
context, uuid)
|
||||||
aggregate_uuids = util.extract_json(req.body, schema.PUT_AGGREGATES_SCHEMA)
|
data = util.extract_json(req.body, put_schema)
|
||||||
resource_provider.set_aggregates(aggregate_uuids)
|
if consider_generation:
|
||||||
|
# Check for generation conflict
|
||||||
|
rp_gen = data['resource_provider_generation']
|
||||||
|
if resource_provider.generation != rp_gen:
|
||||||
|
raise webob.exc.HTTPConflict(
|
||||||
|
_("Resource provider's generation already changed. Please "
|
||||||
|
"update the generation and try again."))
|
||||||
|
aggregate_uuids = data['aggregates']
|
||||||
|
else:
|
||||||
|
aggregate_uuids = data
|
||||||
|
try:
|
||||||
|
resource_provider.set_aggregates(
|
||||||
|
aggregate_uuids, increment_generation=consider_generation)
|
||||||
|
except (exception.ConcurrentUpdateDetected,
|
||||||
|
db_exc.DBDuplicateEntry) as exc:
|
||||||
|
raise webob.exc.HTTPConflict(
|
||||||
|
_('Update conflict: %(error)s') % {'error': exc})
|
||||||
|
|
||||||
return _send_aggregates(req, aggregate_uuids)
|
return _send_aggregates(req, resource_provider, aggregate_uuids)
|
||||||
|
@ -61,6 +61,8 @@ VERSIONS = [
|
|||||||
'1.17', # Add 'required' query parameter to GET /allocation_candidates and
|
'1.17', # Add 'required' query parameter to GET /allocation_candidates and
|
||||||
# return traits in the provider summary.
|
# return traits in the provider summary.
|
||||||
'1.18', # Support ?required=<traits> queryparam on GET /resource_providers
|
'1.18', # Support ?required=<traits> queryparam on GET /resource_providers
|
||||||
|
'1.19', # Include generation and conflict detection in provider aggregates
|
||||||
|
# APIs
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,7 +432,9 @@ def _get_aggregates_by_provider_id(context, rp_id):
|
|||||||
|
|
||||||
|
|
||||||
@db_api.api_context_manager.writer
|
@db_api.api_context_manager.writer
|
||||||
def _set_aggregates(context, rp_id, provided_aggregates):
|
def _set_aggregates(context, resource_provider, provided_aggregates,
|
||||||
|
increment_generation=False):
|
||||||
|
rp_id = resource_provider.id
|
||||||
# When aggregate uuids are persisted no validation is done
|
# When aggregate uuids are persisted no validation is done
|
||||||
# to ensure that they refer to something that has meaning
|
# to ensure that they refer to something that has meaning
|
||||||
# elsewhere. It is assumed that code which makes use of the
|
# elsewhere. It is assumed that code which makes use of the
|
||||||
@ -489,6 +491,10 @@ def _set_aggregates(context, rp_id, provided_aggregates):
|
|||||||
select_agg_id)
|
select_agg_id)
|
||||||
context.session.execute(insert_aggregates)
|
context.session.execute(insert_aggregates)
|
||||||
|
|
||||||
|
if increment_generation:
|
||||||
|
resource_provider.generation = _increment_provider_generation(
|
||||||
|
context, resource_provider)
|
||||||
|
|
||||||
|
|
||||||
@db_api.api_context_manager.reader
|
@db_api.api_context_manager.reader
|
||||||
def _get_traits_by_provider_id(context, rp_id):
|
def _get_traits_by_provider_id(context, rp_id):
|
||||||
@ -757,13 +763,17 @@ class ResourceProvider(base.VersionedObject, base.TimestampedObject):
|
|||||||
"""Get the aggregate uuids associated with this resource provider."""
|
"""Get the aggregate uuids associated with this resource provider."""
|
||||||
return _get_aggregates_by_provider_id(self._context, self.id)
|
return _get_aggregates_by_provider_id(self._context, self.id)
|
||||||
|
|
||||||
def set_aggregates(self, aggregate_uuids):
|
def set_aggregates(self, aggregate_uuids, increment_generation=False):
|
||||||
"""Set the aggregate uuids associated with this resource provider.
|
"""Set the aggregate uuids associated with this resource provider.
|
||||||
|
|
||||||
If an aggregate does not exist, one will be created using the
|
If an aggregate does not exist, one will be created using the
|
||||||
provided uuid.
|
provided uuid.
|
||||||
|
|
||||||
|
The resource provider generation is incremented if and only if the
|
||||||
|
increment_generation parameter is True.
|
||||||
"""
|
"""
|
||||||
_set_aggregates(self._context, self.id, aggregate_uuids)
|
_set_aggregates(self._context, self, aggregate_uuids,
|
||||||
|
increment_generation=increment_generation)
|
||||||
|
|
||||||
def set_traits(self, traits):
|
def set_traits(self, traits):
|
||||||
"""Replaces the set of traits associated with the resource provider
|
"""Replaces the set of traits associated with the resource provider
|
||||||
|
@ -233,3 +233,13 @@ based on other query parameters.
|
|||||||
|
|
||||||
Trait names which are empty, do not exist, or are otherwise invalid will result
|
Trait names which are empty, do not exist, or are otherwise invalid will result
|
||||||
in a 400 error.
|
in a 400 error.
|
||||||
|
|
||||||
|
1.19 Include generation and conflict detection in provider aggregates APIs
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Enhance the payloads for the `GET /resource_providers/{uuid}/aggregates`
|
||||||
|
response and the `PUT /resource_providers/{uuid}/aggregates` request and
|
||||||
|
response to be identical, and to include the ``resource_provider_generation``.
|
||||||
|
As with other generation-aware APIs, if the ``resource_provider_generation``
|
||||||
|
specified in the `PUT` request does not match the generation known by the
|
||||||
|
server, a 409 Conflict error is returned.
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
"""Aggregate schemas for Placement API."""
|
"""Aggregate schemas for Placement API."""
|
||||||
|
import copy
|
||||||
|
|
||||||
|
|
||||||
PUT_AGGREGATES_SCHEMA = {
|
_AGGREGATES_LIST_SCHEMA = {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -20,3 +21,22 @@ PUT_AGGREGATES_SCHEMA = {
|
|||||||
},
|
},
|
||||||
"uniqueItems": True
|
"uniqueItems": True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PUT_AGGREGATES_SCHEMA_V1_1 = copy.deepcopy(_AGGREGATES_LIST_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
PUT_AGGREGATES_SCHEMA_V1_19 = {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"aggregates": copy.deepcopy(_AGGREGATES_LIST_SCHEMA),
|
||||||
|
"resource_provider_generation": {
|
||||||
|
"type": "integer",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"aggregates",
|
||||||
|
"resource_provider_generation",
|
||||||
|
],
|
||||||
|
"additionalProperties": False,
|
||||||
|
}
|
||||||
|
@ -57,22 +57,39 @@ tests:
|
|||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.errors[0].title: Not Found
|
$.errors[0].title: Not Found
|
||||||
|
|
||||||
- name: put same aggregates twice
|
- name: put some aggregates - old payload and new microversion
|
||||||
PUT: $LAST_URL
|
|
||||||
data:
|
|
||||||
- *agg_1
|
|
||||||
- *agg_1
|
|
||||||
status: 400
|
|
||||||
response_strings:
|
|
||||||
- has non-unique elements
|
|
||||||
response_json_paths:
|
|
||||||
$.errors[0].title: Bad Request
|
|
||||||
|
|
||||||
- name: put some aggregates
|
|
||||||
PUT: $LAST_URL
|
PUT: $LAST_URL
|
||||||
data:
|
data:
|
||||||
- *agg_1
|
- *agg_1
|
||||||
- *agg_2
|
- *agg_2
|
||||||
|
status: 400
|
||||||
|
response_strings:
|
||||||
|
- JSON does not validate
|
||||||
|
response_json_paths:
|
||||||
|
$.errors[0].title: Bad Request
|
||||||
|
|
||||||
|
- name: put some aggregates - new payload and old microversion
|
||||||
|
PUT: $LAST_URL
|
||||||
|
request_headers:
|
||||||
|
openstack-api-version: placement 1.18
|
||||||
|
data:
|
||||||
|
resource_provider_generation: 0
|
||||||
|
aggregates:
|
||||||
|
- *agg_1
|
||||||
|
- *agg_2
|
||||||
|
status: 400
|
||||||
|
response_strings:
|
||||||
|
- JSON does not validate
|
||||||
|
response_json_paths:
|
||||||
|
$.errors[0].title: Bad Request
|
||||||
|
|
||||||
|
- name: put some aggregates - new payload and new microversion
|
||||||
|
PUT: $LAST_URL
|
||||||
|
data:
|
||||||
|
resource_provider_generation: 0
|
||||||
|
aggregates:
|
||||||
|
- *agg_1
|
||||||
|
- *agg_2
|
||||||
status: 200
|
status: 200
|
||||||
response_headers:
|
response_headers:
|
||||||
content-type: /application/json/
|
content-type: /application/json/
|
||||||
@ -82,6 +99,7 @@ tests:
|
|||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.aggregates[0]: *agg_1
|
$.aggregates[0]: *agg_1
|
||||||
$.aggregates[1]: *agg_2
|
$.aggregates[1]: *agg_2
|
||||||
|
$.resource_provider_generation: 1
|
||||||
|
|
||||||
- name: get those aggregates
|
- name: get those aggregates
|
||||||
GET: $LAST_URL
|
GET: $LAST_URL
|
||||||
@ -92,9 +110,18 @@ tests:
|
|||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.aggregates.`len`: 2
|
$.aggregates.`len`: 2
|
||||||
|
|
||||||
|
- name: clear those aggregates - generation conflict
|
||||||
|
PUT: $LAST_URL
|
||||||
|
data:
|
||||||
|
resource_provider_generation: 0
|
||||||
|
aggregates: []
|
||||||
|
status: 409
|
||||||
|
|
||||||
- name: clear those aggregates
|
- name: clear those aggregates
|
||||||
PUT: $LAST_URL
|
PUT: $LAST_URL
|
||||||
data: []
|
data:
|
||||||
|
resource_provider_generation: 1
|
||||||
|
aggregates: []
|
||||||
status: 200
|
status: 200
|
||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.aggregates: []
|
$.aggregates: []
|
||||||
@ -113,7 +140,7 @@ tests:
|
|||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.errors[0].title: Bad Request
|
$.errors[0].title: Bad Request
|
||||||
|
|
||||||
- name: put invalid json not array
|
- name: put invalid json no generation
|
||||||
PUT: $LAST_URL
|
PUT: $LAST_URL
|
||||||
data:
|
data:
|
||||||
aggregates:
|
aggregates:
|
||||||
@ -128,11 +155,26 @@ tests:
|
|||||||
- name: put invalid json not uuids
|
- name: put invalid json not uuids
|
||||||
PUT: $LAST_URL
|
PUT: $LAST_URL
|
||||||
data:
|
data:
|
||||||
- harry
|
aggregates:
|
||||||
- sally
|
- harry
|
||||||
|
- sally
|
||||||
|
resource_provider_generation: 2
|
||||||
status: 400
|
status: 400
|
||||||
response_strings:
|
response_strings:
|
||||||
- JSON does not validate
|
- "is not a 'uuid'"
|
||||||
|
response_json_paths:
|
||||||
|
$.errors[0].title: Bad Request
|
||||||
|
|
||||||
|
- name: put same aggregates twice
|
||||||
|
PUT: $LAST_URL
|
||||||
|
data:
|
||||||
|
aggregates:
|
||||||
|
- *agg_1
|
||||||
|
- *agg_1
|
||||||
|
resource_provider_generation: 2
|
||||||
|
status: 400
|
||||||
|
response_strings:
|
||||||
|
- has non-unique elements
|
||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.errors[0].title: Bad Request
|
$.errors[0].title: Bad Request
|
||||||
|
|
||||||
|
@ -39,13 +39,13 @@ tests:
|
|||||||
response_json_paths:
|
response_json_paths:
|
||||||
$.errors[0].title: Not Acceptable
|
$.errors[0].title: Not Acceptable
|
||||||
|
|
||||||
- name: latest microversion is 1.18
|
- name: latest microversion is 1.19
|
||||||
GET: /
|
GET: /
|
||||||
request_headers:
|
request_headers:
|
||||||
openstack-api-version: placement latest
|
openstack-api-version: placement latest
|
||||||
response_headers:
|
response_headers:
|
||||||
vary: /OpenStack-API-Version/
|
vary: /OpenStack-API-Version/
|
||||||
openstack-api-version: placement 1.18
|
openstack-api-version: placement 1.19
|
||||||
|
|
||||||
- name: other accept header bad version
|
- name: other accept header bad version
|
||||||
GET: /
|
GET: /
|
||||||
|
@ -34,7 +34,9 @@ tests:
|
|||||||
- name: associate an aggregate with rp1
|
- name: associate an aggregate with rp1
|
||||||
PUT: /resource_providers/893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/aggregates
|
PUT: /resource_providers/893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/aggregates
|
||||||
data:
|
data:
|
||||||
- 83a3d69d-8920-48e2-8914-cadfd8fa2f91
|
aggregates:
|
||||||
|
- 83a3d69d-8920-48e2-8914-cadfd8fa2f91
|
||||||
|
resource_provider_generation: 0
|
||||||
status: 200
|
status: 200
|
||||||
|
|
||||||
- name: get by aggregates one result
|
- name: get by aggregates one result
|
||||||
@ -58,7 +60,9 @@ tests:
|
|||||||
- name: associate an aggregate with rp2
|
- name: associate an aggregate with rp2
|
||||||
PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates
|
PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates
|
||||||
data:
|
data:
|
||||||
- 83a3d69d-8920-48e2-8914-cadfd8fa2f91
|
aggregates:
|
||||||
|
- 83a3d69d-8920-48e2-8914-cadfd8fa2f91
|
||||||
|
resource_provider_generation: 0
|
||||||
status: 200
|
status: 200
|
||||||
|
|
||||||
- name: get by aggregates two result
|
- name: get by aggregates two result
|
||||||
@ -71,7 +75,9 @@ tests:
|
|||||||
- name: associate another aggregate with rp2
|
- name: associate another aggregate with rp2
|
||||||
PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates
|
PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates
|
||||||
data:
|
data:
|
||||||
- 99652f11-9f77-46b9-80b7-4b1989be9f8c
|
aggregates:
|
||||||
|
- 99652f11-9f77-46b9-80b7-4b1989be9f8c
|
||||||
|
resource_provider_generation: 1
|
||||||
status: 200
|
status: 200
|
||||||
|
|
||||||
- name: get by both aggregates two
|
- name: get by both aggregates two
|
||||||
@ -83,7 +89,9 @@ tests:
|
|||||||
|
|
||||||
- name: clear aggregates on rp1
|
- name: clear aggregates on rp1
|
||||||
PUT: /resource_providers/893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/aggregates
|
PUT: /resource_providers/893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/aggregates
|
||||||
data: []
|
data:
|
||||||
|
aggregates: []
|
||||||
|
resource_provider_generation: 1
|
||||||
status: 200
|
status: 200
|
||||||
|
|
||||||
- name: get by both aggregates one
|
- name: get by both aggregates one
|
||||||
|
@ -146,7 +146,9 @@ tests:
|
|||||||
- name: associate an aggregate with rp1
|
- name: associate an aggregate with rp1
|
||||||
PUT: /resource_providers/$ENVIRON['RP_UUID']/aggregates
|
PUT: /resource_providers/$ENVIRON['RP_UUID']/aggregates
|
||||||
data:
|
data:
|
||||||
- 83a3d69d-8920-48e2-8914-cadfd8fa2f91
|
aggregates:
|
||||||
|
- 83a3d69d-8920-48e2-8914-cadfd8fa2f91
|
||||||
|
resource_provider_generation: $HISTORY['list resource providers providing disk and vcpu resources'].$RESPONSE['$.resource_providers[0].generation']
|
||||||
status: 200
|
status: 200
|
||||||
|
|
||||||
- name: get by aggregates with resources
|
- name: get by aggregates with resources
|
||||||
|
@ -92,12 +92,16 @@ tests:
|
|||||||
- name: aggregate shared
|
- name: aggregate shared
|
||||||
PUT: /resource_providers/d450bd39-3b01-4355-9ea1-594f96594cf1/aggregates
|
PUT: /resource_providers/d450bd39-3b01-4355-9ea1-594f96594cf1/aggregates
|
||||||
data:
|
data:
|
||||||
- f3dc0f36-97d4-4daf-be0c-d71466da9c85
|
aggregates:
|
||||||
|
- f3dc0f36-97d4-4daf-be0c-d71466da9c85
|
||||||
|
resource_provider_generation: 1
|
||||||
|
|
||||||
- name: aggregate cn1
|
- name: aggregate cn1
|
||||||
PUT: /resource_providers/8d830468-6395-46b0-b56a-f934a1d60bbe/aggregates
|
PUT: /resource_providers/8d830468-6395-46b0-b56a-f934a1d60bbe/aggregates
|
||||||
data:
|
data:
|
||||||
- f3dc0f36-97d4-4daf-be0c-d71466da9c85
|
aggregates:
|
||||||
|
- f3dc0f36-97d4-4daf-be0c-d71466da9c85
|
||||||
|
resource_provider_generation: 1
|
||||||
|
|
||||||
# no shared trait
|
# no shared trait
|
||||||
- name: get resources no shared
|
- name: get resources no shared
|
||||||
@ -114,7 +118,7 @@ tests:
|
|||||||
- name: set trait shared
|
- name: set trait shared
|
||||||
PUT: /resource_providers/d450bd39-3b01-4355-9ea1-594f96594cf1/traits
|
PUT: /resource_providers/d450bd39-3b01-4355-9ea1-594f96594cf1/traits
|
||||||
data:
|
data:
|
||||||
resource_provider_generation: 1
|
resource_provider_generation: 2
|
||||||
traits:
|
traits:
|
||||||
- MISC_SHARES_VIA_AGGREGATE
|
- MISC_SHARES_VIA_AGGREGATE
|
||||||
|
|
||||||
|
@ -58,7 +58,8 @@ identified by `{uuid}`.
|
|||||||
|
|
||||||
Normal Response Codes: 200
|
Normal Response Codes: 200
|
||||||
|
|
||||||
Error response codes: itemNotFound(404)
|
Error response codes: itemNotFound(404) if the provider does not exist. (If the
|
||||||
|
provider has no aggregates, the result is 200 with an empty aggregate list.)
|
||||||
|
|
||||||
Request
|
Request
|
||||||
-------
|
-------
|
||||||
@ -67,19 +68,33 @@ Request
|
|||||||
|
|
||||||
- uuid: resource_provider_uuid_path
|
- uuid: resource_provider_uuid_path
|
||||||
|
|
||||||
Response
|
Response (microversions 1.1 - 1.18)
|
||||||
--------
|
-----------------------------------
|
||||||
|
|
||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- aggregates: aggregates
|
- aggregates: aggregates
|
||||||
|
|
||||||
Response Example
|
Response Example (microversions 1.1 - 1.18)
|
||||||
----------------
|
-------------------------------------------
|
||||||
|
|
||||||
.. literalinclude:: ./samples/aggregates/get-aggregates.json
|
.. literalinclude:: ./samples/aggregates/get-aggregates.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
|
Response (microversions 1.19 - )
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
|
- aggregates: aggregates
|
||||||
|
- resource_provider_generation: resource_provider_generation_v1_19
|
||||||
|
|
||||||
|
Response Example (microversions 1.19 - )
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. literalinclude:: ./samples/aggregates/get-aggregates-1.19.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
Update resource provider aggregates
|
Update resource provider aggregates
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
@ -89,31 +104,47 @@ Associate a list of aggregates with the resource provider identified by `{uuid}`
|
|||||||
|
|
||||||
Normal Response Codes: 200
|
Normal Response Codes: 200
|
||||||
|
|
||||||
Error response codes: badRequest(400), itemNotFound(404)
|
Error response codes: badRequest(400), itemNotFound(404), conflict(409)
|
||||||
|
|
||||||
Request
|
Request (microversion 1.1 - 1.18)
|
||||||
-------
|
---------------------------------
|
||||||
|
|
||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- uuid: resource_provider_uuid_path
|
- uuid: resource_provider_uuid_path
|
||||||
- aggregates: aggregates
|
- aggregates: aggregates
|
||||||
|
|
||||||
Request example
|
Request example (microversion 1.1 - 1.18)
|
||||||
---------------
|
-----------------------------------------
|
||||||
|
|
||||||
.. literalinclude:: ./samples/aggregates/update-aggregates-request.json
|
.. literalinclude:: ./samples/aggregates/update-aggregates-request.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
|
||||||
Response
|
Request (microversion 1.19 - )
|
||||||
--------
|
---------------------------------
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
|
- uuid: resource_provider_uuid_path
|
||||||
|
- aggregates: aggregates
|
||||||
|
- resource_provider_generation: resource_provider_generation_v1_19
|
||||||
|
|
||||||
|
Request example (microversion 1.19 - )
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. literalinclude:: ./samples/aggregates/update-aggregates-request-1.19.json
|
||||||
|
:language: javascript
|
||||||
|
|
||||||
|
Response (microversion 1.19 - )
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- aggregates: aggregates
|
- aggregates: aggregates
|
||||||
|
- resource_provider_generation: resource_provider_generation_v1_19
|
||||||
|
|
||||||
Response Example
|
Response Example (microversion 1.19 - )
|
||||||
----------------
|
------------------------------------------
|
||||||
|
|
||||||
.. literalinclude:: ./samples/aggregates/update-aggregates.json
|
.. literalinclude:: ./samples/aggregates/update-aggregates-1.19.json
|
||||||
:language: javascript
|
:language: javascript
|
||||||
|
@ -310,6 +310,9 @@ resource_provider_generation_optional:
|
|||||||
concurrent resource provider updates. The value is ignored;
|
concurrent resource provider updates. The value is ignored;
|
||||||
it is present to preserve symmetry between read and
|
it is present to preserve symmetry between read and
|
||||||
write representations.
|
write representations.
|
||||||
|
resource_provider_generation_v1_19:
|
||||||
|
<<: *resource_provider_generation
|
||||||
|
min_version: 1.19
|
||||||
resource_provider_links:
|
resource_provider_links:
|
||||||
type: array
|
type: array
|
||||||
in: body
|
in: body
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"aggregates": [
|
||||||
|
"42896e0d-205d-4fe3-bd1e-100924931787",
|
||||||
|
"5e08ea53-c4c6-448e-9334-ac4953de3cfa"
|
||||||
|
],
|
||||||
|
"resource_provider_generation": 8
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"aggregates": [
|
||||||
|
"42896e0d-205d-4fe3-bd1e-100924931787",
|
||||||
|
"5e08ea53-c4c6-448e-9334-ac4953de3cfa"
|
||||||
|
],
|
||||||
|
"resource_provider_generation": 9
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"aggregates": [
|
||||||
|
"42896e0d-205d-4fe3-bd1e-100924931787",
|
||||||
|
"5e08ea53-c4c6-448e-9334-ac4953de3cfa"
|
||||||
|
],
|
||||||
|
"resource_provider_generation": 9
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Placement API microversion 1.19 enhances the payloads for the
|
||||||
|
`GET /resource_providers/{uuid}/aggregates` response and the
|
||||||
|
`PUT /resource_providers/{uuid}/aggregates` request and response to be
|
||||||
|
identical, and to include the ``resource_provider_generation``. As with
|
||||||
|
other generation-aware APIs, if the ``resource_provider_generation``
|
||||||
|
specified in the `PUT` request does not match the generation known by the
|
||||||
|
server, a 409 Conflict error is returned.
|
Loading…
Reference in New Issue
Block a user