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

Add option to commit database changes

This commit is contained in:
Jeremy Stretch
2019-08-12 14:28:06 -04:00
parent 3e75da4307
commit 0d289d660d
5 changed files with 38 additions and 11 deletions

View File

@ -387,6 +387,12 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
#
class ScriptForm(BootstrapMixin, forms.Form):
_commit = forms.BooleanField(
required=False,
initial=True,
label="Commit changes",
help_text="Commit changes to the database (uncheck for a dry-run)"
)
def __init__(self, vars, *args, **kwargs):
@ -395,3 +401,6 @@ class ScriptForm(BootstrapMixin, forms.Form):
# Dynamically populate fields for variables
for name, var in vars.items():
self.fields[name] = var.as_field()
# Move _commit to the end of the form
self.fields.move_to_end('_commit', True)

View File

@ -7,6 +7,7 @@ from django.conf import settings
from django.core.validators import RegexValidator
from django.db import transaction
from utilities.exceptions import AbortTransaction
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
from .forms import ScriptForm
@ -197,21 +198,32 @@ def is_variable(obj):
return isinstance(obj, ScriptVariable)
def run_script(script, data=None):
def run_script(script, data, commit=True):
"""
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.
A wrapper for calling Script.run(). This performs error handling and provides a hook for committing changes. It
exists outside of the Script class to ensure it cannot be overridden by a script author.
"""
output = None
try:
with transaction.atomic():
return script.run(data)
output = script.run(data)
if not commit:
raise AbortTransaction()
except AbortTransaction:
pass
except Exception as e:
script.log_failure(
"An exception occurred: {}".format(e)
)
script.log_info(
"Database changes have been reverted automatically."
"An exception occurred. {}: {}".format(type(e).__name__, e)
)
commit = False
finally:
if not commit:
script.log_info(
"Database changes have been reverted automatically."
)
return output
def get_scripts():

View File

@ -404,7 +404,8 @@ class ScriptView(PermissionRequiredMixin, View):
output = None
if form.is_valid():
run_script(script)
commit = form.cleaned_data.pop('_commit')
run_script(script, form.cleaned_data, commit)
return render(request, 'extras/script.html', {
'module': module,

View File

@ -56,7 +56,7 @@
</div>
{% endif %}
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="col-md-6 col-md-offset-3">
{% if not perms.extras.run_script %}
<div class="alert alert-warning">
<i class="fa fa-warning"></i>
@ -82,7 +82,7 @@
<pre>{{ output }}</pre>
</div>
<div role="tabpanel" class="tab-pane" id="source">
<strong>{{ script.filename }}</strong>
<p><code>{{ script.filename }}</code></p>
<pre>{{ script.source }}</pre>
</div>
</div>

View File

@ -0,0 +1,5 @@
class AbortTransaction(Exception):
"""
A dummy exception used to trigger a database transaction rollback.
"""
pass