From 1f03a572686e6b76d2d569558bc8e2ca6b1bfd3d Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Mon, 27 Aug 2018 10:45:31 +0200 Subject: [PATCH] Add version discovery information to the /v1 endpoint Currently we do not provide enough information for keystoneauth to work on. This makes version discovery impossible e.g. in a standalone case when the versioned endpoint is supplied by a user. This change adds the required versioning information based on the actual keystoneauth implementation and the in-progress API SIG specification: https://review.openstack.org/#/c/459710/ Note that this change is not microversioned, as it is used to discover available microversions for the versioned endpoint. Change-Id: Ibb1e8a1c8973a4742b7ba508dc84de577cb967c9 Story: #2003567 Task: #24859 --- ironic/api/controllers/root.py | 54 ++------------- ironic/api/controllers/v1/__init__.py | 5 ++ ironic/api/controllers/version.py | 65 +++++++++++++++++++ ironic/tests/unit/api/test_root.py | 9 ++- .../notes/v1-discovery-4311398040581fe8.yaml | 6 ++ 5 files changed, 90 insertions(+), 49 deletions(-) create mode 100644 ironic/api/controllers/version.py create mode 100644 releasenotes/notes/v1-discovery-4311398040581fe8.yaml diff --git a/ironic/api/controllers/root.py b/ironic/api/controllers/root.py index 5fc14a5305..574d1fc4b5 100644 --- a/ironic/api/controllers/root.py +++ b/ironic/api/controllers/root.py @@ -19,50 +19,10 @@ from pecan import rest from wsme import types as wtypes from ironic.api.controllers import base -from ironic.api.controllers import link from ironic.api.controllers import v1 -from ironic.api.controllers.v1 import versions +from ironic.api.controllers import version from ironic.api import expose -ID_VERSION1 = 'v1' - - -class Version(base.APIBase): - """An API version representation. - - This class represents an API version, including the minimum and - maximum minor versions that are supported within the major version. - """ - - id = wtypes.text - """The ID of the (major) version, also acts as the release number""" - - links = [link.Link] - """A Link that point to a specific version of the API""" - - status = wtypes.text - """Status of the version. - - One of: - * CURRENT - the latest version of API, - * SUPPORTED - supported, but not latest, version of API, - * DEPRECATED - supported, but deprecated, version of API. - """ - - version = wtypes.text - """The current, maximum supported (major.minor) version of API.""" - - min_version = wtypes.text - """Minimum supported (major.minor) version of API.""" - - def __init__(self, id, min_version, version, status='CURRENT'): - self.id = id - self.links = [link.Link.make_link('self', pecan.request.public_url, - self.id, '', bookmark=True)] - self.status = status - self.version = version - self.min_version = min_version - class Root(base.APIBase): @@ -72,10 +32,10 @@ class Root(base.APIBase): description = wtypes.text """Some information about this API""" - versions = [Version] + versions = [version.Version] """Links to all the versions available in this API""" - default_version = Version + default_version = version.Version """A link to the default version of the API""" @staticmethod @@ -84,19 +44,17 @@ class Root(base.APIBase): root.name = "OpenStack Ironic API" root.description = ("Ironic is an OpenStack project which aims to " "provision baremetal machines.") - root.default_version = Version(ID_VERSION1, - versions.min_version_string(), - versions.max_version_string()) + root.default_version = version.default_version() root.versions = [root.default_version] return root class RootController(rest.RestController): - _versions = [ID_VERSION1] + _versions = [version.ID_VERSION1] """All supported API versions""" - _default_version = ID_VERSION1 + _default_version = version.ID_VERSION1 """The default API version""" v1 = v1.Controller() diff --git a/ironic/api/controllers/v1/__init__.py b/ironic/api/controllers/v1/__init__.py index a94a14ac9f..4af57f94b8 100644 --- a/ironic/api/controllers/v1/__init__.py +++ b/ironic/api/controllers/v1/__init__.py @@ -34,6 +34,7 @@ from ironic.api.controllers.v1 import ramdisk from ironic.api.controllers.v1 import utils from ironic.api.controllers.v1 import versions from ironic.api.controllers.v1 import volume +from ironic.api.controllers import version from ironic.api import expose from ironic.common.i18n import _ @@ -99,6 +100,9 @@ class V1(base.APIBase): heartbeat = [link.Link] """Links to the heartbeat resource""" + version = version.Version + """Version discovery information.""" + @staticmethod def convert(): v1 = V1() @@ -174,6 +178,7 @@ class V1(base.APIBase): 'heartbeat', '', bookmark=True) ] + v1.version = version.default_version() return v1 diff --git a/ironic/api/controllers/version.py b/ironic/api/controllers/version.py new file mode 100644 index 0000000000..4516b83643 --- /dev/null +++ b/ironic/api/controllers/version.py @@ -0,0 +1,65 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import pecan +from wsme import types as wtypes + +from ironic.api.controllers import base +from ironic.api.controllers import link + +ID_VERSION1 = 'v1' + + +class Version(base.APIBase): + """An API version representation. + + This class represents an API version, including the minimum and + maximum minor versions that are supported within the major version. + """ + + id = wtypes.text + """The ID of the (major) version, also acts as the release number""" + + links = [link.Link] + """A Link that point to a specific version of the API""" + + status = wtypes.text + """Status of the version. + + One of: + * CURRENT - the latest version of API, + * SUPPORTED - supported, but not latest, version of API, + * DEPRECATED - supported, but deprecated, version of API. + """ + + version = wtypes.text + """The current, maximum supported (major.minor) version of API.""" + + min_version = wtypes.text + """Minimum supported (major.minor) version of API.""" + + def __init__(self, id, min_version, version, status='CURRENT'): + self.id = id + self.links = [link.Link.make_link('self', pecan.request.public_url, + self.id, '', bookmark=True)] + self.status = status + self.version = version + self.min_version = min_version + + +def default_version(): + # NOTE(dtantsur): avoid circular imports + from ironic.api.controllers.v1 import versions + + return Version(ID_VERSION1, + versions.min_version_string(), + versions.max_version_string()) diff --git a/ironic/tests/unit/api/test_root.py b/ironic/tests/unit/api/test_root.py index 3ca47fae45..84da885b27 100644 --- a/ironic/tests/unit/api/test_root.py +++ b/ironic/tests/unit/api/test_root.py @@ -49,7 +49,7 @@ class TestV1Root(base.BaseApiTest): for f in data: self.assertNotIn(f, ['', []]) # Check if all known resources are present and there are no extra ones. - not_resources = ('id', 'links', 'media_types') + not_resources = ('id', 'links', 'media_types', 'version') actual_resources = tuple(set(data) - set(not_resources)) expected_resources = (['chassis', 'drivers', 'nodes', 'ports'] + additional_expected_resources) @@ -57,6 +57,13 @@ class TestV1Root(base.BaseApiTest): self.assertIn({'type': 'application/vnd.openstack.ironic.v1+json', 'base': 'application/json'}, data['media_types']) + version1 = data['version'] + self.assertEqual('v1', version1['id']) + self.assertEqual('CURRENT', version1['status']) + self.assertEqual(versions.min_version_string(), + version1['min_version']) + self.assertEqual(versions.max_version_string(), version1['version']) + def test_get_v1_root(self): self._test_get_root() diff --git a/releasenotes/notes/v1-discovery-4311398040581fe8.yaml b/releasenotes/notes/v1-discovery-4311398040581fe8.yaml new file mode 100644 index 0000000000..2537442ef4 --- /dev/null +++ b/releasenotes/notes/v1-discovery-4311398040581fe8.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Adds the version discovery information to the versioned API endpoint + (``/v1``). This allows *keystoneauth* version discovery to work on this + endpoint.