From aed4766cc95df806e2d0ac8053231cfe4687e149 Mon Sep 17 00:00:00 2001 From: Gabriel Hurley Date: Thu, 9 Feb 2012 22:29:23 -0800 Subject: [PATCH] Full support for dashboard and panel configuration via service catalog. There are no longer any dependencies on settings for whether or not particular components are made available in the site. Implements blueprint toggle-features. Also fixes bug 929983, making the Horizon object a proper singleton and ensuring test isolation for the base horizon tests. Fixes a case where a missing service catalog would cause a 500 error. Fixes bug 930833, Change-Id: If19762afe75859e63aa7bd5128a6795655df2c90 --- horizon/horizon/api/__init__.py | 5 +- horizon/horizon/base.py | 55 ++++++-- horizon/horizon/context_processors.py | 21 +-- .../dashboards/nova/containers/panel.py | 5 +- .../horizon/dashboards/nova/networks/panel.py | 4 +- horizon/horizon/decorators.py | 42 +++++- horizon/horizon/middleware.py | 12 +- .../templates/horizon/_subnav_list.html | 18 +-- horizon/horizon/templatetags/horizon.py | 20 ++- horizon/horizon/test.py | 11 +- horizon/horizon/tests/base_tests.py | 122 ++++++++++++++---- .../horizon/tests/context_processor_tests.py | 12 -- horizon/horizon/tests/templates/404.html | 0 horizon/horizon/tests/test_panel_urls.py | 21 +++ horizon/horizon/tests/testsettings.py | 11 -- .../local/local_settings.py.example | 7 - 16 files changed, 254 insertions(+), 112 deletions(-) create mode 100644 horizon/horizon/tests/templates/404.html create mode 100644 horizon/horizon/tests/test_panel_urls.py diff --git a/horizon/horizon/api/__init__.py b/horizon/horizon/api/__init__.py index 0b45ffd16..5b7f5dadb 100644 --- a/horizon/horizon/api/__init__.py +++ b/horizon/horizon/api/__init__.py @@ -36,5 +36,8 @@ from horizon.api.glance import * from horizon.api.keystone import * from horizon.api.nova import * from horizon.api.swift import * -if settings.QUANTUM_ENABLED: +# Quantum is optional. Ignore it if it's not installed. +try: from horizon.api.quantum import * +except ImportError: + pass diff --git a/horizon/horizon/base.py b/horizon/horizon/base.py index be8a4e5d3..5caa89585 100644 --- a/horizon/horizon/base.py +++ b/horizon/horizon/base.py @@ -36,7 +36,8 @@ from django.utils.importlib import import_module from django.utils.module_loading import module_has_submodule from django.utils.translation import ugettext as _ -from horizon.decorators import require_roles, _current_component +from horizon.decorators import (require_roles, require_services, + _current_component) LOG = logging.getLogger(__name__) @@ -108,7 +109,7 @@ class Registry(object): raise ValueError('Only classes may be registered.') elif not issubclass(cls, self._registerable_class): raise ValueError('Only %s classes or subclasses may be registered.' - % self._registerable_class) + % self._registerable_class.__name__) if cls not in self._registry: cls._registered_with = self @@ -135,9 +136,9 @@ class Registry(object): def _registered(self, cls): if inspect.isclass(cls) and issubclass(cls, self._registerable_class): - cls = self._registry.get(cls, None) - if cls: - return cls + found = self._registry.get(cls, None) + if found: + return found else: # Allow for fetching by slugs as well. for registered in self._registry.values(): @@ -153,9 +154,10 @@ class Registry(object): "parent": parent, "name": self.name}) else: + slug = getattr(cls, "slug", cls) raise NotRegistered('%(type)s with slug "%(slug)s" is not ' - 'registered.' - % {"type": class_name, "slug": cls}) + 'registered.' % {"type": class_name, + "slug": slug}) class Panel(HorizonComponent): @@ -183,6 +185,11 @@ class Panel(HorizonComponent): is combined cumulatively with any roles required on the ``Dashboard`` class with which it is registered. + .. attribute:: services + + A list of service names, all of which must be in the service catalog + in order for this panel to be available. + .. attribute:: urls Path to a URLconf of views for this panel using dotted Python @@ -235,7 +242,9 @@ class Panel(HorizonComponent): # Apply access controls to all views in the patterns roles = getattr(self, 'roles', []) + services = getattr(self, 'services', []) _decorate_urlconf(urlpatterns, require_roles, roles) + _decorate_urlconf(urlpatterns, require_services, services) _decorate_urlconf(urlpatterns, _current_component, panel=self) # Return the three arguments to django.conf.urls.defaults.include @@ -295,13 +304,18 @@ class Dashboard(Registry, HorizonComponent): for this dashboard, that's the panel that is displayed. Default: ``None``. - .. attribute: roles + .. attribute:: roles A list of role names, all of which a user must possess in order to access any panel registered with this dashboard. This attribute is combined cumulatively with any roles required on individual :class:`~horizon.Panel` classes. + .. attribute:: services + + A list of service names, all of which must be in the service catalog + in order for this dashboard to be available. + .. attribute:: urls Optional path to a URLconf of additional views for this dashboard @@ -410,7 +424,9 @@ class Dashboard(Registry, HorizonComponent): _decorate_urlconf(urlpatterns, login_required) # Apply access controls to all views in the patterns roles = getattr(self, 'roles', []) + services = getattr(self, 'services', []) _decorate_urlconf(urlpatterns, require_roles, roles) + _decorate_urlconf(urlpatterns, require_services, services) _decorate_urlconf(urlpatterns, _current_component, dashboard=self) # Return the three arguments to django.conf.urls.defaults.include @@ -437,13 +453,11 @@ class Dashboard(Registry, HorizonComponent): @classmethod def register(cls, panel): """ Registers a :class:`~horizon.Panel` with this dashboard. """ - from horizon import Horizon return Horizon.register_panel(cls, panel) @classmethod def unregister(cls, panel): """ Unregisters a :class:`~horizon.Panel` from this dashboard. """ - from horizon import Horizon return Horizon.unregister_panel(cls, panel) @@ -465,7 +479,8 @@ class LazyURLPattern(SimpleLazyObject): class Site(Registry, HorizonComponent): - """ The core OpenStack Dashboard class. """ + """ The overarching class which encompasses all dashboards and panels. """ + # Required for registry _registerable_class = Dashboard @@ -620,9 +635,7 @@ class Site(Registry, HorizonComponent): def _urls(self): """ Constructs the URLconf for Horizon from registered Dashboards. """ urlpatterns = self._get_default_urlpatterns() - self._autodiscover() - # Add in each dashboard's views. for dash in self._registry.values(): urlpatterns += patterns('', @@ -653,5 +666,19 @@ class Site(Registry, HorizonComponent): if module_has_submodule(mod, mod_name): raise + +class HorizonSite(Site): + """ + A singleton implementation of Site such that all dealings with horizon + get the same instance no matter what. There can be only one. + """ + _instance = None + + def __new__(cls, *args, **kwargs): + if not cls._instance: + cls._instance = super(Site, cls).__new__(cls, *args, **kwargs) + return cls._instance + + # The one true Horizon -Horizon = Site() +Horizon = HorizonSite() diff --git a/horizon/horizon/context_processors.py b/horizon/horizon/context_processors.py index c78506b3c..09b2556dd 100644 --- a/horizon/horizon/context_processors.py +++ b/horizon/horizon/context_processors.py @@ -34,17 +34,15 @@ LOG = logging.getLogger(__name__) def horizon(request): """ The main Horizon context processor. Required for Horizon to function. - Adds three variables to the request context: + The following variables are added to the request context: ``authorized_tenants`` A list of tenant objects which the current user has access to. - ``object_store_configured`` - Boolean. Will be ``True`` if there is a service of type - ``object-store`` in the user's ``ServiceCatalog``. + ``regions`` - ``network_configured`` - Boolean. Will be ``True`` if ``settings.QUANTUM_ENABLED`` is ``True``. + A dictionary containing information about region support, the current + region, and available regions. Additionally, it sets the names ``True`` and ``False`` in the context to their boolean equivalents for convenience. @@ -63,17 +61,6 @@ def horizon(request): if request.user.is_authenticated(): context['authorized_tenants'] = request.user.authorized_tenants - # Object Store/Swift context - catalog = getattr(request.user, 'service_catalog', []) - object_store = catalog and api.get_service_from_catalog(catalog, - 'object-store') - context['object_store_configured'] = object_store - - # Quantum context - # TODO(gabriel): Convert to service catalog check when Quantum starts - # supporting keystone integration. - context['network_configured'] = getattr(settings, 'QUANTUM_ENABLED', None) - # Region context/support available_regions = getattr(settings, 'AVAILABLE_REGIONS', []) regions = {'support': len(available_regions) > 1, diff --git a/horizon/horizon/dashboards/nova/containers/panel.py b/horizon/horizon/dashboards/nova/containers/panel.py index 89e043530..36447a6b7 100644 --- a/horizon/horizon/dashboards/nova/containers/panel.py +++ b/horizon/horizon/dashboards/nova/containers/panel.py @@ -27,9 +27,6 @@ from horizon.dashboards.nova import dashboard class Containers(horizon.Panel): name = _("Containers") slug = 'containers' - - def nav(self, context): - return context['object_store_configured'] - + services = ('object-store',) dashboard.Nova.register(Containers) diff --git a/horizon/horizon/dashboards/nova/networks/panel.py b/horizon/horizon/dashboards/nova/networks/panel.py index c46369689..529339f64 100644 --- a/horizon/horizon/dashboards/nova/networks/panel.py +++ b/horizon/horizon/dashboards/nova/networks/panel.py @@ -25,9 +25,7 @@ from horizon.dashboards.nova import dashboard class Networks(horizon.Panel): name = "Networks" slug = 'networks' - - def nav(self, context): - return context.get('network_configured', False) + services = ("network",) dashboard.Nova.register(Networks) diff --git a/horizon/horizon/decorators.py b/horizon/horizon/decorators.py index 886cbe65f..9d9254953 100644 --- a/horizon/horizon/decorators.py +++ b/horizon/horizon/decorators.py @@ -25,7 +25,7 @@ import functools from django.utils.decorators import available_attrs -from horizon.exceptions import NotAuthorized +from horizon.exceptions import NotAuthorized, NotFound def _current_component(view_func, dashboard=None, panel=None): @@ -79,6 +79,46 @@ def require_roles(view_func, required): return view_func +def require_services(view_func, required): + """ Enforces service-based access controls. + + :param list required: A tuple of service type names, all of which the + must be present in the service catalog in order + access the decorated view. + + Example usage:: + + from horizon.decorators import require_services + + + @require_services(['object-store']) + def my_swift_view(request): + ... + + Raises a :exc:`~horizon.exceptions.NotFound` exception if the + requirements are not met. + """ + # We only need to check each service once for a view, so we'll use a set + current_services = getattr(view_func, '_required_services', set([])) + view_func._required_services = current_services | set(required) + + @functools.wraps(view_func, assigned=available_attrs(view_func)) + def dec(request, *args, **kwargs): + if request.user.is_authenticated(): + services = set([service['type'] for service in + request.user.service_catalog]) + # set operator <= tests that all members of set 1 are in set 2 + if view_func._required_services <= set(services): + return view_func(request, *args, **kwargs) + raise NotFound("The services for this view are not available.") + + # If we don't have any services, just return the original view. + if required: + return dec + else: + return view_func + + def enforce_admin_access(view_func): """ Marks a view as requiring the ``"admin"`` role for access. """ return require_roles(view_func, ('admin',)) diff --git a/horizon/horizon/middleware.py b/horizon/horizon/middleware.py index 8fe81bef2..09e2d5334 100644 --- a/horizon/horizon/middleware.py +++ b/horizon/horizon/middleware.py @@ -23,6 +23,7 @@ Middleware provided and used by Horizon. import logging +from django import http from django import shortcuts from django.contrib import messages from django.utils.translation import ugettext as _ @@ -56,7 +57,7 @@ class HorizonMiddleware(object): authd = api.tenant_list_for_token(request, token, endpoint_type='internalURL') - except Exception, e: + except: authd = [] LOG.exception('Could not retrieve tenant list.') if hasattr(request.user, 'message_set'): @@ -65,11 +66,18 @@ class HorizonMiddleware(object): request.user.authorized_tenants = authd def process_exception(self, request, exception): - """ Catch NotAuthorized and Http302 and handle them gracefully. """ + """ + Catches internal Horizon exception classes such as NotAuthorized, + NotFound and Http302 and handles them gracefully. + """ if isinstance(exception, exceptions.NotAuthorized): messages.error(request, unicode(exception)) return shortcuts.redirect('/auth/login') + # If an internal "NotFound" error gets this far, return a real 404. + if isinstance(exception, exceptions.NotFound): + raise http.Http404(exception) + if isinstance(exception, exceptions.Http302): if exception.message: messages.error(request, exception.message) diff --git a/horizon/horizon/templates/horizon/_subnav_list.html b/horizon/horizon/templates/horizon/_subnav_list.html index 9b17380a2..b14eecc90 100644 --- a/horizon/horizon/templates/horizon/_subnav_list.html +++ b/horizon/horizon/templates/horizon/_subnav_list.html @@ -1,14 +1,16 @@ {% load horizon %} {% for heading, panels in components.iteritems %} -

