diff --git a/netbox/extras/scripts.py b/netbox/extras/scripts.py index 489ee7633..7814163b7 100644 --- a/netbox/extras/scripts.py +++ b/netbox/extras/scripts.py @@ -5,6 +5,7 @@ import pkgutil from django import forms from django.conf import settings from django.core.validators import RegexValidator +from django.db import transaction from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING from .forms import ScriptForm @@ -196,6 +197,23 @@ def is_variable(obj): return isinstance(obj, ScriptVariable) +def run_script(script, data=None): + """ + A wrapper for calling Script.run(). This performs error handling. It exists outside of the Script class to ensure + it cannot be overridden by a script author. + """ + try: + with transaction.atomic(): + return script.run(data) + except Exception as e: + script.log_failure( + "An exception occurred: {}".format(e) + ) + script.log_info( + "Database changes have been reverted automatically." + ) + + def get_scripts(): scripts = OrderedDict() diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 845b01f49..b359077cf 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -3,7 +3,6 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.contenttypes.models import ContentType -from django.db import transaction from django.db.models import Count, Q from django.http import Http404, HttpResponseForbidden from django.shortcuts import get_object_or_404, redirect, render @@ -21,7 +20,7 @@ from .forms import ( ) from .models import ConfigContext, ImageAttachment, ObjectChange, ReportResult, Tag, TaggedItem from .reports import get_report, get_reports -from .scripts import get_scripts +from .scripts import get_scripts, run_script from .tables import ConfigContextTable, ObjectChangeTable, TagTable, TaggedItemTable @@ -405,9 +404,7 @@ class ScriptView(PermissionRequiredMixin, View): output = None if form.is_valid(): - - with transaction.atomic(): - output = script.run(form.cleaned_data) + run_script(script) return render(request, 'extras/script.html', { 'module': module,