Browse Source

HUE-964 [core] 500 errors should go to default debugger if we cannot render custom 500

The scenario where we do not have all the context prepared for proper rendering of a 500 error
is when there is an error early on in the middleware pipeline. IE: an import error.
abec 13 years ago
parent
commit
ab5cee9432
2 changed files with 39 additions and 3 deletions
  1. 28 1
      desktop/core/src/desktop/tests.py
  2. 11 2
      desktop/core/src/desktop/views.py

+ 28 - 1
desktop/core/src/desktop/tests.py

@@ -18,11 +18,12 @@
 from desktop.lib import django_mako
 from desktop.lib import django_mako
 
 
 from nose.tools import assert_true, assert_equal, assert_not_equal
 from nose.tools import assert_true, assert_equal, assert_not_equal
-from desktop.lib.django_test_util import make_logged_in_client
 from django.conf.urls.defaults import patterns, url
 from django.conf.urls.defaults import patterns, url
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.http import HttpResponse
 from django.http import HttpResponse
 from django.db.models import query, CharField, SmallIntegerField
 from django.db.models import query, CharField, SmallIntegerField
+from django.test.client import Client
+from desktop.lib.django_test_util import make_logged_in_client
 from desktop.lib.paginator import Paginator
 from desktop.lib.paginator import Paginator
 from desktop.lib.conf import validate_path
 from desktop.lib.conf import validate_path
 import desktop
 import desktop
@@ -292,6 +293,32 @@ def test_error_handling():
     restore_500_debug()
     restore_500_debug()
 
 
 
 
+def test_error_handling_failure():
+  # Change rewrite_user to call has_hue_permission
+  # Try to get filebrowser page
+  # test for werkzeug debugger
+  # Restore rewrite_user
+
+  restore_django_debug = desktop.conf.DJANGO_DEBUG_MODE.set_for_testing(False)
+  restore_500_debug = desktop.conf.HTTP_500_DEBUG_MODE.set_for_testing(False)
+
+  # Add an error view
+  setattr(views.serve_500_error, 'login_notrequired', True)
+  error_url_pat = patterns('', url('^500_internal_error$', views.serve_500_error))
+  desktop.urls.urlpatterns.extend(error_url_pat)
+  try:
+    c = Client()
+    response = c.get('/500_internal_error')
+    assert_true('AttributeError at /500_internal_error' in response.content, response)
+  finally:
+    # Restore the world
+    for i in error_url_pat:
+      desktop.urls.urlpatterns.remove(i)
+    restore_django_debug()
+    restore_500_debug()
+    delattr(views.serve_500_error, 'login_notrequired')
+
+
 def test_404_handling():
 def test_404_handling():
   view_name = '/the-view-that-is-not-there'
   view_name = '/the-view-that-is-not-there'
   c = make_logged_in_client()
   c = make_logged_in_client()

+ 11 - 2
desktop/core/src/desktop/views.py

@@ -221,7 +221,15 @@ def serve_500_error(request, *args, **kwargs):
   """Registered handler for 500. We use the debug view to make debugging easier."""
   """Registered handler for 500. We use the debug view to make debugging easier."""
   if desktop.conf.HTTP_500_DEBUG_MODE.get():
   if desktop.conf.HTTP_500_DEBUG_MODE.get():
     return django.views.debug.technical_500_response(request, *sys.exc_info())
     return django.views.debug.technical_500_response(request, *sys.exc_info())
-  return render("500.mako", request, {'traceback': traceback.extract_tb(sys.exc_info()[2])})
+  try:
+    return render("500.mako", request, {'traceback': traceback.extract_tb(sys.exc_info()[2])})
+  except:
+    # Fallback to technical 500 response if ours fails
+    # Will end up here:
+    #   - Middleware or authentication backends problems
+    #   - Certain missing imports
+    #   - Packaging and install issues
+    return django.views.debug.technical_500_response(request, *sys.exc_info())
 
 
 _LOG_LEVELS = {
 _LOG_LEVELS = {
   "critical": logging.CRITICAL,
   "critical": logging.CRITICAL,
@@ -270,7 +278,8 @@ def commonheader(title, section, user, padding="60px"):
   """
   """
   Returns the rendered common header
   Returns the rendered common header
   """
   """
-  apps_list = sorted(appmanager.get_apps(user), key=lambda app: app.menu_index)
+  apps = appmanager.get_apps(user)
+  apps_list = sorted(apps, key=lambda app: app.menu_index)
 
 
   return django_mako.render_to_string("common_header.mako", dict(
   return django_mako.render_to_string("common_header.mako", dict(
     apps=apps_list,
     apps=apps_list,