Make Keystone return v3 as part of the version api
The keystone "get version" api currently fails to list v3 as a supported api. It should now do this, along with v2 (which is, of course, still supported) Fixes Bug #1148186 Change-Id: Ie88bf941123702d2f7e2ecf6cecb1fa937ca1e52
This commit is contained in:
parent
756cd5a297
commit
2dd6481a20
@ -23,6 +23,9 @@ from keystone import exception
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
MEDIA_TYPE_JSON = 'application/vnd.openstack.identity-%s+json'
|
||||||
|
MEDIA_TYPE_XML = 'application/vnd.openstack.identity-%s+xml'
|
||||||
|
|
||||||
|
|
||||||
class Extensions(wsgi.Application):
|
class Extensions(wsgi.Application):
|
||||||
"""Base extensions controller to be extended by public and admin API's."""
|
"""Base extensions controller to be extended by public and admin API's."""
|
||||||
@ -113,12 +116,30 @@ class Version(wsgi.Application):
|
|||||||
'media-types': [
|
'media-types': [
|
||||||
{
|
{
|
||||||
'base': 'application/json',
|
'base': 'application/json',
|
||||||
'type': 'application/vnd.openstack.identity-v2.0'
|
'type': MEDIA_TYPE_JSON % 'v2.0'
|
||||||
'+json'
|
|
||||||
}, {
|
}, {
|
||||||
'base': 'application/xml',
|
'base': 'application/xml',
|
||||||
'type': 'application/vnd.openstack.identity-v2.0'
|
'type': MEDIA_TYPE_XML % 'v2.0'
|
||||||
'+xml'
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
versions['v3'] = {
|
||||||
|
'id': 'v3.0',
|
||||||
|
'status': 'stable',
|
||||||
|
'updated': '2013-03-06T00:00:00Z',
|
||||||
|
'links': [
|
||||||
|
{
|
||||||
|
'rel': 'self',
|
||||||
|
'href': self._get_identity_url(version='v3'),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'media-types': [
|
||||||
|
{
|
||||||
|
'base': 'application/json',
|
||||||
|
'type': MEDIA_TYPE_JSON % 'v3'
|
||||||
|
}, {
|
||||||
|
'base': 'application/xml',
|
||||||
|
'type': MEDIA_TYPE_XML % 'v3'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -133,8 +154,14 @@ class Version(wsgi.Application):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_version(self, context):
|
def get_version_v2(self, context):
|
||||||
versions = self._get_versions_list(context)
|
versions = self._get_versions_list(context)
|
||||||
return wsgi.render_response(body={
|
return wsgi.render_response(body={
|
||||||
'version': versions['v2.0']
|
'version': versions['v2.0']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def get_version_v3(self, context):
|
||||||
|
versions = self._get_versions_list(context)
|
||||||
|
return wsgi.render_response(body={
|
||||||
|
'version': versions['v3']
|
||||||
|
})
|
||||||
|
@ -47,7 +47,7 @@ class Extension(wsgi.ComposableRouter):
|
|||||||
conditions=dict(method=['GET']))
|
conditions=dict(method=['GET']))
|
||||||
|
|
||||||
|
|
||||||
class Version(wsgi.ComposableRouter):
|
class VersionV2(wsgi.ComposableRouter):
|
||||||
def __init__(self, description):
|
def __init__(self, description):
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
||||||
@ -55,7 +55,18 @@ class Version(wsgi.ComposableRouter):
|
|||||||
version_controller = controllers.Version(self.description)
|
version_controller = controllers.Version(self.description)
|
||||||
mapper.connect('/',
|
mapper.connect('/',
|
||||||
controller=version_controller,
|
controller=version_controller,
|
||||||
action='get_version')
|
action='get_version_v2')
|
||||||
|
|
||||||
|
|
||||||
|
class VersionV3(wsgi.ComposableRouter):
|
||||||
|
def __init__(self, description):
|
||||||
|
self.description = description
|
||||||
|
|
||||||
|
def add_routes(self, mapper):
|
||||||
|
version_controller = controllers.Version(self.description)
|
||||||
|
mapper.connect('/',
|
||||||
|
controller=version_controller,
|
||||||
|
action='get_version_v3')
|
||||||
|
|
||||||
|
|
||||||
class Versions(wsgi.ComposableRouter):
|
class Versions(wsgi.ComposableRouter):
|
||||||
|
@ -46,7 +46,7 @@ def public_app_factory(global_conf, **local_conf):
|
|||||||
return wsgi.ComposingRouter(routes.Mapper(),
|
return wsgi.ComposingRouter(routes.Mapper(),
|
||||||
[identity.routers.Public(),
|
[identity.routers.Public(),
|
||||||
token.routers.Router(),
|
token.routers.Router(),
|
||||||
routers.Version('public'),
|
routers.VersionV2('public'),
|
||||||
routers.Extension(False)])
|
routers.Extension(False)])
|
||||||
|
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ def admin_app_factory(global_conf, **local_conf):
|
|||||||
return wsgi.ComposingRouter(routes.Mapper(),
|
return wsgi.ComposingRouter(routes.Mapper(),
|
||||||
[identity.routers.Admin(),
|
[identity.routers.Admin(),
|
||||||
token.routers.Router(),
|
token.routers.Router(),
|
||||||
routers.Version('admin'),
|
routers.VersionV2('admin'),
|
||||||
routers.Extension()])
|
routers.Extension()])
|
||||||
|
|
||||||
|
|
||||||
@ -85,5 +85,8 @@ def v3_app_factory(global_conf, **local_conf):
|
|||||||
v3routers = []
|
v3routers = []
|
||||||
for module in [auth, catalog, identity, policy, trust]:
|
for module in [auth, catalog, identity, policy, trust]:
|
||||||
module.routers.append_v3_routers(mapper, v3routers)
|
module.routers.append_v3_routers(mapper, v3routers)
|
||||||
|
# Add in the v3 version api
|
||||||
|
v3routers.append(routers.VersionV3('admin'))
|
||||||
|
v3routers.append(routers.VersionV3('public'))
|
||||||
# TODO(ayoung): put token routes here
|
# TODO(ayoung): put token routes here
|
||||||
return wsgi.ComposingRouter(mapper, v3routers)
|
return wsgi.ComposingRouter(mapper, v3routers)
|
||||||
|
@ -22,6 +22,91 @@ from keystone import test
|
|||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
v2_MEDIA_TYPES = [
|
||||||
|
{
|
||||||
|
"base": "application/json",
|
||||||
|
"type": "application/"
|
||||||
|
"vnd.openstack.identity-v2.0+json"
|
||||||
|
}, {
|
||||||
|
"base": "application/xml",
|
||||||
|
"type": "application/"
|
||||||
|
"vnd.openstack.identity-v2.0+xml"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
v2_HTML_DESCRIPTION = {
|
||||||
|
"rel": "describedby",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "http://docs.openstack.org/api/"
|
||||||
|
"openstack-identity-service/2.0/"
|
||||||
|
"content/"
|
||||||
|
}
|
||||||
|
|
||||||
|
v2_PDF_DESCRIPTION = {
|
||||||
|
"rel": "describedby",
|
||||||
|
"type": "application/pdf",
|
||||||
|
"href": "http://docs.openstack.org/api/"
|
||||||
|
"openstack-identity-service/2.0/"
|
||||||
|
"identity-dev-guide-2.0.pdf"
|
||||||
|
}
|
||||||
|
|
||||||
|
v2_EXPECTED_RESPONSE = {
|
||||||
|
"id": "v2.0",
|
||||||
|
"status": "stable",
|
||||||
|
"updated": "2013-03-06T00:00:00Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"href": "", # Will get filled in after initialization
|
||||||
|
},
|
||||||
|
v2_HTML_DESCRIPTION,
|
||||||
|
v2_PDF_DESCRIPTION
|
||||||
|
],
|
||||||
|
"media-types": v2_MEDIA_TYPES
|
||||||
|
}
|
||||||
|
|
||||||
|
v2_VERSION_RESPONSE = {
|
||||||
|
"version": v2_EXPECTED_RESPONSE
|
||||||
|
}
|
||||||
|
|
||||||
|
v3_MEDIA_TYPES = [
|
||||||
|
{
|
||||||
|
"base": "application/json",
|
||||||
|
"type": "application/"
|
||||||
|
"vnd.openstack.identity-v3+json"
|
||||||
|
}, {
|
||||||
|
"base": "application/xml",
|
||||||
|
"type": "application/"
|
||||||
|
"vnd.openstack.identity-v3+xml"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
v3_EXPECTED_RESPONSE = {
|
||||||
|
"id": "v3.0",
|
||||||
|
"status": "stable",
|
||||||
|
"updated": "2013-03-06T00:00:00Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"href": "", # Will get filled in after initialization
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"media-types": v3_MEDIA_TYPES
|
||||||
|
}
|
||||||
|
|
||||||
|
v3_VERSION_RESPONSE = {
|
||||||
|
"version": v3_EXPECTED_RESPONSE
|
||||||
|
}
|
||||||
|
|
||||||
|
VERSIONS_RESPONSE = {
|
||||||
|
"versions": {
|
||||||
|
"values": [
|
||||||
|
v3_EXPECTED_RESPONSE,
|
||||||
|
v2_EXPECTED_RESPONSE
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class VersionTestCase(test.TestCase):
|
class VersionTestCase(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -33,52 +118,24 @@ class VersionTestCase(test.TestCase):
|
|||||||
self.public_server = self.serveapp('keystone', name='main')
|
self.public_server = self.serveapp('keystone', name='main')
|
||||||
self.admin_server = self.serveapp('keystone', name='admin')
|
self.admin_server = self.serveapp('keystone', name='admin')
|
||||||
|
|
||||||
|
def _paste_in_port(self, response, port):
|
||||||
|
for link in response['links']:
|
||||||
|
if link['rel'] == 'self':
|
||||||
|
link['href'] = port
|
||||||
|
|
||||||
def test_public_versions(self):
|
def test_public_versions(self):
|
||||||
client = self.client(self.public_app)
|
client = self.client(self.public_app)
|
||||||
resp = client.get('/')
|
resp = client.get('/')
|
||||||
self.assertEqual(resp.status_int, 300)
|
self.assertEqual(resp.status_int, 300)
|
||||||
data = jsonutils.loads(resp.body)
|
data = jsonutils.loads(resp.body)
|
||||||
expected = {
|
expected = VERSIONS_RESPONSE
|
||||||
"versions": {
|
for version in expected['versions']['values']:
|
||||||
"values": [
|
if version['id'] == 'v3.0':
|
||||||
{
|
self._paste_in_port(
|
||||||
"id": "v2.0",
|
version, 'http://localhost:%s/v3/' % CONF.public_port)
|
||||||
"status": "stable",
|
elif version['id'] == 'v2.0':
|
||||||
"updated": '2013-03-06T00:00:00Z',
|
self._paste_in_port(
|
||||||
"links": [
|
version, 'http://localhost:%s/v2.0/' % CONF.public_port)
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"href": "http://localhost:%s/v2.0/" %
|
|
||||||
CONF.public_port,
|
|
||||||
}, {
|
|
||||||
"rel": "describedby",
|
|
||||||
"type": "text/html",
|
|
||||||
"href": "http://docs.openstack.org/api/"
|
|
||||||
"openstack-identity-service/2.0/"
|
|
||||||
"content/"
|
|
||||||
}, {
|
|
||||||
"rel": "describedby",
|
|
||||||
"type": "application/pdf",
|
|
||||||
"href": "http://docs.openstack.org/api/"
|
|
||||||
"openstack-identity-service/2.0/"
|
|
||||||
"identity-dev-guide-2.0.pdf"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"media-types": [
|
|
||||||
{
|
|
||||||
"base": "application/json",
|
|
||||||
"type": "application/"
|
|
||||||
"vnd.openstack.identity-v2.0+json"
|
|
||||||
}, {
|
|
||||||
"base": "application/xml",
|
|
||||||
"type": "application/"
|
|
||||||
"vnd.openstack.identity-v2.0+xml"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.assertEqual(data, expected)
|
self.assertEqual(data, expected)
|
||||||
|
|
||||||
def test_admin_versions(self):
|
def test_admin_versions(self):
|
||||||
@ -86,45 +143,53 @@ class VersionTestCase(test.TestCase):
|
|||||||
resp = client.get('/')
|
resp = client.get('/')
|
||||||
self.assertEqual(resp.status_int, 300)
|
self.assertEqual(resp.status_int, 300)
|
||||||
data = jsonutils.loads(resp.body)
|
data = jsonutils.loads(resp.body)
|
||||||
expected = {
|
expected = VERSIONS_RESPONSE
|
||||||
"versions": {
|
for version in expected['versions']['values']:
|
||||||
"values": [
|
if version['id'] == 'v3.0':
|
||||||
{
|
self._paste_in_port(
|
||||||
"id": "v2.0",
|
version, 'http://localhost:%s/v3/' % CONF.admin_port)
|
||||||
"status": "stable",
|
elif version['id'] == 'v2.0':
|
||||||
"updated": '2013-03-06T00:00:00Z',
|
self._paste_in_port(
|
||||||
"links": [
|
version, 'http://localhost:%s/v2.0/' % CONF.admin_port)
|
||||||
{
|
self.assertEqual(data, expected)
|
||||||
"rel": "self",
|
|
||||||
"href": "http://localhost:%s/v2.0/" %
|
def test_public_version_v2(self):
|
||||||
CONF.admin_port,
|
client = self.client(self.public_app)
|
||||||
}, {
|
resp = client.get('/v2.0/')
|
||||||
"rel": "describedby",
|
self.assertEqual(resp.status_int, 200)
|
||||||
"type": "text/html",
|
data = jsonutils.loads(resp.body)
|
||||||
"href": "http://docs.openstack.org/api/"
|
expected = v2_VERSION_RESPONSE
|
||||||
"openstack-identity-service/2.0/"
|
self._paste_in_port(expected['version'],
|
||||||
"content/"
|
'http://localhost:%s/v2.0/' % CONF.public_port)
|
||||||
}, {
|
self.assertEqual(data, expected)
|
||||||
"rel": "describedby",
|
|
||||||
"type": "application/pdf",
|
def test_admin_version_v2(self):
|
||||||
"href": "http://docs.openstack.org/api/"
|
client = self.client(self.admin_app)
|
||||||
"openstack-identity-service/2.0/"
|
resp = client.get('/v2.0/')
|
||||||
"identity-dev-guide-2.0.pdf"
|
self.assertEqual(resp.status_int, 200)
|
||||||
}
|
data = jsonutils.loads(resp.body)
|
||||||
],
|
expected = v2_VERSION_RESPONSE
|
||||||
"media-types": [
|
self._paste_in_port(expected['version'],
|
||||||
{
|
'http://localhost:%s/v2.0/' % CONF.admin_port)
|
||||||
"base": "application/json",
|
self.assertEqual(data, expected)
|
||||||
"type": "application/"
|
|
||||||
"vnd.openstack.identity-v2.0+json"
|
def test_public_version_v3(self):
|
||||||
}, {
|
print CONF.public_port
|
||||||
"base": "application/xml",
|
client = self.client(self.public_app)
|
||||||
"type": "application/"
|
resp = client.get('/v3/')
|
||||||
"vnd.openstack.identity-v2.0+xml"
|
self.assertEqual(resp.status_int, 200)
|
||||||
}
|
data = jsonutils.loads(resp.body)
|
||||||
]
|
expected = v3_VERSION_RESPONSE
|
||||||
}
|
self._paste_in_port(expected['version'],
|
||||||
]
|
'http://localhost:%s/v3/' % CONF.public_port)
|
||||||
}
|
self.assertEqual(data, expected)
|
||||||
}
|
|
||||||
|
def test_admin_version_v3(self):
|
||||||
|
client = self.client(self.public_app)
|
||||||
|
resp = client.get('/v3/')
|
||||||
|
self.assertEqual(resp.status_int, 200)
|
||||||
|
data = jsonutils.loads(resp.body)
|
||||||
|
expected = v3_VERSION_RESPONSE
|
||||||
|
self._paste_in_port(expected['version'],
|
||||||
|
'http://localhost:%s/v3/' % CONF.admin_port)
|
||||||
self.assertEqual(data, expected)
|
self.assertEqual(data, expected)
|
||||||
|
Loading…
Reference in New Issue
Block a user