Browse Source

Add guidelines on Version Discovery

As an expansion of the guidelines around microversions, add guidelines
around how services should expose Version Discovery documents. This
includes recommendations for putting unversioned endpoints into the
catalog.

It also includes a completely new thought, so feel free to punch me in
the head - that versioned discovery documents should include a
collections rel link to allow clients to get from the versioned to the
universioned document without having to do URL manipulation. If we can
get that in, it should serve as a bridge for those clouds that are still
putting versioned endpoints into the catalog for a while for backwards
compat reasons.

Two related follow-up patches are in-work. One that adds a copy of the
consuming-discovery document with all of the extra effort in support of
clouds and services that to not implement these guidelines removed, so a
"perfect future state" is easy to read. The other is a document
recommending a global cloud "profile" that greatly reduces the API
burden on clients consuming this information.

Change-Id: Id8160048dfffc1ada32ce876a65b02fb7a02306e
changes/10/459710/19
Monty Taylor 5 years ago
parent
commit
31f6575ce4
  1. 9
      guidelines/consuming-catalog/version-discovery.rst
  2. 300
      guidelines/discoverability.rst
  3. 90
      guidelines/microversion_specification.rst
  4. 15
      guidelines/version-discovery-schema.json
  5. 41
      guidelines/version-information-schema.json
  6. 12
      guidelines/versioned-discovery-schema.json

9
guidelines/consuming-catalog/version-discovery.rst

@ -693,10 +693,11 @@ becomes:
}
* 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
``href`` ends with with a version string of the form "v[0-9]+(\.[0-9]*)?$",
pop that element from the end of the endpoint and add an entry to the
``links`` list with a ``rel`` of ``collection`` and the resulting endpoint.
look for a ``collection`` link in the links list. If one does not exist,
grab the ``href`` from the ``self`` link. If the ``self`` link ends with a
version string of the form "v[0-9]+(\.[0-9]+)?$", pop that version string
from the end of the endpoint and add a ``collection`` entry to the ``links``
list with the resulting endpoint.
For example:

300
guidelines/discoverability.rst

@ -10,6 +10,306 @@ See also the topic document on :ref:`consuming-catalog`.
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
--------

90
guidelines/microversion_specification.rst

@ -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
servers, clients adjust their behavior to work with server correctly.
.. _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
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.
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.
@ -129,91 +134,6 @@ and not just the body and query parameters. See
.. _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
status code **406 Not Acceptable** along with a response body.

15
guidelines/version-discovery-schema.json

@ -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

@ -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

@ -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…
Cancel
Save