mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-19 11:52:22 -06:00
12510 Merge Scripts and Reports (#14976)
* 12510 move reports to use BaseScript * 12510 merge report into script view * 12510 add migration for job report to script * 12510 update templates * 12510 remove reports * 12510 cleanup * 12510 legacy jobs * 12510 legacy jobs * 12510 fixes * 12510 review changes * 12510 review changes * 12510 update docs * 12510 review changes * 12510 review changes * 12510 review changes * 12510 review changes * 12510 main log results to empty string * 12510 move migration * Introduce an internal log level for debug to simplify Script logging * Misc cleanup * Remove obsolete is_valid() method * Reformat script job data (log, output, tests) * Remove ScriptLogMessageSerializer * Fix formatting of script logs * Record a timestamp with script logs * Rename _current_method to _current_test * Clean up template * Remove obsolete runreport management command * Misc cleanup & refactoring * Clean up template * Clean up migration * Clean up docs --------- Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
@@ -16,7 +16,6 @@ from core.choices import JobStatusChoices
|
||||
from core.models import Job
|
||||
from extras import filtersets
|
||||
from extras.models import *
|
||||
from extras.reports import get_module_and_report, run_report
|
||||
from extras.scripts import get_module_and_script, run_script
|
||||
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
|
||||
from netbox.api.features import SyncedDataMixin
|
||||
@@ -211,111 +210,6 @@ class ConfigTemplateViewSet(SyncedDataMixin, ConfigTemplateRenderMixin, NetBoxMo
|
||||
return self.render_configtemplate(request, configtemplate, context)
|
||||
|
||||
|
||||
#
|
||||
# Reports
|
||||
#
|
||||
|
||||
class ReportViewSet(ViewSet):
|
||||
permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
||||
_ignore_model_permissions = True
|
||||
schema = None
|
||||
lookup_value_regex = '[^/]+' # Allow dots
|
||||
|
||||
def _get_report(self, pk):
|
||||
try:
|
||||
module_name, report_name = pk.split('.', maxsplit=1)
|
||||
except ValueError:
|
||||
raise Http404
|
||||
|
||||
module, report = get_module_and_report(module_name, report_name)
|
||||
if report is None:
|
||||
raise Http404
|
||||
|
||||
return module, report
|
||||
|
||||
def list(self, request):
|
||||
"""
|
||||
Compile all reports and their related results (if any). Result data is deferred in the list view.
|
||||
"""
|
||||
results = {
|
||||
job.name: job
|
||||
for job in Job.objects.filter(
|
||||
object_type=ContentType.objects.get(app_label='extras', model='reportmodule'),
|
||||
status__in=JobStatusChoices.TERMINAL_STATE_CHOICES
|
||||
).order_by('name', '-created').distinct('name').defer('data')
|
||||
}
|
||||
|
||||
report_list = []
|
||||
for report_module in ReportModule.objects.restrict(request.user):
|
||||
report_list.extend([report() for report in report_module.reports.values()])
|
||||
|
||||
# Attach Job objects to each report (if any)
|
||||
for report in report_list:
|
||||
report.result = results.get(report.name, None)
|
||||
|
||||
serializer = serializers.ReportSerializer(report_list, many=True, context={
|
||||
'request': request,
|
||||
})
|
||||
|
||||
return Response({'count': len(report_list), 'results': serializer.data})
|
||||
|
||||
def retrieve(self, request, pk):
|
||||
"""
|
||||
Retrieve a single Report identified as "<module>.<report>".
|
||||
"""
|
||||
module, report = self._get_report(pk)
|
||||
|
||||
# Retrieve the Report and Job, if any.
|
||||
object_type = ContentType.objects.get(app_label='extras', model='reportmodule')
|
||||
report.result = Job.objects.filter(
|
||||
object_type=object_type,
|
||||
name=report.name,
|
||||
status__in=JobStatusChoices.TERMINAL_STATE_CHOICES
|
||||
).first()
|
||||
|
||||
serializer = serializers.ReportDetailSerializer(report, context={
|
||||
'request': request
|
||||
})
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def run(self, request, pk):
|
||||
"""
|
||||
Run a Report identified as "<module>.<script>" and return the pending Job as the result
|
||||
"""
|
||||
# Check that the user has permission to run reports.
|
||||
if not request.user.has_perm('extras.run_report'):
|
||||
raise PermissionDenied("This user does not have permission to run reports.")
|
||||
|
||||
# Check that at least one RQ worker is running
|
||||
if not Worker.count(get_connection('default')):
|
||||
raise RQWorkerNotRunningException()
|
||||
|
||||
# Retrieve and run the Report. This will create a new Job.
|
||||
module, report_cls = self._get_report(pk)
|
||||
report = report_cls
|
||||
input_serializer = serializers.ReportInputSerializer(
|
||||
data=request.data,
|
||||
context={'report': report}
|
||||
)
|
||||
|
||||
if input_serializer.is_valid():
|
||||
report.result = Job.enqueue(
|
||||
run_report,
|
||||
instance=module,
|
||||
name=report.class_name,
|
||||
user=request.user,
|
||||
job_timeout=report.job_timeout,
|
||||
schedule_at=input_serializer.validated_data.get('schedule_at'),
|
||||
interval=input_serializer.validated_data.get('interval')
|
||||
)
|
||||
serializer = serializers.ReportDetailSerializer(report, context={'request': request})
|
||||
|
||||
return Response(serializer.data)
|
||||
return Response(input_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
#
|
||||
# Scripts
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user