From 91467d31350dbece515242dfedfd551ddae35514 Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Tue, 4 Aug 2015 13:49:48 +0200 Subject: [PATCH] Expose versioning information on GET / endpoint This returns 'min_version' (minimum supported version), 'version' (current/maximum supported version), and 'status' (of the version, is 'CURRENT' for v1) in the response to a GET / request. It makes our response to / very close to Nova's one[0], and will allow us to implement a `ironic version-list` command similar to Nova's. As this change is needed for proper versioning support on client side, it's not versioned itself. Otherwise we'll have a chicken-and-egg problem. [0]http://specs.openstack.org/openstack/nova-specs/specs/kilo/implemented/api-microversions.html#versioning Closes-Bug: #1489172 Co-Authored-By: Ruby Loo Change-Id: I6dd1ea20e23137d9a9566355adc0784067d2cb5b --- ironic/api/controllers/root.py | 50 ++++++++++++++++++++++-------- ironic/tests/unit/api/test_root.py | 16 ++++++++-- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/ironic/api/controllers/root.py b/ironic/api/controllers/root.py index 5485fd3c8c..534d4bdc35 100644 --- a/ironic/api/controllers/root.py +++ b/ironic/api/controllers/root.py @@ -21,25 +21,47 @@ 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 import expose +ID_VERSION1 = 'v1' + class Version(base.APIBase): - """An API version representation.""" + """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 version, also acts as the release number""" + """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""" - @staticmethod - def convert(id): - version = Version() - version.id = id - version.links = [link.Link.make_link('self', pecan.request.public_url, - id, '', bookmark=True)] - return version + 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): @@ -62,17 +84,19 @@ class Root(base.APIBase): root.name = "OpenStack Ironic API" root.description = ("Ironic is an OpenStack project which aims to " "provision baremetal machines.") - root.versions = [Version.convert('v1')] - root.default_version = Version.convert('v1') + root.default_version = Version(ID_VERSION1, + versions.MIN_VERSION_STRING, + versions.MAX_VERSION_STRING) + root.versions = [root.default_version] return root class RootController(rest.RestController): - _versions = ['v1'] + _versions = [ID_VERSION1] """All supported API versions""" - _default_version = 'v1' + _default_version = ID_VERSION1 """The default API version""" v1 = v1.Controller() diff --git a/ironic/tests/unit/api/test_root.py b/ironic/tests/unit/api/test_root.py index 5923fe4c29..2aa4e25baa 100644 --- a/ironic/tests/unit/api/test_root.py +++ b/ironic/tests/unit/api/test_root.py @@ -13,16 +13,26 @@ # License for the specific language governing permissions and limitations # under the License. +from ironic.api.controllers.v1 import versions from ironic.tests.unit.api import base class TestRoot(base.BaseApiTest): def test_get_root(self): - data = self.get_json('/', path_prefix='') - self.assertEqual('v1', data['default_version']['id']) + response = self.get_json('/', path_prefix='') # Check fields are not empty - [self.assertNotIn(f, ['', []]) for f in data.keys()] + [self.assertNotIn(f, ['', []]) for f in response] + + self.assertEqual('OpenStack Ironic API', response['name']) + self.assertTrue(response['description']) + self.assertEqual([response['default_version']], response['versions']) + + version1 = response['default_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']) class TestV1Root(base.BaseApiTest):