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.


Closes-Bug: #1489172
Co-Authored-By: Ruby Loo <rloo@yahoo-inc.com>
Change-Id: I6dd1ea20e23137d9a9566355adc0784067d2cb5b
Dmitry Tantsur 8 years ago committed by Ruby Loo
parent 56ef2a001c
commit 91467d3135

@ -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"""
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,
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()

@ -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.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):