User.authorized_tenants is now a cached property.

This allows moving the call to get authorized tenants out of
the middleware (which was a wasteful call on many requests),
and allows the value to be re-used anytime it's accessed more
than once per request.

Fixes bug 942074.

Change-Id: Ic09b15adbffb16c0358bb28aec73345cc01834ad
This commit is contained in:
Gabriel Hurley 2012-03-13 15:09:12 -07:00
parent d3f2552547
commit 382a5105c4
8 changed files with 45 additions and 26 deletions

View File

@ -332,7 +332,7 @@ class Dashboard(Registry, HorizonComponent):
Optional boolean that indicates whether or not this dashboard includes
support for projects/tenants. If set to ``True`` this dashboard's
naviagtion will include a UI element that allows the user to select
navigation will include a UI element that allows the user to select
project/tenant. Default: ``False``.
.. attribute:: public

View File

@ -56,7 +56,9 @@ def horizon(request):
# Auth/Keystone context
context.setdefault('authorized_tenants', [])
if request.user.is_authenticated():
current_dash = request.horizon['dashboard']
needs_tenants = getattr(current_dash, 'supports_tenants', False)
if request.user.is_authenticated() and needs_tenants:
context['authorized_tenants'] = request.user.authorized_tenants
# Region context/support

View File

@ -53,21 +53,6 @@ class HorizonMiddleware(object):
"""
request.__class__.user = users.LazyUser()
request.horizon = {'dashboard': None, 'panel': None}
if request.user.is_authenticated() and \
request.user.authorized_tenants is None:
try:
token = request.session.get("unscoped_token",
request.user.token)
authd = api.tenant_list_for_token(request,
token,
endpoint_type='internalURL')
except:
authd = []
LOG.exception('Could not retrieve tenant list.')
if hasattr(request.user, 'message_set'):
messages.error(request,
_("Unable to retrieve tenant list."))
request.user.authorized_tenants = authd
def process_exception(self, request, exception):
"""

View File

@ -38,7 +38,7 @@ def can_haz(user, component):
user_roles = set([])
roles_statisfied = set(getattr(component, 'roles', [])) <= user_roles
if hasattr(user, 'roles'):
if hasattr(user, 'service_catalog'):
services = set([service['type'] for service in user.service_catalog])
else:
services = set([])

View File

@ -120,7 +120,8 @@ class TestCase(django_test.TestCase):
tenant_id=tenant_id,
service_catalog=service_catalog,
roles=roles,
authorized_tenants=authorized_tenants)
authorized_tenants=authorized_tenants,
request=self.request)
def override_times(self):
""" Overrides the "current" time with immutable values. """
@ -214,7 +215,8 @@ class BaseAdminViewTests(TestCase):
tenant_id=self.tenant.id,
service_catalog=self.service_catalog,
roles=[self.roles.admin._info],
authorized_tenants=None)
authorized_tenants=None,
request=self.request)
class APITestCase(TestCase):

View File

@ -249,6 +249,7 @@ class HorizonTests(BaseHorizonTests):
self.setActiveUser(token=self.token.id,
username=self.user.name,
tenant_id=self.tenant.id,
service_catalog=self.service_catalog,
roles=[])
resp = self.client.get(user_panel.get_absolute_url())

View File

@ -25,6 +25,7 @@ from horizon import api
from horizon import context_processors
from horizon import middleware
from horizon import test
from horizon import Dashboard
class ContextProcessorTests(test.TestCase):
@ -41,13 +42,21 @@ class ContextProcessorTests(test.TestCase):
tenant_list = self.context['authorized_tenants']
self.request.user.authorized_tenants = None # Reset from setUp
self.mox.StubOutWithMock(api, 'tenant_list_for_token')
api.tenant_list_for_token(IsA(http.HttpRequest),
self.token.id,
endpoint_type='internalURL') \
api.tenant_list_for_token(IsA(http.HttpRequest), self.token.id) \
.AndReturn(tenant_list)
self.mox.ReplayAll()
middleware.HorizonMiddleware().process_request(self.request)
# Without dashboard that has "supports_tenants = True"
context = context_processors.horizon(self.request)
self.assertEqual(len(context['authorized_tenants']), 0)
# With dashboard that has "supports_tenants = True"
class ProjectDash(Dashboard):
supports_tenants = True
self.request.horizon['dashboard'] = ProjectDash
self.assertTrue(self.request.user.is_authenticated())
context = context_processors.horizon(self.request)
self.assertEqual(len(context['authorized_tenants']), 1)
tenant = context['authorized_tenants'].pop()

View File

@ -25,6 +25,7 @@ import logging
from django.utils.translation import ugettext as _
from horizon import api
from horizon import exceptions
@ -52,7 +53,8 @@ def get_user_from_request(request):
tenant_id=request.session['tenant_id'],
tenant_name=request.session['tenant'],
service_catalog=request.session['serviceCatalog'],
roles=request.session['roles'])
roles=request.session['roles'],
request=request)
except KeyError:
# If any of those keys are missing from the session it is
# overwhelmingly likely that we're dealing with an outdated session.
@ -104,7 +106,7 @@ class User(object):
"""
def __init__(self, id=None, token=None, user=None, tenant_id=None,
service_catalog=None, tenant_name=None, roles=None,
authorized_tenants=None):
authorized_tenants=None, request=None):
self.id = id
self.token = token
self.username = user
@ -112,7 +114,9 @@ class User(object):
self.tenant_name = tenant_name
self.service_catalog = service_catalog
self.roles = roles or []
self.authorized_tenants = authorized_tenants
self._authorized_tenants = authorized_tenants
# Store the request for lazy fetching of auth'd tenants
self._request = request
def is_authenticated(self):
"""
@ -142,3 +146,19 @@ class User(object):
``django.contrib.auth.models.User``.
"""
return []
@property
def authorized_tenants(self):
if self.is_authenticated() and self._authorized_tenants is None:
try:
token = self._request.session.get("unscoped_token", self.token)
authd = api.tenant_list_for_token(self._request, token)
except:
authd = []
LOG.exception('Could not retrieve tenant list.')
self._authorized_tenants = authd
return self._authorized_tenants
@authorized_tenants.setter
def authorized_tenants(self, tenant_list):
self._authorized_tenants = tenant_list