mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-25 01:48:38 -06:00
Add options for script vars; include script output
This commit is contained in:
parent
a25a27f31f
commit
9d054fb345
@ -4,27 +4,37 @@ import pkgutil
|
|||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.validators import RegexValidator
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
class OptionalBooleanField(forms.BooleanField):
|
||||||
|
required = False
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Script variables
|
# Script variables
|
||||||
#
|
#
|
||||||
|
|
||||||
class ScriptVariable:
|
class ScriptVariable:
|
||||||
|
"""
|
||||||
|
Base model for script variables
|
||||||
|
"""
|
||||||
form_field = forms.CharField
|
form_field = forms.CharField
|
||||||
|
|
||||||
def __init__(self, label='', description=''):
|
def __init__(self, label='', description='', default=None, required=True):
|
||||||
|
|
||||||
# Default field attributes
|
# Default field attributes
|
||||||
if not hasattr(self, 'field_attrs'):
|
self.field_attrs = {
|
||||||
self.field_attrs = {}
|
'help_text': description,
|
||||||
|
'required': required
|
||||||
|
}
|
||||||
if label:
|
if label:
|
||||||
self.field_attrs['label'] = label
|
self.field_attrs['label'] = label
|
||||||
if description:
|
if default:
|
||||||
self.field_attrs['help_text'] = description
|
self.field_attrs['initial'] = default
|
||||||
|
|
||||||
def as_field(self):
|
def as_field(self):
|
||||||
"""
|
"""
|
||||||
@ -34,26 +44,62 @@ class ScriptVariable:
|
|||||||
|
|
||||||
|
|
||||||
class StringVar(ScriptVariable):
|
class StringVar(ScriptVariable):
|
||||||
pass
|
"""
|
||||||
|
Character string representation. Can enforce minimum/maximum length and/or regex validation.
|
||||||
|
"""
|
||||||
|
def __init__(self, min_length=None, max_length=None, regex=None, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Optional minimum/maximum lengths
|
||||||
|
if min_length:
|
||||||
|
self.field_attrs['min_length'] = min_length
|
||||||
|
if max_length:
|
||||||
|
self.field_attrs['max_length'] = max_length
|
||||||
|
|
||||||
|
# Optional regular expression validation
|
||||||
|
if regex:
|
||||||
|
self.field_attrs['validators'] = [
|
||||||
|
RegexValidator(
|
||||||
|
regex=regex,
|
||||||
|
message='Invalid value. Must match regex: {}'.format(regex),
|
||||||
|
code='invalid'
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class IntegerVar(ScriptVariable):
|
class IntegerVar(ScriptVariable):
|
||||||
|
"""
|
||||||
|
Integer representation. Can enforce minimum/maximum values.
|
||||||
|
"""
|
||||||
form_field = forms.IntegerField
|
form_field = forms.IntegerField
|
||||||
|
|
||||||
|
def __init__(self, min_value=None, max_value=None, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Optional minimum/maximum values
|
||||||
|
if min_value:
|
||||||
|
self.field_attrs['min_value'] = min_value
|
||||||
|
if max_value:
|
||||||
|
self.field_attrs['max_value'] = max_value
|
||||||
|
|
||||||
|
|
||||||
class BooleanVar(ScriptVariable):
|
class BooleanVar(ScriptVariable):
|
||||||
form_field = forms.BooleanField
|
"""
|
||||||
field_attrs = {
|
Boolean representation (true/false). Renders as a checkbox.
|
||||||
'required': False
|
"""
|
||||||
}
|
form_field = OptionalBooleanField
|
||||||
|
|
||||||
|
|
||||||
class ObjectVar(ScriptVariable):
|
class ObjectVar(ScriptVariable):
|
||||||
|
"""
|
||||||
|
NetBox object representation. The provided QuerySet will determine the choices available.
|
||||||
|
"""
|
||||||
form_field = forms.ModelChoiceField
|
form_field = forms.ModelChoiceField
|
||||||
|
|
||||||
def __init__(self, queryset, *args, **kwargs):
|
def __init__(self, queryset, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Queryset for field choices
|
||||||
self.field_attrs['queryset'] = queryset
|
self.field_attrs['queryset'] = queryset
|
||||||
|
|
||||||
|
|
||||||
@ -61,7 +107,6 @@ class Script:
|
|||||||
"""
|
"""
|
||||||
Custom scripts inherit this object.
|
Custom scripts inherit this object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Initiate the log
|
# Initiate the log
|
||||||
@ -80,7 +125,7 @@ class Script:
|
|||||||
# TODO: This should preserve var ordering
|
# TODO: This should preserve var ordering
|
||||||
return inspect.getmembers(self, is_variable)
|
return inspect.getmembers(self, is_variable)
|
||||||
|
|
||||||
def run(self, context):
|
def run(self, data):
|
||||||
raise NotImplementedError("The script must define a run() method.")
|
raise NotImplementedError("The script must define a run() method.")
|
||||||
|
|
||||||
def as_form(self, data=None):
|
def as_form(self, data=None):
|
||||||
|
@ -396,14 +396,16 @@ class ScriptView(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
script = self._get_script(module, name)
|
script = self._get_script(module, name)
|
||||||
form = script.as_form(request.POST)
|
form = script.as_form(request.POST)
|
||||||
|
output = None
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
script.run(form.cleaned_data)
|
output = script.run(form.cleaned_data)
|
||||||
|
|
||||||
return render(request, 'extras/script.html', {
|
return render(request, 'extras/script.html', {
|
||||||
'module': module,
|
'module': module,
|
||||||
'script': script,
|
'script': script,
|
||||||
'form': form,
|
'form': form,
|
||||||
|
'output': output,
|
||||||
})
|
})
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
<li role="presentation" class="active">
|
<li role="presentation" class="active">
|
||||||
<a href="#run" role="tab" data-toggle="tab" class="active">Run</a>
|
<a href="#run" role="tab" data-toggle="tab" class="active">Run</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li role="presentation"{% if not output %} class="disabled"{% endif %}>
|
||||||
|
<a href="#output" role="tab" data-toggle="tab">Output</a>
|
||||||
|
</li>
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a href="#source" role="tab" data-toggle="tab">Source</a>
|
<a href="#source" role="tab" data-toggle="tab">Source</a>
|
||||||
</li>
|
</li>
|
||||||
@ -69,6 +72,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane" id="output">
|
||||||
|
<pre>{{ output }}</pre>
|
||||||
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="source">
|
<div role="tabpanel" class="tab-pane" id="source">
|
||||||
<strong>{{ script.filename }}</strong>
|
<strong>{{ script.filename }}</strong>
|
||||||
<pre>{{ script.source }}</pre>
|
<pre>{{ script.source }}</pre>
|
||||||
|
Loading…
Reference in New Issue
Block a user