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:
@ -387,6 +387,12 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ScriptForm(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):
|
def __init__(self, vars, *args, **kwargs):
|
||||||
|
|
||||||
@ -395,3 +401,6 @@ class ScriptForm(BootstrapMixin, forms.Form):
|
|||||||
# Dynamically populate fields for variables
|
# Dynamically populate fields for variables
|
||||||
for name, var in vars.items():
|
for name, var in vars.items():
|
||||||
self.fields[name] = var.as_field()
|
self.fields[name] = var.as_field()
|
||||||
|
|
||||||
|
# Move _commit to the end of the form
|
||||||
|
self.fields.move_to_end('_commit', True)
|
||||||
|
@ -7,6 +7,7 @@ from django.conf import settings
|
|||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
|
from utilities.exceptions import AbortTransaction
|
||||||
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
|
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
|
||||||
from .forms import ScriptForm
|
from .forms import ScriptForm
|
||||||
|
|
||||||
@ -197,21 +198,32 @@ def is_variable(obj):
|
|||||||
return isinstance(obj, ScriptVariable)
|
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
|
A wrapper for calling Script.run(). This performs error handling and provides a hook for committing changes. It
|
||||||
it cannot be overridden by a script author.
|
exists outside of the Script class to ensure it cannot be overridden by a script author.
|
||||||
"""
|
"""
|
||||||
|
output = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
return script.run(data)
|
output = script.run(data)
|
||||||
|
if not commit:
|
||||||
|
raise AbortTransaction()
|
||||||
|
except AbortTransaction:
|
||||||
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
script.log_failure(
|
script.log_failure(
|
||||||
"An exception occurred: {}".format(e)
|
"An exception occurred. {}: {}".format(type(e).__name__, e)
|
||||||
)
|
|
||||||
script.log_info(
|
|
||||||
"Database changes have been reverted automatically."
|
|
||||||
)
|
)
|
||||||
|
commit = False
|
||||||
|
finally:
|
||||||
|
if not commit:
|
||||||
|
script.log_info(
|
||||||
|
"Database changes have been reverted automatically."
|
||||||
|
)
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
def get_scripts():
|
def get_scripts():
|
||||||
|
@ -404,7 +404,8 @@ class ScriptView(PermissionRequiredMixin, View):
|
|||||||
output = None
|
output = None
|
||||||
|
|
||||||
if form.is_valid():
|
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', {
|
return render(request, 'extras/script.html', {
|
||||||
'module': module,
|
'module': module,
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row">
|
<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 %}
|
{% if not perms.extras.run_script %}
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
<i class="fa fa-warning"></i>
|
<i class="fa fa-warning"></i>
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<pre>{{ output }}</pre>
|
<pre>{{ output }}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="source">
|
<div role="tabpanel" class="tab-pane" id="source">
|
||||||
<strong>{{ script.filename }}</strong>
|
<p><code>{{ script.filename }}</code></p>
|
||||||
<pre>{{ script.source }}</pre>
|
<pre>{{ script.source }}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
5
netbox/utilities/exceptions.py
Normal file
5
netbox/utilities/exceptions.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class AbortTransaction(Exception):
|
||||||
|
"""
|
||||||
|
A dummy exception used to trigger a database transaction rollback.
|
||||||
|
"""
|
||||||
|
pass
|
Reference in New Issue
Block a user