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 | 124 ++++++++++++++---- .../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, 255 insertions(+), 113 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 0b45ffd16ce..5b7f5dadb22 100644 --- a/horizon/horizon/api/__init__.py +++ b/horizon/horizon/api/__init__.py @@ -36,5 +36,8 @@ 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 be8a4e5d3c7..5caa8958593 100644 --- a/horizon/horizon/base.py +++ b/horizon/horizon/base.py @@ -36,7 +36,8 @@ 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 @@ def _register(self, cls): 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 @@ def _unregister(self, cls): 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 @@ def _registered(self, cls): "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 @@ def _decorated_urls(self): # 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 Syspanel(horizon.Dashboard): 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 @@ def _decorated_urls(self): _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 @@ def _autodiscover(self): @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 @@ def __reversed__(self): 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 @@ def url_patterns(): 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 @@ def _autodiscover(self): 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 c78506b3c36..09b2556dd2a 100644 --- a/horizon/horizon/context_processors.py +++ b/horizon/horizon/context_processors.py @@ -34,17 +34,15 @@ 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 89e04353074..36447a6b75b 100644 --- a/horizon/horizon/dashboards/nova/containers/panel.py +++ b/horizon/horizon/dashboards/nova/containers/panel.py @@ -27,9 +27,6 @@ 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 c4636968932..529339f641a 100644 --- a/horizon/horizon/dashboards/nova/networks/panel.py +++ b/horizon/horizon/dashboards/nova/networks/panel.py @@ -25,9 +25,7 @@ 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 886cbe65fd3..9d9254953e9 100644 --- a/horizon/horizon/decorators.py +++ b/horizon/horizon/decorators.py @@ -25,7 +25,7 @@ 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 dec(request, *args, **kwargs): 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 8fe81bef212..09e2d53347f 100644 --- a/horizon/horizon/middleware.py +++ b/horizon/horizon/middleware.py @@ -23,6 +23,7 @@ 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 @@ def process_request(self, request): 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 @@ def process_request(self, request): 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 9b17380a21d..b14eecc905a 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 d19803d9feb..1a812c0d329 100644 --- a/horizon/horizon/templatetags/horizon.py +++ b/horizon/horizon/templatetags/horizon.py @@ -28,16 +28,32 @@ @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 9c8fe07380a..1f5e04384ec 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 b362efaeb75..852b3d3391d 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 @@ def test_registry(self): 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 @@ def test_registry(self): '']) # 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 @@ def test_index_url_name(self): 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 @@ def test_lazy_urls(self): 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 + + 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(test.BaseViewTests): - def setUp(self): - super(HorizonBaseViewTests, self).setUp() - users.get_user_from_request = self._real_get_user_from_request +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 e938cccdc3a..817ae20ed9a 100644 --- a/horizon/horizon/tests/context_processor_tests.py +++ b/horizon/horizon/tests/context_processor_tests.py @@ -52,15 +52,3 @@ def test_authorized_tenants(self): 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 00000000000..e69de29bb2d diff --git a/horizon/horizon/tests/test_panel_urls.py b/horizon/horizon/tests/test_panel_urls.py new file mode 100644 index 00000000000..93f61d2a6f9 --- /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 6b0f7f450cf..96496920a2b 100644 --- a/horizon/horizon/tests/testsettings.py +++ b/horizon/horizon/tests/testsettings.py @@ -71,12 +71,6 @@ 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 @@ '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 74bdccc6294..1e7ed73d2e6 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'],