From a8a6246dbc320863529d0cd93dc9690acece4d4a Mon Sep 17 00:00:00 2001 From: Graham Hayes Date: Fri, 13 Mar 2015 15:14:02 +0000 Subject: [PATCH] Add Admin API and add extensions * Move the current v2 extensions to /admin * This should be an evolving API, so not guaranteed to be stable * Basic admin api code ripped from Id19d6b84808b1b2ef0b1fcefdf85ffa0ccce191b Change-Id: I1737af3be4eb7cb8c965f215f9c609af49d3bea2 APIImpact: Moved admin extensions to /admin/ --- contrib/devstack/lib/designate | 5 +- designate/api/__init__.py | 1 + designate/api/admin/__init__.py | 52 ++++++ designate/api/admin/app.py | 46 ++++++ .../controllers}/__init__.py | 0 .../controllers}/extensions/__init__.py | 0 .../controllers/extensions/counts.py | 2 +- .../controllers/extensions/quotas.py | 2 +- .../controllers/extensions/reports.py | 4 +- .../controllers/extensions/tenants.py | 2 +- designate/api/admin/controllers/root.py | 46 ++++++ .../admin/views}/__init__.py | 0 .../api/admin/views/extensions/__init__.py | 0 .../{v2 => admin}/views/extensions/quotas.py | 0 .../{v2 => admin}/views/extensions/reports.py | 0 designate/api/versions.py | 26 ++- designate/schema/__init__.py | 2 +- .../tests/test_api/test_admin/__init__.py | 150 ++++++++++++++++++ .../test_admin/extensions/__init__.py | 0 .../extensions/test_quotas.py | 10 +- .../extensions/test_reports.py | 10 +- etc/designate/api-paste.ini | 9 ++ etc/designate/designate.conf.sample | 9 +- .../api/v2/clients/quotas_client.py | 2 +- setup.cfg | 6 +- 25 files changed, 354 insertions(+), 30 deletions(-) create mode 100644 designate/api/admin/__init__.py create mode 100644 designate/api/admin/app.py rename designate/api/{v2/controllers/extensions => admin/controllers}/__init__.py (100%) rename designate/api/{v2/views => admin/controllers}/extensions/__init__.py (100%) rename designate/api/{v2 => admin}/controllers/extensions/counts.py (95%) rename designate/api/{v2 => admin}/controllers/extensions/quotas.py (97%) rename designate/api/{v2 => admin}/controllers/extensions/reports.py (88%) rename designate/api/{v2 => admin}/controllers/extensions/tenants.py (95%) create mode 100644 designate/api/admin/controllers/root.py rename designate/{tests/test_api/test_v2/extensions => api/admin/views}/__init__.py (100%) create mode 100644 designate/api/admin/views/extensions/__init__.py rename designate/api/{v2 => admin}/views/extensions/quotas.py (100%) rename designate/api/{v2 => admin}/views/extensions/reports.py (100%) create mode 100644 designate/tests/test_api/test_admin/__init__.py create mode 100644 designate/tests/test_api/test_admin/extensions/__init__.py rename designate/tests/test_api/{test_v2 => test_admin}/extensions/test_quotas.py (94%) rename designate/tests/test_api/{test_v2 => test_admin}/extensions/test_reports.py (93%) diff --git a/contrib/devstack/lib/designate b/contrib/devstack/lib/designate index 48092a90a..12d1eb05c 100644 --- a/contrib/devstack/lib/designate +++ b/contrib/devstack/lib/designate @@ -55,7 +55,8 @@ DESIGNATE_SERVICE_PORT_MDNS=${DESIGNATE_SERVICE_PORT_MDNS:-5354} DESIGNATE_TEST_NSREC=${DESIGNATE_TEST_NSREC:-ns1.devstack.org.} DESIGNATE_ENABLED_EXTENSIONS_V1=${DESIGNATE_ENABLED_EXTENSIONS_V1:-"quotas"} -DESIGNATE_ENABLED_EXTENSIONS_V2=${DESIGNATE_ENABLED_EXTENSIONS_V2:-"quotas"} +DESIGNATE_ENABLED_EXTENSIONS_V2=${DESIGNATE_ENABLED_EXTENSIONS_V2:-""} +DESIGNATE_ENABLED_EXTENSIONS_ADMIN=${DESIGNATE_ENABLED_EXTENSIONS_ADMIN:-"quotas"} # Tell Tempest this project is present TEMPEST_SERVICES+=,designate @@ -113,6 +114,7 @@ function configure_designate { iniset $DESIGNATE_CONF pool_manager_cache:sqlalchemy connection `database_connection_url designate_pool_manager` iniset $DESIGNATE_CONF service:api enabled_extensions_v1 $DESIGNATE_ENABLED_EXTENSIONS_V1 iniset $DESIGNATE_CONF service:api enabled_extensions_v2 $DESIGNATE_ENABLED_EXTENSIONS_V2 + iniset $DESIGNATE_CONF service:api enabled_extensions_admin $DESIGNATE_ENABLED_EXTENSIONS_ADMIN sudo cp $DESIGNATE_DIR/etc/designate/rootwrap.conf.sample $DESIGNATE_ROOTWRAP_CONF iniset $DESIGNATE_ROOTWRAP_CONF DEFAULT filters_path $DESIGNATE_DIR/etc/designate/rootwrap.d root-helper @@ -146,6 +148,7 @@ function configure_designate { iniset $DESIGNATE_CONF service:api api_base_uri $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/ iniset $DESIGNATE_CONF service:api enable_api_v1 True iniset $DESIGNATE_CONF service:api enable_api_v2 True + iniset $DESIGNATE_CONF service:api enable_api_admin True if is_service_enabled tls-proxy; then # Set the service port for a proxy to take the original iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT_INT diff --git a/designate/api/__init__.py b/designate/api/__init__.py index b42d713a8..8fb5811f2 100644 --- a/designate/api/__init__.py +++ b/designate/api/__init__.py @@ -35,4 +35,5 @@ cfg.CONF.register_opts([ 'keystone'), cfg.BoolOpt('enable-api-v1', default=True), cfg.BoolOpt('enable-api-v2', default=False), + cfg.BoolOpt('enable-api-admin', default=False), ], group='service:api') diff --git a/designate/api/admin/__init__.py b/designate/api/admin/__init__.py new file mode 100644 index 000000000..b3f8a5cc8 --- /dev/null +++ b/designate/api/admin/__init__.py @@ -0,0 +1,52 @@ +# Copyright (c) 2014 Rackspace Hosting +# All Rights Reserved. +# +# 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 pecan.deploy +from oslo.config import cfg +from oslo_log import log as logging + +LOG = logging.getLogger(__name__) + +OPTS = [ + cfg.ListOpt('enabled-extensions-admin', default=[], + help='Enabled Admin API Extensions'), +] + +cfg.CONF.register_opts(OPTS, group='service:api') + + +def factory(global_config, **local_conf): + if not cfg.CONF['service:api'].enable_api_admin: + def disabled_app(environ, start_response): + status = '404 Not Found' + start_response(status, []) + return [] + + return disabled_app + + conf = { + 'app': { + 'root': 'designate.api.admin.controllers.root.RootController', + 'modules': ['designate.api.admin'], + 'errors': { + 404: '/errors/not_found', + 405: '/errors/method_not_allowed', + '__force_dict__': True + } + } + } + + app = pecan.deploy.deploy(conf) + + return app diff --git a/designate/api/admin/app.py b/designate/api/admin/app.py new file mode 100644 index 000000000..bd8d5dc6f --- /dev/null +++ b/designate/api/admin/app.py @@ -0,0 +1,46 @@ +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Author: Kiall Mac Innes +# +# 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 pecan +import pecan.deploy +from oslo.config import cfg +from oslo_log import log as logging + +from designate.api.v2 import patches + + +LOG = logging.getLogger(__name__) + +cfg.CONF.register_opts([ + cfg.BoolOpt('pecan_debug', default=False, + help='Pecan HTML Debug Interface'), +], group='service:api') + + +def setup_app(pecan_config): + config = dict(pecan_config) + + config['app']['debug'] = cfg.CONF['service:api'].pecan_debug + + pecan.configuration.set_config(config, overwrite=True) + + app = pecan.make_app( + pecan_config.app.root, + debug=getattr(pecan_config.app, 'debug', False), + force_canonical=getattr(pecan_config.app, 'force_canonical', True), + request_cls=patches.Request + ) + + return app diff --git a/designate/api/v2/controllers/extensions/__init__.py b/designate/api/admin/controllers/__init__.py similarity index 100% rename from designate/api/v2/controllers/extensions/__init__.py rename to designate/api/admin/controllers/__init__.py diff --git a/designate/api/v2/views/extensions/__init__.py b/designate/api/admin/controllers/extensions/__init__.py similarity index 100% rename from designate/api/v2/views/extensions/__init__.py rename to designate/api/admin/controllers/extensions/__init__.py diff --git a/designate/api/v2/controllers/extensions/counts.py b/designate/api/admin/controllers/extensions/counts.py similarity index 95% rename from designate/api/v2/controllers/extensions/counts.py rename to designate/api/admin/controllers/extensions/counts.py index 0c8bb7023..ed221a6a5 100644 --- a/designate/api/v2/controllers/extensions/counts.py +++ b/designate/api/admin/controllers/extensions/counts.py @@ -18,7 +18,7 @@ import pecan from oslo_log import log as logging from designate.api.v2.controllers import rest -from designate.api.v2.views.extensions import reports as reports_view +from designate.api.admin.views.extensions import reports as reports_view LOG = logging.getLogger(__name__) diff --git a/designate/api/v2/controllers/extensions/quotas.py b/designate/api/admin/controllers/extensions/quotas.py similarity index 97% rename from designate/api/v2/controllers/extensions/quotas.py rename to designate/api/admin/controllers/extensions/quotas.py index 91b4f80f5..d7427d5b2 100644 --- a/designate/api/v2/controllers/extensions/quotas.py +++ b/designate/api/admin/controllers/extensions/quotas.py @@ -18,7 +18,7 @@ from oslo_log import log as logging from designate import schema from designate.api.v2.controllers import rest -from designate.api.v2.views.extensions import quotas as quotas_view +from designate.api.admin.views.extensions import quotas as quotas_view LOG = logging.getLogger(__name__) diff --git a/designate/api/v2/controllers/extensions/reports.py b/designate/api/admin/controllers/extensions/reports.py similarity index 88% rename from designate/api/v2/controllers/extensions/reports.py rename to designate/api/admin/controllers/extensions/reports.py index b3b8d3189..38a49d36a 100644 --- a/designate/api/v2/controllers/extensions/reports.py +++ b/designate/api/admin/controllers/extensions/reports.py @@ -17,8 +17,8 @@ from oslo_log import log as logging from designate.api.v2.controllers import rest -from designate.api.v2.controllers.extensions import counts -from designate.api.v2.controllers.extensions import tenants +from designate.api.admin.controllers.extensions import counts +from designate.api.admin.controllers.extensions import tenants LOG = logging.getLogger(__name__) diff --git a/designate/api/v2/controllers/extensions/tenants.py b/designate/api/admin/controllers/extensions/tenants.py similarity index 95% rename from designate/api/v2/controllers/extensions/tenants.py rename to designate/api/admin/controllers/extensions/tenants.py index 8d1f8d213..eac3125a7 100644 --- a/designate/api/v2/controllers/extensions/tenants.py +++ b/designate/api/admin/controllers/extensions/tenants.py @@ -18,7 +18,7 @@ import pecan from oslo_log import log as logging from designate.api.v2.controllers import rest -from designate.api.v2.views.extensions import reports as reports_view +from designate.api.admin.views.extensions import reports as reports_view LOG = logging.getLogger(__name__) diff --git a/designate/api/admin/controllers/root.py b/designate/api/admin/controllers/root.py new file mode 100644 index 000000000..07e8d51bc --- /dev/null +++ b/designate/api/admin/controllers/root.py @@ -0,0 +1,46 @@ +# Copyright (c) 2014 Rackspace Hosting +# All Rights Reserved. +# +# 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. +from oslo.config import cfg +from oslo_log import log as logging +from stevedore import named + +from designate.api.v2.controllers import errors + + +LOG = logging.getLogger(__name__) + + +class RootController(object): + """ + This is /admin/ Controller. Pecan will find all controllers via the object + properties attached to this. + """ + + def __init__(self): + enabled_ext = cfg.CONF['service:api'].enabled_extensions_admin + if len(enabled_ext) > 0: + self._mgr = named.NamedExtensionManager( + namespace='designate.api.admin.extensions', + names=enabled_ext, + invoke_on_load=True) + for ext in self._mgr: + controller = self + path = ext.obj.get_path() + for p in path.split('.')[:-1]: + if p != '': + controller = getattr(controller, p) + setattr(controller, path.split('.')[-1], ext.obj) + + errors = errors.ErrorsController() diff --git a/designate/tests/test_api/test_v2/extensions/__init__.py b/designate/api/admin/views/__init__.py similarity index 100% rename from designate/tests/test_api/test_v2/extensions/__init__.py rename to designate/api/admin/views/__init__.py diff --git a/designate/api/admin/views/extensions/__init__.py b/designate/api/admin/views/extensions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/designate/api/v2/views/extensions/quotas.py b/designate/api/admin/views/extensions/quotas.py similarity index 100% rename from designate/api/v2/views/extensions/quotas.py rename to designate/api/admin/views/extensions/quotas.py diff --git a/designate/api/v2/views/extensions/reports.py b/designate/api/admin/views/extensions/reports.py similarity index 100% rename from designate/api/v2/views/extensions/reports.py rename to designate/api/admin/views/extensions/reports.py diff --git a/designate/api/versions.py b/designate/api/versions.py index cebf15553..3aacc0751 100644 --- a/designate/api/versions.py +++ b/designate/api/versions.py @@ -25,14 +25,24 @@ def factory(global_config, **local_conf): base = cfg.CONF['service:api'].api_base_uri.rstrip('/') def _version(version, status): - versions.append({ - 'id': 'v%s' % version, - 'status': status, - 'links': [{ - 'href': base + '/v' + version, - 'rel': 'self' - }] - }) + if version.isdigit(): + versions.append({ + 'id': 'v%s' % version, + 'status': status, + 'links': [{ + 'href': base + '/v' + version, + 'rel': 'self' + }] + }) + else: + versions.append({ + 'id': '%s' % version, + 'status': status, + 'links': [{ + 'href': base + '/' + version, + 'rel': 'self' + }] + }) if cfg.CONF['service:api'].enable_api_v1: _version('1', 'CURRENT') diff --git a/designate/schema/__init__.py b/designate/schema/__init__.py index 26cff53f9..fe0fc7089 100644 --- a/designate/schema/__init__.py +++ b/designate/schema/__init__.py @@ -34,7 +34,7 @@ class Schema(object): self.validator = validators.Draft3Validator( self.raw_schema, resolver=self.resolver, format_checker=format.draft3_format_checker) - elif version == 'v2': + elif version in ['v2', 'admin']: self.validator = validators.Draft4Validator( self.raw_schema, resolver=self.resolver, format_checker=format.draft4_format_checker) diff --git a/designate/tests/test_api/test_admin/__init__.py b/designate/tests/test_api/test_admin/__init__.py new file mode 100644 index 000000000..c9f22b400 --- /dev/null +++ b/designate/tests/test_api/test_admin/__init__.py @@ -0,0 +1,150 @@ +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Author: Kiall Mac Innes +# +# 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 itertools + +from oslo_log import log as logging +from webtest import TestApp + +from designate.api import admin as admin_api +from designate.api import middleware +from designate.tests.test_api import ApiTestCase + + +LOG = logging.getLogger(__name__) + + +INVALID_ID = [ + '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff98g', + '2fdadfb1cf964259ac6bbb7b6d2ff9GG', + '12345' +] + + +class AdminApiTestCase(ApiTestCase): + def setUp(self): + super(AdminApiTestCase, self).setUp() + + # Ensure the v2 API is enabled + self.config(enable_api_admin=True, group='service:api') + + # Create the application + self.app = admin_api.factory({}) + + # Inject the NormalizeURIMiddleware middleware + self.app = middleware.NormalizeURIMiddleware(self.app) + + # Inject the FaultWrapper middleware + self.app = middleware.FaultWrapperMiddleware(self.app) + + # Inject the TestContext middleware + self.app = middleware.TestContextMiddleware( + self.app, self.admin_context.tenant, + self.admin_context.tenant) + + # Obtain a test client + self.client = TestApp(self.app) + + def tearDown(self): + self.app = None + self.client = None + + super(AdminApiTestCase, self).tearDown() + + def _assert_invalid_uuid(self, method, url_format, *args, **kw): + """ + Test that UUIDs used in the URL is valid. + """ + count = url_format.count('%s') + for i in itertools.product(INVALID_ID, repeat=count): + self._assert_exception('invalid_uuid', 400, method, url_format % i) + + def _assert_exception(self, expected_type, expected_status, obj, + *args, **kwargs): + """ + Checks the response that a api call with a exception contains the + wanted data. + """ + kwargs.setdefault('status', expected_status) + + response = obj(*args, **kwargs) if not hasattr(obj, 'json') else obj + + self.assertEqual(expected_status, response.json['code']) + self.assertEqual(expected_type, response.json['type']) + + def _assert_invalid_paging(self, data, url, key): + """ + Test that certain circumstances is invalid for paging in a given url. + """ + self._assert_paging(data, url, key=key, + limit='invalid_limit', + expected_type='invalid_limit', + expected_status=400) + + self._assert_paging(data, url, key=key, + sort_dir='invalid_sort_dir', + expected_type='invalid_sort_dir', + expected_status=400) + + self._assert_paging(data, url, key=key, + sort_key='invalid_sort_key', + expected_type='invalid_sort_key', + expected_status=400) + + self._assert_paging(data, url, key=key, + marker='invalid_marker', + expected_type='invalid_marker', + expected_status=400) + + def _assert_paging(self, data, url, key=None, limit=5, sort_dir='asc', + sort_key='created_at', marker=None, + expected_type=None, expected_status=200): + + def _page(marker=None): + params = {'limit': limit, + 'sort_dir': sort_dir, + 'sort_key': sort_key} + + if marker is not None: + params['marker'] = marker + + r = self.client.get(url, params, status=expected_status) + if expected_status != 200: + if expected_type: + self._assert_exception(expected_type, expected_status, r) + return r + else: + return r.json[key] if key in r.json else r.json + + response = _page(marker=marker) + if expected_status != 200: + if expected_type: + self._assert_exception(expected_type, expected_status, + response) + + return response + + x = 0 + length = len(data) + for i in xrange(0, length): + assert data[i]['id'] == response[x]['id'] + + x += 1 + # Don't bother getting a new page if we're at the last item + if x == len(response) and i != length - 1: + x = 0 + response = _page(response[-1:][0]['id']) + + _page(marker=response[-1:][0]['id']) diff --git a/designate/tests/test_api/test_admin/extensions/__init__.py b/designate/tests/test_api/test_admin/extensions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/designate/tests/test_api/test_v2/extensions/test_quotas.py b/designate/tests/test_api/test_admin/extensions/test_quotas.py similarity index 94% rename from designate/tests/test_api/test_v2/extensions/test_quotas.py rename to designate/tests/test_api/test_admin/extensions/test_quotas.py index ce292f348..ac463423b 100644 --- a/designate/tests/test_api/test_v2/extensions/test_quotas.py +++ b/designate/tests/test_api/test_admin/extensions/test_quotas.py @@ -16,16 +16,16 @@ # under the License. from oslo.config import cfg -from designate.tests.test_api.test_v2 import ApiV2TestCase +from designate.tests.test_api.test_admin import AdminApiTestCase -cfg.CONF.import_opt('enabled_extensions_v2', 'designate.api.v2', +cfg.CONF.import_opt('enabled_extensions_admin', 'designate.api.admin', group='service:api') -class ApiV2QuotasTest(ApiV2TestCase): +class AdminApiQuotasTest(AdminApiTestCase): def setUp(self): - self.config(enabled_extensions_v2=['quotas'], group='service:api') - super(ApiV2QuotasTest, self).setUp() + self.config(enabled_extensions_admin=['quotas'], group='service:api') + super(AdminApiQuotasTest, self).setUp() def test_get_quotas(self): self.policy({'get_quotas': '@'}) diff --git a/designate/tests/test_api/test_v2/extensions/test_reports.py b/designate/tests/test_api/test_admin/extensions/test_reports.py similarity index 93% rename from designate/tests/test_api/test_v2/extensions/test_reports.py rename to designate/tests/test_api/test_admin/extensions/test_reports.py index 6629e0390..4a7ada84a 100644 --- a/designate/tests/test_api/test_v2/extensions/test_reports.py +++ b/designate/tests/test_api/test_admin/extensions/test_reports.py @@ -16,16 +16,16 @@ # under the License. from oslo.config import cfg -from designate.tests.test_api.test_v2 import ApiV2TestCase +from designate.tests.test_api.test_admin import AdminApiTestCase -cfg.CONF.import_opt('enabled_extensions_v2', 'designate.api.v2', +cfg.CONF.import_opt('enabled_extensions_admin', 'designate.api.admin', group='service:api') -class ApiV2ReportsTest(ApiV2TestCase): +class AdminApiReportsTest(AdminApiTestCase): def setUp(self): - self.config(enabled_extensions_v2=['reports'], group='service:api') - super(ApiV2ReportsTest, self).setUp() + self.config(enabled_extensions_admin=['reports'], group='service:api') + super(AdminApiReportsTest, self).setUp() def test_get_counts(self): self.policy({'count_tenants': '@'}) diff --git a/etc/designate/api-paste.ini b/etc/designate/api-paste.ini index 159d1f58d..7a5f5b7be 100644 --- a/etc/designate/api-paste.ini +++ b/etc/designate/api-paste.ini @@ -3,6 +3,7 @@ use = egg:Paste#urlmap /: osapi_dns_app_versions /v1: osapi_dns_v1 /v2: osapi_dns_v2 +/admin: osapi_dns_admin [app:osapi_dns_app_versions] paste.app_factory = designate.api.versions:factory @@ -23,6 +24,14 @@ keystone = request_id faultwrapper authtoken keystonecontext maintenance normali [app:osapi_dns_app_v2] paste.app_factory = designate.api.v2:factory +[composite:osapi_dns_admin] +use = call:designate.api.middleware:auth_pipeline_factory +noauth = request_id faultwrapper noauthcontext maintenance normalizeuri osapi_dns_app_admin +keystone = request_id faultwrapper authtoken keystonecontext maintenance normalizeuri osapi_dns_app_admin + +[app:osapi_dns_app_admin] +paste.app_factory = designate.api.admin:factory + [filter:request_id] paste.filter_factory = oslo_middleware:RequestId.factory diff --git a/etc/designate/designate.conf.sample b/etc/designate/designate.conf.sample index 91c179375..8ebf19005 100644 --- a/etc/designate/designate.conf.sample +++ b/etc/designate/designate.conf.sample @@ -84,6 +84,13 @@ debug = False # Enable Version 2 API (experimental) #enable_api_v2 = False +# Enable Admin API (experimental) +#enable_api_admin = False + +# Enabled Admin API extensions +# Can be one or more of : reports, quotas, counts, tenants +#enabled_extensions_admin = + # Show the pecan HTML based debug interface (v2 only) # This is only useful for development, and WILL break python-designateclient # if an error occurs @@ -94,7 +101,7 @@ debug = False #enabled_extensions_v1 = # Enabled API Version 2 extensions -# Can be one or more of : reports, quotas +# Can be one or more of : #enabled_extensions_v2 = #----------------------- diff --git a/functionaltests/api/v2/clients/quotas_client.py b/functionaltests/api/v2/clients/quotas_client.py index b7a241c00..0ee27d8d1 100644 --- a/functionaltests/api/v2/clients/quotas_client.py +++ b/functionaltests/api/v2/clients/quotas_client.py @@ -24,7 +24,7 @@ class QuotasClient(object): @classmethod def quotas_uri(cls, tenant_id): - return "/v2/quotas/" + tenant_id + return "/admin/quotas/" + tenant_id @classmethod def deserialize(cls, resp, body, model_type): diff --git a/setup.cfg b/setup.cfg index 0e3db2f2f..028e41471 100644 --- a/setup.cfg +++ b/setup.cfg @@ -53,9 +53,9 @@ designate.api.v1.extensions = reports = designate.api.v1.extensions.reports:blueprint touch = designate.api.v1.extensions.touch:blueprint -designate.api.v2.extensions = - reports = designate.api.v2.controllers.extensions.reports:ReportsController - quotas = designate.api.v2.controllers.extensions.quotas:QuotasController +designate.api.admin.extensions = + reports = designate.api.admin.controllers.extensions.reports:ReportsController + quotas = designate.api.admin.controllers.extensions.quotas:QuotasController designate.storage = sqlalchemy = designate.storage.impl_sqlalchemy:SQLAlchemyStorage