Versions endpoint is working

Fix Versions endpoint
- was conflicting with other endpoints starting
from v2.0 and v3.0 which for versions was {version_id}
- template dict VERSIONS was mutated every request

Additionally this commit provides moving /version
outside of keystone authentication

Change-Id: I184a0fbc2dcaca21aa5f1256d9a1c41597f9d184
This commit is contained in:
Tomasz Trębski 2016-03-08 11:32:58 +01:00
parent 81413d4d52
commit 0405d59701
4 changed files with 206 additions and 43 deletions

View File

@ -1,4 +1,4 @@
# Copyright 2015 FUJITSU LIMITED
# Copyright 2016 FUJITSU LIMITED
#
# 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
@ -17,6 +17,9 @@ from oslo_log import log
LOG = log.getLogger(__name__)
_SKIP_PATH = '/version', '/healthcheck'
"""Tuple of non-application endpoints"""
class SkippingAuthProtocol(auth_token.AuthProtocol):
"""SkippingAuthProtocol to reach healthcheck endpoint
@ -35,10 +38,12 @@ class SkippingAuthProtocol(auth_token.AuthProtocol):
def process_request(self, request):
path = request.path
if path == '/healthcheck':
LOG.debug(('Request path is %s and it does not require keystone '
'communication'), path)
return None # return NONE to reach actual logic
for p in _SKIP_PATH:
if path.startswith(p):
LOG.debug(
('Request path is %s and it does not require keystone '
'communication'), path)
return None # return NONE to reach actual logic
return super(SkippingAuthProtocol, self).process_request(request)

View File

@ -20,68 +20,104 @@ from oslo_log import log
from monasca_log_api.api import versions_api
LOG = log.getLogger(__name__)
VERSIONS = {
_VERSIONS_TPL_DICT = {
'v2.0': {
'id': 'v2.0',
'links': [
{
'rel': 'self',
'href': ''
},
'rel': 'logs',
'href': '/log/single'
}
],
'status': 'DEPRECATED',
'updated': "2015-09-01T00:00:00Z"
},
'v3.0': {
'id': 'v3.0',
'links': [
{
'rel': 'links',
'href': '/log'
'rel': 'logs',
'href': '/logs'
}
],
'status': 'CURRENT',
'updated': "2013-03-06T00:00:00Z"
'updated': "2016-03-01T00:00:00Z"
}
}
class Versions(versions_api.VersionsAPI):
"""Versions Api V2."""
def __init__(self):
super(Versions, self).__init__()
"""Versions Api"""
@staticmethod
def handle_none_version_id(req, res, result):
for version in VERSIONS:
VERSIONS[version]['links'][0]['href'] = (
req.uri.decode('utf8') + version)
result['elements'].append(VERSIONS[version])
res.body = rest_utils.as_json(result)
for version in _VERSIONS_TPL_DICT:
selected_version = _parse_version(version, req)
result['elements'].append(selected_version)
res.body = rest_utils.as_json(result, sort_keys=True)
res.status = falcon.HTTP_200
@staticmethod
def handle_version_id(req, res, version_id):
if version_id in VERSIONS:
VERSIONS[version_id]['links'][0]['href'] = (
req.uri.decode(rest_utils.ENCODING)
)
for version in VERSIONS:
VERSIONS[version]['links'][0]['href'] = (
req.uri.decode('utf8')
)
VERSIONS[version_id]['links'][1]['href'] = (
req.uri.decode('utf8') +
VERSIONS[version_id]['links'][1]['href']
)
res.body = rest_utils.as_json(VERSIONS[version_id])
def handle_version_id(req, res, result, version_id):
if version_id in _VERSIONS_TPL_DICT:
result['elements'].append(_parse_version(version_id, req))
res.body = rest_utils.as_json(result, sort_keys=True)
res.status = falcon.HTTP_200
else:
res.body = 'Invalid Version ID'
error_body = {'message': '%s is not valid version' % version_id}
res.body = rest_utils.as_json(error_body)
res.status = falcon.HTTP_400
def on_get(self, req, res, version_id=None):
result = {
'links': [{
'rel': 'self',
'href': req.uri.decode(rest_utils.ENCODING)
}],
'links': _get_common_links(req),
'elements': []
}
if version_id is None:
self.handle_none_version_id(req, res, result)
else:
self.handle_version_id(req, res, version_id)
self.handle_version_id(req, res, result, version_id)
def _get_common_links(req):
self_uri = req.uri.decode(rest_utils.ENCODING)
base_uri = self_uri.replace(req.path, '')
return [
{
'rel': 'self',
'href': self_uri
},
{
'rel': 'version',
'href': '%s/version' % base_uri
},
{
'rel': 'healthcheck',
'href': '%s/healthcheck' % base_uri
}
]
def _parse_version(version_id, req):
self_uri = req.uri.decode('utf-8')
base_uri = self_uri.replace(req.path, '')
# need to get template dict, consecutive calls
# needs to operate on unmodified instance
selected_version = _VERSIONS_TPL_DICT[version_id].copy()
raw_links = selected_version['links']
links = []
for link in raw_links:
raw_link_href = link.get('href')
raw_link_rel = link.get('rel')
link_href = base_uri + '/' + version_id + raw_link_href
links.append({
'href': link_href,
'rel': raw_link_rel
})
selected_version['links'] = links
return selected_version

View File

@ -1,5 +1,5 @@
# Copyright 2015 kornicameister@gmail.com
# Copyright 2015 FUJITSU LIMITED
# Copyright 2016 FUJITSU LIMITED
#
# 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
@ -84,8 +84,8 @@ def load_logs_resource(app):
def load_versions_resource(app):
versions = simport.load(CONF.dispatcher.versions)()
app.add_route("/", versions)
app.add_route("/{version_id}", versions)
app.add_route("/version", versions)
app.add_route("/version/{version_id}", versions)
def get_wsgi_app(config_base_path=None):

View File

@ -0,0 +1,122 @@
# Copyright 2016 FUJITSU LIMITED
#
# 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 falcon
from falcon import testing
import ujson as json
from monasca_log_api.reference import versions
def _get_versioned_url(version_id):
return '/version/%s' % version_id
class TestVersions(testing.TestBase):
def __init__(self, *args, **kwargs):
self.versions = None
super(TestVersions, self).__init__(*args, **kwargs)
def before(self):
self.versions = versions.Versions()
self.api.add_route("/version/", self.versions)
self.api.add_route("/version/{version_id}", self.versions)
def test_should_fail_for_unsupported_version(self):
unsupported_version = 'v5.0'
uri = _get_versioned_url(unsupported_version)
self.simulate_request(
uri,
method='GET',
headers={
'Content-Type': 'application/json'
}
)
self.assertEqual(falcon.HTTP_400, self.srmock.status)
def test_should_return_all_supported_versions(self):
def _check_elements():
self.assertIn('elements', response)
elements = response.get('elements')
self.assertIsInstance(elements, list)
for el in elements:
# do checkup by expected keys
self.assertIn('id', el)
self.assertItemsEqual([
u'id',
u'links',
u'status',
u'updated'
], el.keys())
ver = el.get('id')
self.assertIn(ver, expected_versions)
def _check_global_links():
self.assertIn('links', response)
links = response.get('links')
self.assertIsInstance(links, list)
for link in links:
self.assertIn('rel', link)
key = link.get('rel')
self.assertIn(key, expected_links_keys)
expected_versions = 'v2.0', 'v3.0'
expected_links_keys = 'self', 'version', 'healthcheck'
res = self.simulate_request(
'/version',
method='GET',
headers={
'Content-Type': 'application/json'
},
decode='utf-8'
)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
response = json.loads(res)
_check_elements()
_check_global_links()
def test_should_return_expected_version_id(self):
expected_versions = 'v2.0', 'v3.0'
for expected_version in expected_versions:
uri = _get_versioned_url(expected_version)
res = self.simulate_request(
uri,
method='GET',
headers={
'Content-Type': 'application/json'
},
decode='utf-8'
)
self.assertEqual(falcon.HTTP_200, self.srmock.status)
response = json.loads(res)
self.assertIn('elements', response)
self.assertIn('links', response)
elements = response.get('elements')
self.assertIsInstance(elements, list)
self.assertEqual(1, len(elements))
el = elements[0]
ver = el.get('id')
self.assertEqual(expected_version, ver)