mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 17:26:10 -06:00
Enable resolving scripts/reports from module class
This commit is contained in:
parent
bfccd6820e
commit
f5830c1cd8
@ -1,5 +1,7 @@
|
|||||||
|
import inspect
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
from functools import cached_property
|
||||||
from pkgutil import ModuleInfo, get_importer
|
from pkgutil import ModuleInfo, get_importer
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -31,6 +33,7 @@ from netbox.models.features import (
|
|||||||
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, SyncedDataMixin,
|
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, SyncedDataMixin,
|
||||||
TagsMixin, WebhooksMixin,
|
TagsMixin, WebhooksMixin,
|
||||||
)
|
)
|
||||||
|
from ..temp import is_report, is_script
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from utilities.querysets import RestrictedQuerySet
|
||||||
from utilities.rqworker import get_queue_for_model
|
from utilities.rqworker import get_queue_for_model
|
||||||
from utilities.utils import render_jinja2
|
from utilities.utils import render_jinja2
|
||||||
@ -827,6 +830,11 @@ class PythonModuleMixin:
|
|||||||
ispkg=False
|
ispkg=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_module(self):
|
||||||
|
importer, module_name, _ = self.get_module_info()
|
||||||
|
module = importer.find_module(module_name).load_module(module_name)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
class Script(JobResultsMixin, WebhooksMixin, models.Model):
|
class Script(JobResultsMixin, WebhooksMixin, models.Model):
|
||||||
"""
|
"""
|
||||||
@ -862,6 +870,18 @@ class ScriptModule(JobResultsMixin, WebhooksMixin, PythonModuleMixin, ManagedFil
|
|||||||
def name(self):
|
def name(self):
|
||||||
return self.file_path
|
return self.file_path
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def scripts(self):
|
||||||
|
module = self.get_module()
|
||||||
|
|
||||||
|
scripts = {}
|
||||||
|
for name, cls in inspect.getmembers(module, is_script):
|
||||||
|
# For child objects in submodules use the full import path w/o the root module as the name
|
||||||
|
child_name = cls.full_name.split(".", maxsplit=1)[1]
|
||||||
|
scripts[child_name] = cls
|
||||||
|
|
||||||
|
return scripts
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Reports
|
# Reports
|
||||||
@ -896,3 +916,15 @@ class ReportModule(JobResultsMixin, WebhooksMixin, PythonModuleMixin, ManagedFil
|
|||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('extras:report_list')
|
return reverse('extras:report_list')
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def reports(self):
|
||||||
|
module = self.get_module()
|
||||||
|
|
||||||
|
reports = {}
|
||||||
|
for name, cls in inspect.getmembers(module, is_report):
|
||||||
|
# For child objects in submodules use the full import path w/o the root module as the name
|
||||||
|
child_name = cls().full_name.split(".", maxsplit=1)[1]
|
||||||
|
reports[child_name] = cls
|
||||||
|
|
||||||
|
return reports
|
||||||
|
@ -7,18 +7,12 @@ from django_rq import job
|
|||||||
|
|
||||||
from .choices import JobResultStatusChoices, LogLevelChoices
|
from .choices import JobResultStatusChoices, LogLevelChoices
|
||||||
from .models import JobResult, ReportModule
|
from .models import JobResult, ReportModule
|
||||||
|
from .temp import is_report
|
||||||
from .utils import get_modules
|
from .utils import get_modules
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def is_report(obj):
|
|
||||||
"""
|
|
||||||
Returns True if the given object is a Report.
|
|
||||||
"""
|
|
||||||
return obj in Report.__subclasses__()
|
|
||||||
|
|
||||||
|
|
||||||
def get_reports():
|
def get_reports():
|
||||||
return get_modules(ReportModule.objects.all(), is_report, 'report_order')
|
return get_modules(ReportModule.objects.all(), is_report, 'report_order')
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ from utilities.exceptions import AbortScript, AbortTransaction
|
|||||||
from utilities.forms import add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
from utilities.forms import add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
||||||
from .context_managers import change_logging
|
from .context_managers import change_logging
|
||||||
from .forms import ScriptForm
|
from .forms import ScriptForm
|
||||||
|
from .temp import is_script
|
||||||
from .utils import get_modules
|
from .utils import get_modules
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -423,15 +424,6 @@ class Script(BaseScript):
|
|||||||
# Functions
|
# Functions
|
||||||
#
|
#
|
||||||
|
|
||||||
def is_script(obj):
|
|
||||||
"""
|
|
||||||
Returns True if the object is a Script.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return issubclass(obj, Script) and obj != Script
|
|
||||||
except TypeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_variable(obj):
|
def is_variable(obj):
|
||||||
"""
|
"""
|
||||||
|
20
netbox/extras/temp.py
Normal file
20
netbox/extras/temp.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
def is_script(obj):
|
||||||
|
"""
|
||||||
|
Returns True if the object is a Script.
|
||||||
|
"""
|
||||||
|
from .scripts import Script
|
||||||
|
try:
|
||||||
|
return issubclass(obj, Script) and obj != Script
|
||||||
|
except TypeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_report(obj):
|
||||||
|
"""
|
||||||
|
Returns True if the given object is a Report.
|
||||||
|
"""
|
||||||
|
from .reports import Report
|
||||||
|
try:
|
||||||
|
return issubclass(obj, Report) and obj != Report
|
||||||
|
except TypeError:
|
||||||
|
return False
|
@ -849,10 +849,8 @@ class ReportView(ContentTypePermissionRequiredMixin, View):
|
|||||||
return 'extras.view_report'
|
return 'extras.view_report'
|
||||||
|
|
||||||
def get(self, request, module, name):
|
def get(self, request, module, name):
|
||||||
|
module = get_object_or_404(ReportModule.objects.restrict(request.user), file_path=f'{module}.py')
|
||||||
report = get_report(module, name)
|
report = module.reports[name]()
|
||||||
if report is None:
|
|
||||||
raise Http404
|
|
||||||
|
|
||||||
report_content_type = ContentType.objects.get(app_label='extras', model='report')
|
report_content_type = ContentType.objects.get(app_label='extras', model='report')
|
||||||
report.result = JobResult.objects.filter(
|
report.result = JobResult.objects.filter(
|
||||||
@ -1001,7 +999,8 @@ class ScriptView(ContentTypePermissionRequiredMixin, GetScriptMixin, View):
|
|||||||
return 'extras.view_script'
|
return 'extras.view_script'
|
||||||
|
|
||||||
def get(self, request, module, name):
|
def get(self, request, module, name):
|
||||||
script = self._get_script(name, module)
|
module = get_object_or_404(ScriptModule.objects.restrict(request.user), file_path=f'{module}.py')
|
||||||
|
script = module.scripts[name]()
|
||||||
form = script.as_form(initial=normalize_querydict(request.GET))
|
form = script.as_form(initial=normalize_querydict(request.GET))
|
||||||
|
|
||||||
# Look for a pending JobResult (use the latest one by creation timestamp)
|
# Look for a pending JobResult (use the latest one by creation timestamp)
|
||||||
|
Loading…
Reference in New Issue
Block a user