Parcourir la source

Closes #1683: Replaced default 500 handler with custom middleware to provide preliminary troubleshooting assistance

Jeremy Stretch il y a 7 ans
Parent
commit
f77bf72de8

+ 1 - 0
netbox/netbox/settings.py

@@ -148,6 +148,7 @@ MIDDLEWARE = (
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.security.SecurityMiddleware',
+    'utilities.middleware.ExceptionHandlingMiddleware',
     'utilities.middleware.LoginRequiredMiddleware',
     'utilities.middleware.APIVersionMiddleware',
 )

+ 1 - 5
netbox/netbox/urls.py

@@ -7,11 +7,10 @@ from django.conf.urls import include, url
 from django.contrib import admin
 from django.views.static import serve
 
-from netbox.views import APIRootView, handle_500, HomeView, SearchView, trigger_500
+from netbox.views import APIRootView, HomeView, SearchView
 from users.views import LoginView, LogoutView
 
 
-handler500 = handle_500
 swagger_view = get_swagger_view(title='NetBox API')
 
 _patterns = [
@@ -48,9 +47,6 @@ _patterns = [
     # Serving static media in Django to pipe it through LoginRequiredMiddleware
     url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
 
-    # Error testing
-    url(r'^500/$', trigger_500),
-
     # Admin
     url(r'^admin/', admin.site.urls),
 

+ 0 - 20
netbox/netbox/views.py

@@ -247,23 +247,3 @@ class APIRootView(APIView):
             ('tenancy', reverse('tenancy-api:api-root', request=request, format=format)),
             ('virtualization', reverse('virtualization-api:api-root', request=request, format=format)),
         )))
-
-
-def handle_500(request):
-    """
-    Custom server error handler
-    """
-    type_, error, traceback = sys.exc_info()
-    return render(request, '500.html', {
-        'exception': str(type_),
-        'error': error,
-    }, status=500)
-
-
-def trigger_500(request):
-    """
-    Hot-wired method of triggering a server error to test reporting
-    """
-    raise Exception(
-        "Congratulations, you've triggered an exception! Go tell all your friends what an exceptional person you are."
-    )

+ 13 - 6
netbox/templates/500.html

@@ -12,7 +12,7 @@
 <body>
     <div class="container-fluid">
         <div class="row">
-            <div class="col-md-4 col-md-offset-4">
+            <div class="col-md-6 col-md-offset-3">
                 <div class="panel panel-danger" style="margin-top: 200px">
                     <div class="panel-heading">
                         <strong>
@@ -21,13 +21,20 @@
                         </strong>
                     </div>
                     <div class="panel-body">
-                        <p>There was a problem with your request. This error has been logged and administrative staff have
-                        been notified. Please return to the home page and try again.</p>
-                        <p>If you are responsible for this installation, please consider
-                        <a href="https://github.com/digitalocean/netbox/issues">filing a bug report</a>. Additional
-                        information is provided below:</p>
+                        {% block message %}
+                            <p>
+                                There was a problem with your request. Please contact an administrator.
+                            </p>
+                        {% endblock %}
+                        <hr />
+                        <p>
+                            The complete exception is provided below:
+                        </p>
 <pre><strong>{{ exception }}</strong><br />
 {{ error }}</pre>
+                        <p>
+                            If further assistance is required, please post to the <a href="https://groups.google.com/forum/#!forum/netbox-discuss">NetBox mailing list</a>.
+                        </p>
                         <div class="text-right">
                             <a href="{% url 'home' %}" class="btn btn-primary">Home Page</a>
                         </div>

+ 18 - 0
netbox/templates/exceptions/import_error.html

@@ -0,0 +1,18 @@
+{% extends '500.html' %}
+
+{% block message %}
+    <p>
+        A module import error occurred during this request. Common causes include the following:
+    </p>
+    <p>
+        <i class="fa fa-warning"></i> <strong>Missing required packages</strong> - This installation of NetBox might be missing one or more required
+        Python packages. These packages are listed in <code>requirements.txt</code> and are normally installed as part
+        of the installation or upgrade process. To verify installed packages, run <code>pip freeze</code> from the
+        console and compare the output to the list of required packages.
+    </p>
+    <p>
+        <i class="fa fa-warning"></i> <strong>WSGI service not restarted after upgrade</strong> - If this installation has recently been upgraded,
+        check that the WSGI service (e.g. gunicorn or uWSGI) has been restarted. This ensures that the new code is
+        running.
+    </p>
+{% endblock %}

+ 12 - 0
netbox/templates/exceptions/permission_error.html

@@ -0,0 +1,12 @@
+{% extends '500.html' %}
+
+{% block message %}
+    <p>
+        A file permission error was detected while processing this request. Common causes include the following:
+    </p>
+    <p>
+        <i class="fa fa-warning"></i> <strong>Insufficient write permission to the media root</strong> - The configured
+        media root is <code>{{ settings.MEDIA_ROOT }}</code>. Ensure that the user NetBox runs as has access to write
+        files to all locations within this path.
+    </p>
+{% endblock %}

+ 17 - 0
netbox/templates/exceptions/programming_error.html

@@ -0,0 +1,17 @@
+{% extends '500.html' %}
+
+{% block message %}
+    <p>
+        A database programming error was detected while processing this request. Common causes include the following:
+    </p>
+    <p>
+        <i class="fa fa-warning"></i> <strong>Database migrations missing</strong> - When upgrading to a new NetBox release, the upgrade script must
+        be run to apply any new database migrations. You can run migrations manually by executing
+        <code>python3 manage.py migrate</code> from the command line.
+    </p>
+    <p>
+        <i class="fa fa-warning"></i> <strong>Unsupported PostgreSQL version</strong> - Ensure that PostgreSQL version 9.4 or higher is in use. You
+        can check this by connecting to the database using NetBox's credentials and issuing a query for
+        <code>SELECT VERSION()</code>.
+    </p>
+{% endblock %}

+ 39 - 1
netbox/utilities/middleware.py

@@ -1,7 +1,10 @@
 from __future__ import unicode_literals
+import sys
 
-from django.http import HttpResponseRedirect
 from django.conf import settings
+from django.db import ProgrammingError
+from django.http import HttpResponseRedirect
+from django.shortcuts import render
 from django.urls import reverse
 
 
@@ -39,3 +42,38 @@ class APIVersionMiddleware(object):
         if request.path_info.startswith(api_path):
             response['API-Version'] = settings.REST_FRAMEWORK_VERSION
         return response
+
+
+class ExceptionHandlingMiddleware(object):
+    """
+    Intercept certain exceptions which are likely indicative of installation issues and provide helpful instructions
+    to the user.
+    """
+    def __init__(self, get_response):
+        self.get_response = get_response
+
+    def __call__(self, request):
+        return self.get_response(request)
+
+    def process_exception(self, request, exception):
+
+        # Raise exceptions if in debug mode
+        if settings.DEBUG:
+            raise exception
+
+        # Determine the type of exception
+        if isinstance(exception, ProgrammingError):
+            template_name = 'exceptions/programming_error.html'
+        elif isinstance(exception, ImportError):
+            template_name = 'exceptions/import_error.html'
+        elif isinstance(exception, PermissionError):
+            template_name = 'exceptions/permission_error.html'
+        else:
+            template_name = '500.html'
+
+        # Return an error message
+        type_, error, traceback = sys.exc_info()
+        return render(request, template_name, {
+            'exception': str(type_),
+            'error': error,
+        }, status=500)