From ae319ee3590ffeaac3a31f98894bfbf9a82926c0 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 11 Aug 2015 03:37:46 -0700 Subject: [PATCH] Implement TODO for version listing Return a list of currently enabled API versions building the response in the same way as it is done for the eventlet WSGI API in order to ensure backward compatibility. The only version listed is obviously 2.0, but the solution devised in this patch allows version controller for self declaring the version they implement. This patch also replaces the use of _lookup when such method is not strictly necessary. To this aim, the minimum version of Pecan has been bumped to 1.0 as previouse releases did not support dots "." as valid characters in URI path segments. Change-Id: Ia748194b2c07a04a711d32ce8058a006e73621ef --- neutron/newapi/controllers/root.py | 53 +++++++++++++------ .../functional/newapi/test_functional.py | 16 ++++++ requirements.txt | 2 +- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/neutron/newapi/controllers/root.py b/neutron/newapi/controllers/root.py index 1e2fb553d..6bcace413 100644 --- a/neutron/newapi/controllers/root.py +++ b/neutron/newapi/controllers/root.py @@ -18,6 +18,18 @@ import pecan from pecan import request from neutron.api import extensions +from neutron.api.views import versions as versions_view + +_VERSION_INFO = {} + + +def _load_version_info(version_info): + assert version_info['id'] not in _VERSION_INFO + _VERSION_INFO[version_info['id']] = version_info + + +def _get_version_info(): + return _VERSION_INFO.values() def expose(*args, **kwargs): @@ -36,24 +48,11 @@ def when(index, *args, **kwargs): class RootController(object): - @expose() - def _lookup(self, version, *remainder): - if version == 'v2.0': - return V2Controller(), remainder - @expose(generic=True) def index(self): - #TODO(kevinbenton): return a version list - return dict(message='A neutron server') - - -class V2Controller(object): - - @expose() - def _lookup(self, endpoint, *remainder): - if endpoint == 'extensions': - return ExtensionsController(), remainder - return CollectionsController(endpoint), remainder + builder = versions_view.get_view_builder(pecan.request) + versions = [builder.build(version) for version in _get_version_info()] + return dict(versions=versions) class ExtensionsController(object): @@ -70,6 +69,28 @@ class ExtensionsController(object): return {'extensions': exts} +class V2Controller(object): + + # Same data structure as neutron.api.versions.Versions for API backward + # compatibility + version_info = { + 'id': 'v2.0', + 'status': 'CURRENT' + } + _load_version_info(version_info) + + extensions = ExtensionsController() + + @expose() + def _lookup(self, endpoint, *remainder): + return CollectionsController(endpoint), remainder + + +# This controller cannot be specified directly as a member of RootController +# as its path is not a valid python identifier +pecan.route(RootController, 'v2.0', V2Controller()) + + class ExtensionController(object): def __init__(self, alias): diff --git a/neutron/tests/functional/newapi/test_functional.py b/neutron/tests/functional/newapi/test_functional.py index 458be23ac..a7cf4fa92 100644 --- a/neutron/tests/functional/newapi/test_functional.py +++ b/neutron/tests/functional/newapi/test_functional.py @@ -17,6 +17,7 @@ import os import mock from oslo_config import cfg +from oslo_serialization import jsonutils from oslo_utils import uuidutils from pecan import request from pecan import set_config @@ -27,6 +28,7 @@ from neutron.api.v2 import attributes from neutron.common import exceptions as n_exc from neutron import context from neutron import manager +from neutron.newapi.controllers import root as controllers from neutron.tests.unit import testlib_api @@ -230,3 +232,17 @@ class TestEnforcementHooks(PecanFunctionalTest): def test_policy_enforcement(self): # TODO(kevinbenton): this test should do something pass + + +class TestRootController(PecanFunctionalTest): + """Test version listing on root URI.""" + + def test_get(self): + response = self.app.get('/') + self.assertEqual(response.status_int, 200) + json_body = jsonutils.loads(response.body) + versions = json_body.get('versions') + self.assertEqual(1, len(versions)) + for (attr, value) in controllers.V2Controller.version_info.items(): + self.assertIn(attr, versions[0]) + self.assertEqual(value, versions[0][attr]) diff --git a/requirements.txt b/requirements.txt index 8fbf815e8..b372e4c10 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ Routes!=2.0,!=2.1,>=1.12.3;python_version=='2.7' Routes!=2.0,>=1.12.3;python_version!='2.7' debtcollector>=0.3.0 # Apache-2.0 eventlet>=0.17.4 -pecan>=0.8.0 +pecan>=1.0.0 greenlet>=0.3.2 httplib2>=0.7.5 requests>=2.5.2 -- 2.45.2