{{ heading }}

- + {% endwith %} {% endfor %} diff --git a/horizon/horizon/templatetags/horizon.py b/horizon/horizon/templatetags/horizon.py index d19803d9f..1a812c0d3 100644 --- a/horizon/horizon/templatetags/horizon.py +++ b/horizon/horizon/templatetags/horizon.py @@ -28,16 +28,32 @@ register = template.Library() @register.filter def can_haz(user, component): - """ Checks if the given user has the necessary roles for the component. """ + """ + Checks if the given user meets the requirements for the component. This + includes both user roles and services in the service catalog. + """ if hasattr(user, 'roles'): user_roles = set([role['name'].lower() for role in user.roles]) else: user_roles = set([]) - if set(getattr(component, 'roles', [])) <= user_roles: + roles_statisfied = set(getattr(component, 'roles', [])) <= user_roles + + if hasattr(user, 'roles'): + services = set([service['type'] for service in user.service_catalog]) + else: + services = set([]) + services_statisfied = set(getattr(component, 'services', [])) <= services + + if roles_statisfied and services_statisfied: return True return False +@register.filter +def can_haz_list(components, user): + return [component for component in components if can_haz(user, component)] + + @register.inclusion_tag('horizon/_nav_list.html', takes_context=True) def horizon_main_nav(context): """ Generates top-level dashboard navigation entries. """ diff --git a/horizon/horizon/test.py b/horizon/horizon/test.py index 9c8fe0738..1f5e04384 100644 --- a/horizon/horizon/test.py +++ b/horizon/horizon/test.py @@ -61,9 +61,7 @@ class TestCase(django_test.TestCase): TEST_CONTEXT = {'authorized_tenants': [{'enabled': True, 'name': 'aTenant', 'id': '1', - 'description': "None"}], - 'object_store_configured': False, - 'network_configured': False} + 'description': "None"}]} TEST_SERVICE_CATALOG = [ {"endpoints": [{ @@ -94,6 +92,13 @@ class TestCase(django_test.TestCase): "publicURL": "http://cdn.admin-nets.local:5000/v2.0"}], "type": "identity", "name": "identity"}, + {"endpoints": [{ + "adminURL": "http://example.com:9696/quantum", + "region": "RegionOne", + "internalURL": "http://example.com:9696/quantum", + "publicURL": "http://example.com:9696/quantum"}], + "type": "network", + "name": "quantum"}, {"endpoints": [{ "adminURL": "http://swift/swiftapi/admin", "region": "RegionOne", diff --git a/horizon/horizon/tests/base_tests.py b/horizon/horizon/tests/base_tests.py index b362efaeb..852b3d339 100644 --- a/horizon/horizon/tests/base_tests.py +++ b/horizon/horizon/tests/base_tests.py @@ -18,38 +18,74 @@ # License for the specific language governing permissions and limitations # under the License. -import copy - -from django.core.urlresolvers import NoReverseMatch +from django.conf import settings +from django.core import urlresolvers from django.test.client import Client +from django.utils.importlib import import_module import horizon from horizon import base -from horizon import exceptions from horizon import test from horizon import users -from horizon.base import Horizon class MyDash(horizon.Dashboard): name = "My Dashboard" slug = "mydash" + default_panel = "myslug" class MyPanel(horizon.Panel): name = "My Panel" slug = "myslug" + services = ("compute",) + urls = 'horizon.tests.test_panel_urls' -class HorizonTests(test.TestCase): +class BaseHorizonTests(test.TestCase): def setUp(self): - super(HorizonTests, self).setUp() - self._orig_horizon = copy.deepcopy(base.Horizon) + super(BaseHorizonTests, self).setUp() + # Trigger discovery, registration, and URLconf generation if it + # hasn't happened yet. + base.Horizon._urls() + # Store our original dashboards + self._discovered_dashboards = base.Horizon._registry.keys() + # Gather up and store our original panels for each dashboard + self._discovered_panels = {} + for dash in self._discovered_dashboards: + panels = base.Horizon._registry[dash]._registry.keys() + self._discovered_panels[dash] = panels def tearDown(self): - super(HorizonTests, self).tearDown() - base.Horizon = self._orig_horizon + super(BaseHorizonTests, self).tearDown() + # Destroy our singleton and re-create it. + base.HorizonSite._instance = None + del base.Horizon + base.Horizon = base.HorizonSite() + # Reload the convenience references to Horizon stored in __init__ + reload(import_module("horizon")) + # Re-register our original dashboards and panels. + # This is necessary because autodiscovery only works on the first + # import, and calling reload introduces innumerable additional + # problems. Manual re-registration is the only good way for testing. + for dash in self._discovered_dashboards: + base.Horizon.register(dash) + for panel in self._discovered_panels[dash]: + dash.register(panel) + def _reload_urls(self): + ''' + Clears out the URL caches, reloads the root urls module, and + re-triggers the autodiscovery mechanism for Horizon. Allows URLs + to be re-calculated after registering new dashboards. Useful + only for testing and should never be used on a live site. + ''' + urlresolvers.clear_url_caches() + reload(import_module(settings.ROOT_URLCONF)) + base.Horizon._urls() + + +class HorizonTests(BaseHorizonTests): def test_registry(self): """ Verify registration and autodiscovery work correctly. @@ -57,11 +93,10 @@ class HorizonTests(test.TestCase): by virtue of the fact that the dashboards listed in ``settings.INSTALLED_APPS`` are loaded from the start. """ - # Registration - self.assertEqual(len(Horizon._registry), 3) + self.assertEqual(len(base.Horizon._registry), 3) horizon.register(MyDash) - self.assertEqual(len(Horizon._registry), 4) + self.assertEqual(len(base.Horizon._registry), 4) with self.assertRaises(ValueError): horizon.register(MyPanel) with self.assertRaises(ValueError): @@ -81,23 +116,24 @@ class HorizonTests(test.TestCase): '']) # Removal - self.assertEqual(len(Horizon._registry), 4) + self.assertEqual(len(base.Horizon._registry), 4) horizon.unregister(MyDash) - self.assertEqual(len(Horizon._registry), 3) + self.assertEqual(len(base.Horizon._registry), 3) with self.assertRaises(base.NotRegistered): horizon.get_dashboard(MyDash) def test_site(self): - self.assertEqual(unicode(Horizon), "Horizon") - self.assertEqual(repr(Horizon), "") - dash = Horizon.get_dashboard('nova') - self.assertEqual(Horizon.get_default_dashboard(), dash) + self.assertEqual(unicode(base.Horizon), "Horizon") + self.assertEqual(repr(base.Horizon), "") + dash = base.Horizon.get_dashboard('nova') + self.assertEqual(base.Horizon.get_default_dashboard(), dash) user = users.User() - self.assertEqual(Horizon.get_user_home(user), dash.get_absolute_url()) + self.assertEqual(base.Horizon.get_user_home(user), + dash.get_absolute_url()) def test_dashboard(self): syspanel = horizon.get_dashboard("syspanel") - self.assertEqual(syspanel._registered_with, Horizon) + self.assertEqual(syspanel._registered_with, base.Horizon) self.assertQuerysetEqual(syspanel.get_panels()['System Panel'], ['', '', @@ -133,7 +169,7 @@ class HorizonTests(test.TestCase): syspanel = horizon.get_dashboard("syspanel") instances = syspanel.get_panel("instances") instances.index_url_name = "does_not_exist" - with self.assertRaises(NoReverseMatch): + with self.assertRaises(urlresolvers.NoReverseMatch): instances.get_absolute_url() instances.index_url_name = "index" self.assertEqual(instances.get_absolute_url(), "/syspanel/instances/") @@ -145,18 +181,50 @@ class HorizonTests(test.TestCase): iter(urlpatterns) reversed(urlpatterns) + def test_horizon_test_isolation_1(self): + """ Isolation Test Part 1: sets a value. """ + syspanel = horizon.get_dashboard("syspanel") + syspanel.evil = True -class HorizonBaseViewTests(test.BaseViewTests): - def setUp(self): - super(HorizonBaseViewTests, self).setUp() - users.get_user_from_request = self._real_get_user_from_request + def test_horizon_test_isolation_2(self): + """ Isolation Test Part 2: The value set in part 1 should be gone. """ + syspanel = horizon.get_dashboard("syspanel") + self.assertFalse(hasattr(syspanel, "evil")) + +class HorizonBaseViewTests(BaseHorizonTests, test.BaseViewTests): def test_public(self): + users.get_user_from_request = self._real_get_user_from_request settings = horizon.get_dashboard("settings") # Known to have no restrictions on it other than being logged in. user_panel = settings.get_panel("user") url = user_panel.get_absolute_url() - client = Client() # Get a clean, logged out client instance. + # Get a clean, logged out client instance. + client = Client() client.logout() resp = client.get(url) self.assertRedirectsNoFollow(resp, '/accounts/login/?next=/settings/') + + def test_required_services(self): + horizon.register(MyDash) + MyDash.register(MyPanel) + dash = horizon.get_dashboard("mydash") + panel = dash.get_panel('myslug') + self._reload_urls() + + # With the required service, the page returns fine. + resp = self.client.get(panel.get_absolute_url()) + self.assertEqual(resp.status_code, 200) + + # Remove the required service from the service catalog and we + # should get a 404. + new_catalog = [service for service in self.request.user.service_catalog + if service['type'] != MyPanel.services[0]] + tenants = self.TEST_CONTEXT['authorized_tenants'] + self.setActiveUser(token=self.TEST_TOKEN, + username=self.TEST_USER, + tenant_id=self.TEST_TENANT, + service_catalog=new_catalog, + authorized_tenants=tenants) + resp = self.client.get(panel.get_absolute_url()) + self.assertEqual(resp.status_code, 404) diff --git a/horizon/horizon/tests/context_processor_tests.py b/horizon/horizon/tests/context_processor_tests.py index e938cccdc..817ae20ed 100644 --- a/horizon/horizon/tests/context_processor_tests.py +++ b/horizon/horizon/tests/context_processor_tests.py @@ -52,15 +52,3 @@ class ContextProcessorTests(test.TestCase): self.assertEqual(len(context['authorized_tenants']), 1) tenant = context['authorized_tenants'].pop() self.assertEqual(tenant['id'], self.TEST_TENANT) - - def test_object_store(self): - # Returns the object store service data when it's in the catalog - context = context_processors.horizon(self.request) - self.assertNotEqual(None, context['object_store_configured']) - - # Returns None when the object store is not in the catalog - new_catalog = [service for service in self.request.user.service_catalog - if service['type'] != 'object-store'] - self.request.user.service_catalog = new_catalog - context = context_processors.horizon(self.request) - self.assertEqual(None, context['object_store_configured']) diff --git a/horizon/horizon/tests/templates/404.html b/horizon/horizon/tests/templates/404.html new file mode 100644 index 000000000..e69de29bb diff --git a/horizon/horizon/tests/test_panel_urls.py b/horizon/horizon/tests/test_panel_urls.py new file mode 100644 index 000000000..93f61d2a6 --- /dev/null +++ b/horizon/horizon/tests/test_panel_urls.py @@ -0,0 +1,21 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Nebula, Inc. +# +# 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 django.conf.urls.defaults import * + +urlpatterns = patterns('', + url(r'^$', 'horizon.tests.views.fakeView', name='index'), +) diff --git a/horizon/horizon/tests/testsettings.py b/horizon/horizon/tests/testsettings.py index 6b0f7f450..96496920a 100644 --- a/horizon/horizon/tests/testsettings.py +++ b/horizon/horizon/tests/testsettings.py @@ -71,12 +71,6 @@ NOVA_DEFAULT_REGION = 'test' NOVA_ACCESS_KEY = 'test' NOVA_SECRET_KEY = 'test' -QUANTUM_URL = '127.0.0.1' -QUANTUM_PORT = '9696' -QUANTUM_TENANT = '1234' -QUANTUM_CLIENT_VERSION = '0.1' -QUANTUM_ENABLED = True - CREDENTIAL_AUTHORIZATION_DAYS = 2 CREDENTIAL_DOWNLOAD_URL = TESTSERVER + '/credentials/' @@ -95,11 +89,6 @@ HORIZON_CONFIG = { 'default_dashboard': 'nova', } -SWIFT_ACCOUNT = 'test' -SWIFT_USER = 'tester' -SWIFT_PASS = 'testing' -SWIFT_AUTHURL = 'http://swift/swiftapi/v1.0' - AVAILABLE_REGIONS = [ ('http://localhost:5000/v2.0', 'local'), ('http://remote:5000/v2.0', 'remote'), diff --git a/openstack-dashboard/local/local_settings.py.example b/openstack-dashboard/local/local_settings.py.example index 74bdccc62..1e7ed73d2 100644 --- a/openstack-dashboard/local/local_settings.py.example +++ b/openstack-dashboard/local/local_settings.py.example @@ -55,13 +55,6 @@ OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member" # providing a paging element (a "more" link) to paginate results. API_RESULT_LIMIT = 1000 -# Configure quantum connection details for networking -QUANTUM_ENABLED = True -QUANTUM_URL = '%s' % OPENSTACK_HOST -QUANTUM_PORT = '9696' -QUANTUM_TENANT = '1234' -QUANTUM_CLIENT_VERSION='0.1' - # If you have external monitoring links, eg: # EXTERNAL_MONITORING = [ # ['Nagios','http://foo.com'],