diff --git a/guidelines/consuming-catalog/version-discovery.rst b/guidelines/consuming-catalog/version-discovery.rst index ef2befc..3fd2ec1 100644 --- a/guidelines/consuming-catalog/version-discovery.rst +++ b/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: diff --git a/guidelines/discoverability.rst b/guidelines/discoverability.rst index 647eb39..af4cd02 100644 --- a/guidelines/discoverability.rst +++ b/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 ` + +.. literalinclude:: version-information-schema.json + :language: json + +:download:`Version Discovery Schema ` + +.. 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 ` + +.. 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 -------- diff --git a/guidelines/microversion_specification.rst b/guidelines/microversion_specification.rst index 6c52bbe..05cd847 100644 --- a/guidelines/microversion_specification.rst +++ b/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. diff --git a/guidelines/version-discovery-schema.json b/guidelines/version-discovery-schema.json new file mode 100644 index 0000000..8b3015b --- /dev/null +++ b/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#" + } + } + } +} diff --git a/guidelines/version-information-schema.json b/guidelines/version-information-schema.json new file mode 100644 index 0000000..ead2904 --- /dev/null +++ b/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}$" + } + } +} diff --git a/guidelines/versioned-discovery-schema.json b/guidelines/versioned-discovery-schema.json new file mode 100644 index 0000000..8bf7a42 --- /dev/null +++ b/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#" + } + } +}