Moved authorized_tenants retrieval to middleware.

Fixes bug 917263. By moving the tenant API call from the context
processor to the middleware the API call is no longer made
multiple times per request/response cycle.

Additionally, there are various PEP8 fixes included, with the
addition of one "ignore" flag to the PEP8 runner (related to
github issue #34 for pep8.py).

Change-Id: I5c755dfe381b1c38dbeeb99eb2b7ed9172d16f86
This commit is contained in:
Gabriel Hurley 2012-01-16 10:05:11 -08:00
parent 3cb2c0d919
commit a77ed5e534
10 changed files with 70 additions and 43 deletions

View File

@ -37,8 +37,8 @@ def horizon(request):
Adds three variables to the request context:
``tenants``
A list of the tenants the current uses is authorized to access.
``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
@ -49,6 +49,12 @@ def horizon(request):
Additionally, it sets the names ``True`` and ``False`` in the context
to their boolean equivalents for convenience.
.. warning::
Don't put API calls in context processors; they will be called once
for each template/template fragment which takes context that is used
to render the complete output.
"""
context = {"True": True,
"False": False}
@ -56,19 +62,7 @@ def horizon(request):
# Auth/Keystone context
context.setdefault('authorized_tenants', [])
if request.user.is_authenticated():
try:
tenants = api.tenant_list_for_token(request,
request.user.token,
endpoint_type='internalURL')
context['authorized_tenants'] = tenants
except Exception, e:
if hasattr(request.user, 'message_set'):
if not hasattr(e, 'message'):
e.message = str(e)
messages.error(request, _("Unable to retrieve tenant list: %s")
% e.message)
else:
LOG.exception('Could not retrieve tenant list.')
context['authorized_tenants'] = request.user.authorized_tenants
# Object Store/Swift context
catalog = getattr(request.user, 'service_catalog', [])

View File

@ -52,7 +52,7 @@ class TenantsViewTests(test.BaseAdminViewTests):
cores='1')
self.quota = FakeQuotaSet(id=self.TEST_TENANT, **self.quota_data)
self.tenants = [self.tenant,]
self.tenants = [self.tenant]
def test_index(self):
self.mox.StubOutWithMock(api, 'tenant_list')

View File

@ -96,7 +96,7 @@ class SelectDateWidget(widgets.Widget):
self.month_field, value, month_val, choices)
choices = [(i, i) for i in range(1, 32)]
day_html = self.create_select(name,
self.day_field, value, day_val, choices)
self.day_field, value, day_val, choices)
format = formats.get_format('DATE_FORMAT')
escaped = False

View File

@ -21,13 +21,19 @@
Middleware provided and used by Horizon.
"""
import logging
from django.contrib import messages
from django import shortcuts
from horizon import api
from horizon import exceptions
from horizon import users
LOG = logging.getLogger(__name__)
class HorizonMiddleware(object):
""" The main Horizon middleware class. Required for use of Horizon. """
@ -41,6 +47,19 @@ 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:
authd = api.tenant_list_for_token(request,
request.user.token,
endpoint_type='internalURL')
except Exception, e:
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):
""" Catch NotAuthorized and Http302 and handle them gracefully. """

View File

@ -137,10 +137,12 @@ class TestCase(django_test.TestCase):
context_processors.horizon = lambda request: self.TEST_CONTEXT
self._real_get_user_from_request = users.get_user_from_request
tenants = self.TEST_CONTEXT['authorized_tenants']
self.setActiveUser(token=self.TEST_TOKEN,
username=self.TEST_USER,
tenant_id=self.TEST_TENANT,
service_catalog=self.TEST_SERVICE_CATALOG)
service_catalog=self.TEST_SERVICE_CATALOG,
authorized_tenants=tenants)
self.request = http.HttpRequest()
middleware.HorizonMiddleware().process_request(self.request)
@ -152,13 +154,15 @@ class TestCase(django_test.TestCase):
self.mox.VerifyAll()
def setActiveUser(self, id=None, token=None, username=None, tenant_id=None,
service_catalog=None, tenant_name=None, roles=None):
service_catalog=None, tenant_name=None, roles=None,
authorized_tenants=None):
users.get_user_from_request = lambda x: \
users.User(id=id,
token=token,
user=username,
tenant_id=tenant_id,
service_catalog=service_catalog)
service_catalog=service_catalog,
authorized_tenants=authorized_tenants)
def override_times(self):
now = datetime.datetime.utcnow()
@ -187,11 +191,13 @@ class BaseViewTests(TestCase):
class BaseAdminViewTests(BaseViewTests):
def setActiveUser(self, id=None, token=None, username=None, tenant_id=None,
service_catalog=None, tenant_name=None, roles=None):
service_catalog=None, tenant_name=None, roles=None,
authorized_tenants=None):
users.get_user_from_request = lambda x: \
users.User(id=self.TEST_USER_ID,
token=self.TEST_TOKEN,
user=self.TEST_USER,
tenant_id=self.TEST_TENANT,
service_catalog=self.TEST_SERVICE_CATALOG,
roles=self.TEST_ROLES)
roles=self.TEST_ROLES,
authorized_tenants=None)

