Merge "Add guidelines on Version Discovery"
This commit is contained in:
commit
81e7685d3c
@ -693,10 +693,11 @@ becomes:
|
|||||||
}
|
}
|
||||||
|
|
||||||
* If the document has a key named ``version``, (even if you just created it)
|
* If the document has a key named ``version``, (even if you just created it)
|
||||||
grab the ``href`` for the link where ``rel`` is ``self`` link. If the
|
look for a ``collection`` link in the links list. If one does not exist,
|
||||||
``href`` ends with with a version string of the form "v[0-9]+(\.[0-9]*)?$",
|
grab the ``href`` from the ``self`` link. If the ``self`` link ends with a
|
||||||
pop that element from the end of the endpoint and add an entry to the
|
version string of the form "v[0-9]+(\.[0-9]+)?$", pop that version string
|
||||||
``links`` list with a ``rel`` of ``collection`` and the resulting endpoint.
|
from the end of the endpoint and add a ``collection`` entry to the ``links``
|
||||||
|
list with the resulting endpoint.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -10,6 +10,306 @@ See also the topic document on :ref:`consuming-catalog`.
|
|||||||
|
|
||||||
See also the topic document on :doc:`consuming-catalog/version-discovery`.
|
See also the topic document on :doc:`consuming-catalog/version-discovery`.
|
||||||
|
|
||||||
|
.. _versioned-and-unversioned-endpoints:
|
||||||
|
|
||||||
|
Versioned and Unversioned Endpoints
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Each service should have a base endpoint which is referred to as the
|
||||||
|
"Unversioned" endpoint for the service.
|
||||||
|
|
||||||
|
.. note:: It is highly recommended that Cloud Operators register the
|
||||||
|
Unversioned Endpoint for a service in the Keystone Catalog. If they
|
||||||
|
do, the process described in the :ref:`version-discovery-algorithm` will
|
||||||
|
be able to be both the most featureful for the API Consumer and the
|
||||||
|
most efficient.
|
||||||
|
|
||||||
|
Each service must have at least one Major API version.
|
||||||
|
|
||||||
|
If a service has, or expects to have, more than one Major API version,
|
||||||
|
each of those versions should have a base endpoint which is referred to
|
||||||
|
as the "Versioned" endpoint for that version of the service.
|
||||||
|
|
||||||
|
All version discovery documents must be accessible via unauthenticated
|
||||||
|
connection.
|
||||||
|
|
||||||
|
If a service only uses microversions and only has one Major API version,
|
||||||
|
that service should not have any additional "Versioned" endpoints.
|
||||||
|
|
||||||
|
For instance, the Glance service at cloud ``example.com`` might have an
|
||||||
|
Unversioned Endpoint at::
|
||||||
|
|
||||||
|
https://image.example.com
|
||||||
|
|
||||||
|
That Glance service may then also provide three major versions, `v1`, `v2`, and
|
||||||
|
`v3`::
|
||||||
|
|
||||||
|
https://image.example.com/v1
|
||||||
|
https://image.example.com/v2
|
||||||
|
https://image.example.com/v3
|
||||||
|
|
||||||
|
Additionally, the Placement service at cloud ``example.com`` might have
|
||||||
|
an Unversioned Endpoint at::
|
||||||
|
|
||||||
|
https://placement.example.com
|
||||||
|
|
||||||
|
The Placement service only uses microversions, so there are no additional
|
||||||
|
Versioned Endpoints.
|
||||||
|
|
||||||
|
In both cases, the Unversioned Endpoint is the endpoint recommended to be
|
||||||
|
registered in the Service Catalog.
|
||||||
|
|
||||||
|
Preference for Subpaths
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Historically each of the OpenStack services were also given a port. It is
|
||||||
|
strongly recommended to not use those ports and instead use the normal port
|
||||||
|
443 for https. If multiple API services are to be installed on a single
|
||||||
|
machine, it is highly recommended to use subpaths::
|
||||||
|
|
||||||
|
https://api.example.com/compute
|
||||||
|
https://api.example.com/image
|
||||||
|
|
||||||
|
The rationale behind this recommendation is to ease use for users who may have
|
||||||
|
restrictive port-blocking firewalls in their operating environment. Since the
|
||||||
|
traffic is HTTP traffic and not a different protocol, it is not necessary to
|
||||||
|
distinguish it by port number, and doing so increases the chances that users
|
||||||
|
will have problems connecting to individual API endpoints.
|
||||||
|
|
||||||
|
.. _version-discovery:
|
||||||
|
|
||||||
|
Version Discovery
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Each service should provide a Version Discovery API on both the Unversioned
|
||||||
|
Endpoint and each of Versioned Endpoints of the service to be used by clients
|
||||||
|
to discover the supported API versions.
|
||||||
|
|
||||||
|
.. _unversioned-version-discovery:
|
||||||
|
|
||||||
|
Unversioned Discovery
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Each service should provide a Version Discovery API at the Unversioned Endpoint
|
||||||
|
of the service. It should be exposed to all users without authentication.
|
||||||
|
|
||||||
|
.. note:: It is recommended that the Version Discovery API not be protected
|
||||||
|
by authentication requirements. The information returned is not
|
||||||
|
specific to a user, but is, instead, a fundamental characteristic
|
||||||
|
of the base API of the service running. Additionally, the v2 and
|
||||||
|
v3 authentication API are different, so requiring authentication
|
||||||
|
before version discovery makes it harder to determine reliably
|
||||||
|
whether v2 or v3 authentication should be used.
|
||||||
|
|
||||||
|
The Unversioned Version Discovery API for each service should return a list of
|
||||||
|
Version Information for all of the Base Endpoints the service provides,
|
||||||
|
along with that version's minimum and maximum microversions. These values are
|
||||||
|
used by the client to discover the supported API versions.
|
||||||
|
|
||||||
|
|
||||||
|
:download:`Version Information Schema <version-information-schema.json>`
|
||||||
|
|
||||||
|
.. literalinclude:: version-information-schema.json
|
||||||
|
:language: json
|
||||||
|
|
||||||
|
:download:`Version Discovery Schema <version-discovery-schema.json>`
|
||||||
|
|
||||||
|
.. literalinclude:: version-discovery-schema.json
|
||||||
|
:language: json
|
||||||
|
|
||||||
|
.. _unversioned-discovery-response:
|
||||||
|
|
||||||
|
An Unversioned Version Discovery response would look as follows:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
GET /
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"id": "v2.1",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://compute.example.com/v2/",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://compute.example.com/",
|
||||||
|
"rel": "collection"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "CURRENT",
|
||||||
|
"max_version": "5.2",
|
||||||
|
"min_version": "2.1"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Each Version Information in the list should contain the following information:
|
||||||
|
|
||||||
|
id
|
||||||
|
The major API version. Follows format outlined in :ref:`versioning`,
|
||||||
|
preceeded by a "v". Required.
|
||||||
|
|
||||||
|
links
|
||||||
|
Contains information about where to find the actual versioned endpoint. See
|
||||||
|
:ref:`version-links` below. Required.
|
||||||
|
|
||||||
|
status
|
||||||
|
Support and lifecycle status of the versioned endpoint. Required.
|
||||||
|
See :ref:`endpoint-status`
|
||||||
|
|
||||||
|
max_version
|
||||||
|
The maximum microversion available if the version of the service supports
|
||||||
|
microversions. Optional. See :ref:`microversion_specification`
|
||||||
|
|
||||||
|
min_version
|
||||||
|
The minimum microversion available if the version of the service supports
|
||||||
|
microversions. Optional. See :ref:`microversion_specification`
|
||||||
|
|
||||||
|
If a service has no Versioned Endpoints, it should simply list its Base
|
||||||
|
Endpoint in the document, like so:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
GET /
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"id": "v1.0",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://placement.example.com/",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://placement.example.com/",
|
||||||
|
"rel": "collection"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "CURRENT",
|
||||||
|
"max_version": "1.25",
|
||||||
|
"min_version": "1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
.. _versioned-version-discovery:
|
||||||
|
|
||||||
|
Versioned Discovery
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Each service should provide a Version Discovery API at each Versioned Endpoint
|
||||||
|
of the service. It should be exposed to all users without authentication.
|
||||||
|
|
||||||
|
The document returned from the Version Discovery API for Versioned Endpoint
|
||||||
|
should be identical to the document returned from the Unversioned Endpoint.
|
||||||
|
In this way, a client that is looking for a version of an API can always
|
||||||
|
get the complete information in one step, rather than a sequence of attempts,
|
||||||
|
failures and re-attempts.
|
||||||
|
|
||||||
|
However, in service of getting to a perfect future from amidst an imperfect
|
||||||
|
past, services that already deliver a different document on their Versioned
|
||||||
|
Endpoints who are concerned with API breakage resulting from changing the
|
||||||
|
payload of their Versioned Version Discovery Document from a single object
|
||||||
|
named ``version`` to a list of objects named ``versions``, it can be
|
||||||
|
nonetheless a step forward to add a link to the list of links provided
|
||||||
|
that points to the Unversioned Discovery Endpoint.
|
||||||
|
|
||||||
|
For services that do not return the Versioned Version Discovery Document
|
||||||
|
inside of an object named ``version`` but instead with the information
|
||||||
|
directly in the root object, it is similarly suggested to add the
|
||||||
|
``collection`` link. (see
|
||||||
|
https://www.iana.org/assignments/link-relations/link-relations.xhtml for
|
||||||
|
the list of defined relation types)
|
||||||
|
|
||||||
|
:download:`Versioned Discovery Schema <versioned-discovery-schema.json>`
|
||||||
|
|
||||||
|
.. literalinclude:: versioned-discovery-schema.json
|
||||||
|
:language: json
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
GET /v2
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"version": {
|
||||||
|
"id": "v2.0",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://image.example.com/v2",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://image.example.com/",
|
||||||
|
"rel": "collection"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "CURRENT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.. _endpoint-status:
|
||||||
|
|
||||||
|
Endpoint Status
|
||||||
|
---------------
|
||||||
|
|
||||||
|
While it is typical for there to only be a single versioned API for a given
|
||||||
|
service, it is also sometimes useful to be able to offer more than one version
|
||||||
|
of a given API. Common examples of this are when an older version is still
|
||||||
|
made available in order to support clients that have not yet upgraded to the
|
||||||
|
current version, or when a new API version is being tested before it is
|
||||||
|
released. To distinguish these different APIs for the same service, the
|
||||||
|
`status` value is used. The following values can be returned for status:
|
||||||
|
|
||||||
|
CURRENT
|
||||||
|
The newest API that is currently being developed and improved.
|
||||||
|
Unless you need to support old code, use this API. One and only
|
||||||
|
one API must be marked as CURRENT.
|
||||||
|
|
||||||
|
SUPPORTED
|
||||||
|
An older version of the API. No new features will be added to this version,
|
||||||
|
but any bugs discovered in the code may be fixed.
|
||||||
|
|
||||||
|
DEPRECATED
|
||||||
|
This API will be removed in the foreseeable future. You should start
|
||||||
|
planning on using alternatives.
|
||||||
|
|
||||||
|
EXPERIMENTAL
|
||||||
|
This API is under development ('alpha'), and you can expect it to change or
|
||||||
|
even be removed.
|
||||||
|
|
||||||
|
.. _version-links:
|
||||||
|
|
||||||
|
Version Links
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. note:: The ``links`` conform to the :ref:`links` guideline.
|
||||||
|
|
||||||
|
The ``links`` field of the endpoint description should contain at least
|
||||||
|
two entries, listed here by the value of their ``rel`` field.
|
||||||
|
|
||||||
|
self
|
||||||
|
The location of the base endpoint for the given version of the service.
|
||||||
|
|
||||||
|
collection
|
||||||
|
The location of the base endpoint for the Unversioned Version Discovery
|
||||||
|
Endpoint. The ``collection`` entry provides guidance to allow a client to
|
||||||
|
navigate from a Versioned Endpoint that may have been listed in the
|
||||||
|
Service Catalog to the Unversioned Endpoint if they are looking for a
|
||||||
|
different version without resorting to attempting to guess at URL schemes
|
||||||
|
and performing URL manipulation.
|
||||||
|
|
||||||
Guidance
|
Guidance
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ Microversions enables the ability to introduce API changes while being able
|
|||||||
to allow clients to discover those changes. According to negotiations with
|
to allow clients to discover those changes. According to negotiations with
|
||||||
servers, clients adjust their behavior to work with server correctly.
|
servers, clients adjust their behavior to work with server correctly.
|
||||||
|
|
||||||
|
.. _versioning:
|
||||||
|
|
||||||
Versioning
|
Versioning
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@ -43,6 +45,9 @@ can be increased when supporting old clients is too great a burden.
|
|||||||
Increasing the minimum version means breaking the old clients, this happens
|
Increasing the minimum version means breaking the old clients, this happens
|
||||||
very rarely also.
|
very rarely also.
|
||||||
|
|
||||||
|
Services expose information about their minimum and maximum supported
|
||||||
|
microversion range as part of :ref:`version-discovery`.
|
||||||
|
|
||||||
Each version includes all the changes since minimum version was introduced.
|
Each version includes all the changes since minimum version was introduced.
|
||||||
It is not possible to request the feature introduced at microversion X.Y
|
It is not possible to request the feature introduced at microversion X.Y
|
||||||
without accepting all the changes before X.Y in the same request.
|
without accepting all the changes before X.Y in the same request.
|
||||||
@ -129,91 +134,6 @@ and not just the body and query parameters. See
|
|||||||
|
|
||||||
.. _microversion-parse: https://pypi.org/project/microversion_parse
|
.. _microversion-parse: https://pypi.org/project/microversion_parse
|
||||||
|
|
||||||
Version Discovery
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The Version API for each service should return the minimum and maximum
|
|
||||||
versions. These values are used by the client to discover the supported API
|
|
||||||
versions. If a service ever decides to raise the minimum version that will be
|
|
||||||
supported, it should also return the next minimum version, as well as a date
|
|
||||||
until which the current minimum version is guaranteed to be supported. If there
|
|
||||||
are no plans to change the minimum microversion, the next minimum version and
|
|
||||||
support date should be omitted.
|
|
||||||
|
|
||||||
A version response for a service that is planning on raising its minimum
|
|
||||||
supported version would look as follows::
|
|
||||||
|
|
||||||
GET /
|
|
||||||
{
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"id": "v2.1",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"href": "http://localhost:8774/v2/",
|
|
||||||
"rel": "self"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "CURRENT",
|
|
||||||
"max_version": "2.42",
|
|
||||||
"min_version": "2.1",
|
|
||||||
"next_min_version": "2.13",
|
|
||||||
"not_before": "2019-12-31"
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
.. note:: The ``links`` conform to the :ref:`links` guideline.
|
|
||||||
|
|
||||||
"max_version" is the maximum version supported; "min_version" is the minimum
|
|
||||||
version supported; "next_min_version" is the planned next minimum version; and
|
|
||||||
"not_before" is the date (in ISO YYYY-MM-DD format) before which the minimum
|
|
||||||
will not change. Note that this doesn't require that the minimum be raised on
|
|
||||||
that date; that can happen any time afterwards. It is there to give operators a
|
|
||||||
sense of how quickly they need to change their tooling to support it.
|
|
||||||
|
|
||||||
If there is no planned change to the minimum version, the response can omit the
|
|
||||||
'next_min_version' and 'not_before' values. Such a response would look like::
|
|
||||||
|
|
||||||
GET /
|
|
||||||
{
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"id": "v2.1",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"href": "http://localhost:8774/v2/",
|
|
||||||
"rel": "self"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "CURRENT",
|
|
||||||
"max_version": "2.42",
|
|
||||||
"min_version": "2.1",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
While it is typical for there to be a single API for a given service, it is
|
|
||||||
also sometimes useful to be able to offer more than one version of a given API.
|
|
||||||
Common examples of this are when an older version is still made available in
|
|
||||||
order to support clients that have not yet upgraded to the current version, or
|
|
||||||
when a new API version is being tested before it is released. To distinguish
|
|
||||||
these different APIs for the same service, the `status` value is used. The
|
|
||||||
following values can be returned for status:
|
|
||||||
|
|
||||||
============ =======
|
|
||||||
Status Meaning
|
|
||||||
============ =======
|
|
||||||
CURRENT The newest API that is currently being developed and improved.
|
|
||||||
Unless you need to support old code, use this API.
|
|
||||||
SUPPORTED An older version of the API. No new features will be added to
|
|
||||||
this version, but any bugs discovered in the code may be fixed.
|
|
||||||
DEPRECATED This API will be removed in the foreseeable future. You should
|
|
||||||
start planning on using alternatives.
|
|
||||||
EXPERIMENTAL This API is under development ('alpha'), and you can expect it to
|
|
||||||
change or even be removed.
|
|
||||||
============ =======
|
|
||||||
|
|
||||||
When the requested version is out of range for the server, the server returns
|
When the requested version is out of range for the server, the server returns
|
||||||
status code **406 Not Acceptable** along with a response body.
|
status code **406 Not Acceptable** along with a response body.
|
||||||
|
|
||||||
|
15
guidelines/version-discovery-schema.json
Normal file
15
guidelines/version-discovery-schema.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"id": "https://specs.openstack.org/openstack/api-wg/_downloads/unversioned-discovery-schema.json#",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["versions"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"versions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "version-information-schema.json#"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
guidelines/version-information-schema.json
Normal file
41
guidelines/version-information-schema.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"id": "https://specs.openstack.org/openstack/api-wg/_downloads/version-information-schema.json#",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties":false,
|
||||||
|
"required":[
|
||||||
|
"status",
|
||||||
|
"id",
|
||||||
|
"links"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"description": "Support and lifecycle status of the versioned endpoint.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"CURRENT",
|
||||||
|
"SUPPORTED",
|
||||||
|
"EXPERIMENTAL",
|
||||||
|
"DEPRECATED"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "The major API version.",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^v[0-9]{1,2}.?[0-9]{0,2}$"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"$ref": "http://json-schema.org/draft-04/links#"
|
||||||
|
},
|
||||||
|
"max_version": {
|
||||||
|
"desciption": "The maximum microversion available",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9]{1,2}.[0-9]{1,2}$"
|
||||||
|
},
|
||||||
|
"min_version": {
|
||||||
|
"desciption": "The minimum microversion available",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9]{1,2}.[0-9]{1,2}$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
guidelines/versioned-discovery-schema.json
Normal file
12
guidelines/versioned-discovery-schema.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"id": "https://specs.openstack.org/openstack/api-wg/_downloads/versioned-discovery-schema.json#",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["version"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"$ref": "version-information-schema.json#"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user