diff --git a/api-ref/source/allocations.inc b/api-ref/source/allocations.inc index fbd8dea99..82315d2c2 100644 --- a/api-ref/source/allocations.inc +++ b/api-ref/source/allocations.inc @@ -28,8 +28,14 @@ Normal response codes: 204 Error response codes: badRequest(400), conflict(409) * `409 Conflict` if there is no available inventory in any of the - resource providers for any specified resource classes or inventories - are updated by another thread while attempting the operation. + resource providers for any specified resource classes. +* `409 Conflict` with `error code `_ + ``placement.concurrent_update`` if inventories are updated by another request + while attempting the operation. See :ref:`generations`. +* `409 Conflict` with `error code `_ + ``placement.concurrent_update`` at microversion 1.28 or higher if allocations + for a specified consumer have been created, updated, or removed by another + request while attempting the operation. See :ref:`generations`. Request ------- @@ -122,8 +128,14 @@ Normal Response Codes: 204 Error response codes: badRequest(400), itemNotFound(404), conflict(409) * `409 Conflict` if there is no available inventory in any of the - resource providers for any specified resource classes or inventories - are updated by another thread while attempting the operation. + resource providers for any specified resource classes. +* `409 Conflict` with `error code `_ + ``placement.concurrent_update`` if inventories are updated by another request + while attempting the operation. See :ref:`generations`. +* `409 Conflict` with `error code `_ + ``placement.concurrent_update`` at microversion 1.28 or higher if allocations + for the specified consumer have been created, updated, or removed by another + request while attempting the operation. See :ref:`generations`. Request (microversions 1.12 - ) ------------------------------- diff --git a/api-ref/source/errors.inc b/api-ref/source/errors.inc index 4419162c0..620cfb2f5 100644 --- a/api-ref/source/errors.inc +++ b/api-ref/source/errors.inc @@ -30,6 +30,7 @@ error response is defined by the OpenStack errors_ guideline. the above because the error is produced by code other than the placement service. +.. _`error_codes`: Error Codes =========== diff --git a/api-ref/source/generations.inc b/api-ref/source/generations.inc new file mode 100644 index 000000000..be3a0ece9 --- /dev/null +++ b/api-ref/source/generations.inc @@ -0,0 +1,48 @@ +.. _generations: + +========================================== +Resource Provider and Consumer Generations +========================================== +Placement handles concurrent requests against the same entity by maintaining a +**generation** for resource providers and consumers. The generation is an +opaque value that is updated every time its entity is successfully changed on +the server. + +At appropriate microversions, the generation is returned in responses involving +resource providers and/or consumers (allocations), and must be included in +requests which make changes to those entities. The server checks to make sure +the generation specified in the request matches the internal value. A mismatch +indicates that a different request successfully updated that entity in the +interim, thereby changing its generation. This will result in an HTTP 409 +Conflict response with `error code `_ +``placement.concurrent_update``. + +Depending on the usage scenario, an appropriate reaction to such an error may +be to re-``GET`` the entity in question, re-evaluate and update as appropriate, +and resubmit the request with the new payload. + +The following pseudocode is a simplistic example of how one might ensure that a +trait is set on a resource provider. + +.. note:: This is not production code. Aside from not being valid syntax for + any particular programming language, it deliberately glosses over + details and good programming practices such as error checking, retry + limits, etc. It is purely for illustrative purposes. + +:: + + function _is_concurrent_update(resp) { + if(resp.status_code != 409) return False + return(resp.json()["errors"][0]["code"] == "placement.concurrent_update") + } + + function ensure_trait_on_provider(provider_uuid, trait) { + do { + path = "/resource_providers/" + provider_uuid + "/traits" + get_resp = placement.GET(path) + payload = get_resp.json() + if(trait in payload["traits"]) return + payload["traits"].append(trait) + put_resp = placement.PUT(path, payload) + } while _is_concurrent_update(put_resp) + } diff --git a/api-ref/source/index.rst b/api-ref/source/index.rst index c356454ed..8919e95a3 100644 --- a/api-ref/source/index.rst +++ b/api-ref/source/index.rst @@ -16,6 +16,7 @@ header for APIs sending data payloads in the request body (i.e. ``PUT`` and .. include:: request-ids.inc .. include:: errors.inc +.. include:: generations.inc .. include:: root.inc .. include:: resource_providers.inc .. include:: resource_provider.inc