View File

@ -174,16 +174,7 @@ class AuthViewTests(test.BaseViewTests):
NEW_TENANT_ID = '6'
NEW_TENANT_NAME = 'FAKENAME'
TOKEN_ID = 1
self.setActiveUser(self.TEST_USER_ID, self.TEST_TOKEN, self.TEST_USER,
self.TEST_TENANT, False, self.TEST_SERVICE_CATALOG)
form_data = {'method': 'LoginWithTenant',
'password': self.PASSWORD,
'tenant': NEW_TENANT_ID,
'username': self.TEST_USER}
self.mox.StubOutWithMock(api, 'token_create')
tenants = self.TEST_CONTEXT['authorized_tenants']
aTenant = self.mox.CreateMock(api.Token)
aTenant.id = NEW_TENANT_ID
@ -196,15 +187,27 @@ class AuthViewTests(test.BaseViewTests):
aToken.serviceCatalog = {}
aToken.tenant = {'id': aTenant.id, 'name': aTenant.name}
self.setActiveUser(id=self.TEST_USER_ID,
token=self.TEST_TOKEN,
username=self.TEST_USER,
tenant_id=self.TEST_TENANT,
service_catalog=self.TEST_SERVICE_CATALOG,
authorized_tenants=tenants)
self.mox.StubOutWithMock(api, 'token_create')
self.mox.StubOutWithMock(api, 'tenant_list_for_token')
api.token_create(IsA(http.HttpRequest), NEW_TENANT_ID, self.TEST_USER,
self.PASSWORD).AndReturn(aToken)
self.mox.StubOutWithMock(api, 'tenant_list_for_token')
api.tenant_list_for_token(IsA(http.HttpRequest), aToken.id).\
AndReturn([aTenant])
api.tenant_list_for_token(IsA(http.HttpRequest), aToken.id) \
.AndReturn([aTenant])
self.mox.ReplayAll()
form_data = {'method': 'LoginWithTenant',
'password': self.PASSWORD,
'tenant': NEW_TENANT_ID,
'username': self.TEST_USER}
res = self.client.post(reverse('horizon:auth_switch',
args=[NEW_TENANT_ID]), form_data)

View File

@ -21,9 +21,10 @@
from django import http
from mox import IsA
from horizon import context_processors
from horizon import test
from horizon import api
from horizon import context_processors
from horizon import middleware
from horizon import test
class ContextProcessorTests(test.TestCase):
@ -38,6 +39,7 @@ class ContextProcessorTests(test.TestCase):
def test_authorized_tenants(self):
tenant_list = self.TEST_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.TEST_TOKEN,
@ -45,6 +47,7 @@ class ContextProcessorTests(test.TestCase):
.AndReturn(tenant_list)
self.mox.ReplayAll()
middleware.HorizonMiddleware().process_request(self.request)
context = context_processors.horizon(self.request)
self.assertEqual(len(context['authorized_tenants']), 1)
tenant = context['authorized_tenants'].pop()

View File

@ -101,7 +101,8 @@ class User(object):
privileges. Internally mapped to :meth:`horizon.users.User.is_admin`.
"""
def __init__(self, id=None, token=None, user=None, tenant_id=None,
service_catalog=None, tenant_name=None, roles=None):
service_catalog=None, tenant_name=None, roles=None,
authorized_tenants=None):
self.id = id
self.token = token
self.username = user
@ -109,6 +110,7 @@ class User(object):
self.tenant_name = tenant_name
self.service_catalog = service_catalog
self.roles = roles or []
self.authorized_tenants = authorized_tenants
def is_authenticated(self):
"""

View File

@ -70,9 +70,9 @@ class Login(forms.SelfHandlingForm):
data['username'],
data['password'])
tenants = api.tenant_list_for_token(request, token.id)
except Exception, e:
except:
exceptions.handle(request,
message=_('Error authenticating: %s') % e,
message=_('Unable to authenticate tenant.'),
escalate=True)
tenant = None
for t in tenants:
@ -94,7 +94,6 @@ class Login(forms.SelfHandlingForm):
except:
exceptions.handle(request, escalate=True)
# Unscoped token
request.session['unscoped_token'] = token.id
request.user.username = data['username']

View File

@ -115,7 +115,8 @@ function run_pep8 {
echo "Running pep8 ..."
rm -f pep8.txt
PEP8_EXCLUDE=vcsversion.py
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat"
PEP8_IGNORE=W602
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --ignore=$PEP8_IGNORE --repeat"
${command_wrapper} pep8 $PEP8_OPTIONS $included_dirs | perl -ple 's/: ([WE]\d+)/: [$1]/' > pep8.txt || true
PEP8_COUNT=`wc -l pep8.txt | awk '{ print $1 }'`
if [ $PEP8_COUNT -ge 1 ]; then