1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

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

This commit is contained in:
Jeremy Stretch
2017-11-03 13:24:31 -04:00
parent f2fbd92f78
commit f77bf72de8
8 changed files with 101 additions and 32 deletions

View File

@ -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',
)

View File

@ -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),

View File

@ -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."
)

View File

@ -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>

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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)