Consolidate redundant traceback rendering

This commit is contained in:
Brian Tiemann
2026-03-11 20:47:32 -04:00
parent 28ac5b6201
commit 07238e9f9c
4 changed files with 28 additions and 36 deletions
+5 -20
View File
@@ -1,10 +1,7 @@
import traceback
from jinja2.exceptions import TemplateError
from rest_framework.decorators import action
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from netbox.api.authentication import TokenWritePermission
from netbox.api.renderers import TextRenderer
@@ -47,23 +44,11 @@ class ConfigTemplateRenderMixin:
def render_configtemplate(self, request, configtemplate, context):
try:
output = configtemplate.render(context=context)
except TemplateError as e:
if configtemplate.debug:
detail = traceback.format_exc()
else:
parts = [f"{type(e).__name__}: {e}"]
if getattr(e, 'name', None):
parts.append(f"Template: {e.name}")
if getattr(e, 'lineno', None):
parts.append(f"Line: {e.lineno}")
detail = "\n".join(parts)
return Response({'detail': detail}, status=500)
except Exception as e:
if configtemplate.debug:
detail = traceback.format_exc()
else:
detail = f"{type(e).__name__}: {e}"
return Response({'detail': detail}, status=500)
return Response(
{'detail': configtemplate.format_render_error(e)},
status=HTTP_500_INTERNAL_SERVER_ERROR,
)
# If the client has requested "text/plain", return the raw content.
if request.accepted_renderer.format == 'txt':
+21
View File
@@ -1,9 +1,12 @@
import traceback
import jsonschema
from django.conf import settings
from django.core.validators import ValidationError
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from jinja2.exceptions import TemplateError
from jsonschema.exceptions import ValidationError as JSONValidationError
from extras.models.mixins import RenderTemplateMixin
@@ -306,3 +309,21 @@ class ConfigTemplate(
"""
self.template_code = self.data_file.data_as_string
sync_data.alters_data = True
def format_render_error(self, exc):
"""
Return a formatted error string for a rendering exception. When debug is enabled, the full
traceback is returned. Otherwise, a concise, user-facing message is returned.
Must be called from within the except block so that traceback.format_exc() is valid.
"""
if self.debug:
return traceback.format_exc()
if isinstance(exc, TemplateError):
parts = [f"{type(exc).__name__}: {exc}"]
if getattr(exc, 'name', None):
parts.append(_("Template: {name}").format(name=exc.name))
if getattr(exc, 'lineno', None):
parts.append(_("Line: {lineno}").format(lineno=exc.lineno))
return "\n".join(parts)
return f"{type(exc).__name__}: {exc}"
+1
View File
@@ -699,6 +699,7 @@ class ConfigTemplateTable(NetBoxTable):
)
debug = columns.BooleanColumn(
verbose_name=_('Debug'),
false_mark=None
)
owner = tables.Column(
linkify=True,
+1 -16
View File
@@ -1,4 +1,3 @@
import traceback
from datetime import datetime
from django.contrib import messages
@@ -13,7 +12,6 @@ from django.utils import timezone
from django.utils.module_loading import import_string
from django.utils.translation import gettext as _
from django.views.generic import View
from jinja2.exceptions import TemplateError
from core.choices import ManagedFileRootPathChoices
from core.models import Job
@@ -1125,21 +1123,8 @@ class ObjectRenderConfigView(generic.ObjectView):
if config_template:
try:
rendered_config = config_template.render(context=context_data)
except TemplateError as e:
if config_template.debug:
error_message = traceback.format_exc()
else:
parts = [f"{type(e).__name__}: {e}"]
if getattr(e, 'name', None):
parts.append(_("Template: {name}").format(name=e.name))
if getattr(e, 'lineno', None):
parts.append(_("Line: {lineno}").format(lineno=e.lineno))
error_message = "\n".join(parts)
except Exception as e:
if config_template.debug:
error_message = traceback.format_exc()
else:
error_message = f"{type(e).__name__}: {e}"
error_message = config_template.format_render_error(e)
return {
'base_template': self.base_template,