Initial work on custom scripts (#3415)

This commit is contained in:
Jeremy Stretch
2019-08-09 12:33:33 -04:00
parent f18c3be745
commit a25a27f31f
11 changed files with 376 additions and 4 deletions

143
netbox/extras/scripts.py Normal file
View File

@@ -0,0 +1,143 @@
from collections import OrderedDict
import inspect
import pkgutil
from django import forms
from django.conf import settings
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
from .forms import ScriptForm
#
# Script variables
#
class ScriptVariable:
form_field = forms.CharField
def __init__(self, label='', description=''):
# Default field attributes
if not hasattr(self, 'field_attrs'):
self.field_attrs = {}
if label:
self.field_attrs['label'] = label
if description:
self.field_attrs['help_text'] = description
def as_field(self):
"""
Render the variable as a Django form field.
"""
return self.form_field(**self.field_attrs)
class StringVar(ScriptVariable):
pass
class IntegerVar(ScriptVariable):
form_field = forms.IntegerField
class BooleanVar(ScriptVariable):
form_field = forms.BooleanField
field_attrs = {
'required': False
}
class ObjectVar(ScriptVariable):
form_field = forms.ModelChoiceField
def __init__(self, queryset, *args, **kwargs):
super().__init__(*args, **kwargs)
self.field_attrs['queryset'] = queryset
class Script:
"""
Custom scripts inherit this object.
"""
def __init__(self):
# Initiate the log
self.log = []
# Grab some info about the script
self.filename = inspect.getfile(self.__class__)
self.source = inspect.getsource(self.__class__)
def __str__(self):
if hasattr(self, 'name'):
return self.name
return self.__class__.__name__
def _get_vars(self):
# TODO: This should preserve var ordering
return inspect.getmembers(self, is_variable)
def run(self, context):
raise NotImplementedError("The script must define a run() method.")
def as_form(self, data=None):
"""
Return a Django form suitable for populating the context data required to run this Script.
"""
vars = self._get_vars()
form = ScriptForm(vars, data)
return form
# Logging
def log_debug(self, message):
self.log.append((LOG_DEFAULT, message))
def log_success(self, message):
self.log.append((LOG_SUCCESS, message))
def log_info(self, message):
self.log.append((LOG_INFO, message))
def log_warning(self, message):
self.log.append((LOG_WARNING, message))
def log_failure(self, message):
self.log.append((LOG_FAILURE, message))
#
# Functions
#
def is_script(obj):
"""
Returns True if the object is a Script.
"""
return obj in Script.__subclasses__()
def is_variable(obj):
"""
Returns True if the object is a ScriptVariable.
"""
return isinstance(obj, ScriptVariable)
def get_scripts():
scripts = OrderedDict()
# Iterate through all modules within the reports path. These are the user-created files in which reports are
# defined.
for importer, module_name, _ in pkgutil.iter_modules([settings.SCRIPTS_ROOT]):
module = importer.find_module(module_name).load_module(module_name)
module_scripts = OrderedDict()
for name, cls in inspect.getmembers(module, is_script):
module_scripts[name] = cls
scripts[module_name] = module_scripts
return scripts