1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Extended reports API

This commit is contained in:
Jeremy Stretch
2017-09-25 17:27:58 -04:00
parent 88c57d002d
commit d35a2b0faa
4 changed files with 107 additions and 17 deletions

View File

@ -7,7 +7,7 @@ from rest_framework import serializers
from dcim.api.serializers import NestedDeviceSerializer, NestedRackSerializer, NestedSiteSerializer
from dcim.models import Device, Rack, Site
from extras.models import (
ACTION_CHOICES, ExportTemplate, Graph, GRAPH_TYPE_CHOICES, ImageAttachment, TopologyMap, UserAction,
ACTION_CHOICES, ExportTemplate, Graph, GRAPH_TYPE_CHOICES, ImageAttachment, ReportResult, TopologyMap, UserAction,
)
from users.api.serializers import NestedUserSerializer
from utilities.api import ChoiceFieldSerializer, ContentTypeFieldSerializer, ValidatedModelSerializer
@ -127,6 +127,36 @@ class WritableImageAttachmentSerializer(ValidatedModelSerializer):
return data
#
# Reports
#
class ReportResultSerializer(serializers.ModelSerializer):
class Meta:
model = ReportResult
fields = ['created', 'user', 'failed', 'data']
class NestedReportResultSerializer(serializers.ModelSerializer):
class Meta:
model = ReportResult
fields = ['created', 'user', 'failed']
class ReportSerializer(serializers.Serializer):
module = serializers.CharField(max_length=255)
name = serializers.CharField(max_length=255)
description = serializers.CharField(max_length=255, required=False)
test_methods = serializers.ListField(child=serializers.CharField(max_length=255))
result = NestedReportResultSerializer()
class ReportDetailSerializer(ReportSerializer):
result = ReportResultSerializer()
#
# User actions
#

View File

@ -1,17 +1,16 @@
from __future__ import unicode_literals
from collections import OrderedDict
from rest_framework.decorators import detail_route
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet, ViewSet
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponse
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from extras import filters
from extras.models import ExportTemplate, Graph, ImageAttachment, TopologyMap, UserAction
from extras.reports import get_reports
from extras.models import ExportTemplate, Graph, ImageAttachment, ReportResult, TopologyMap, UserAction
from extras.reports import get_report, get_reports
from utilities.api import WritableSerializerMixin
from . import serializers
@ -94,23 +93,76 @@ class ImageAttachmentViewSet(WritableSerializerMixin, ModelViewSet):
class ReportViewSet(ViewSet):
_ignore_model_permissions = True
exclude_from_schema = True
lookup_value_regex = '[^/]+' # Allow dots
def list(self, request):
ret_list = []
# Compile all reports
report_list = []
for module_name, reports in get_reports():
for report_name, report_cls in reports:
report = OrderedDict((
('module', module_name),
('name', report_name),
('description', report_cls.description),
('test_methods', report_cls().test_methods),
))
ret_list.append(report)
data = {
'module': module_name,
'name': report_name,
'description': report_cls.description,
'test_methods': report_cls().test_methods,
'result': None,
}
try:
result = ReportResult.objects.defer('data').get(report='{}.{}'.format(module_name, report_name))
data['result'] = result
except ReportResult.DoesNotExist:
pass
report_list.append(data)
return Response(ret_list)
serializer = serializers.ReportSerializer(report_list, many=True, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, pk):
# Retrieve report by <module>.<report>
if '.' not in pk:
raise Http404
module_name, report_name = pk.split('.', 1)
report_cls = get_report(module_name, report_name)
data = {
'module': module_name,
'name': report_name,
'description': report_cls.description,
'test_methods': report_cls().test_methods,
'result': None,
}
# Attach report result
try:
result = ReportResult.objects.get(report='{}.{}'.format(module_name, report_name))
data['result'] = result
except ReportResult.DoesNotExist:
pass
serializer = serializers.ReportDetailSerializer(data)
return Response(serializer.data)
@detail_route()
def run(self, request, pk):
# Retrieve report by <module>.<report>
if '.' not in pk:
raise Http404
module_name, report_name = pk.split('.', 1)
report_cls = get_report(module_name, report_name)
# Run the report
report = report_cls()
result = report.run()
# Save the ReportResult
ReportResult.objects.filter(report=pk).delete()
ReportResult(report=pk, failed=report.failed, data=result).save()
return Response('Report completed.')
class RecentActivityViewSet(ReadOnlyModelViewSet):

View File

@ -30,15 +30,15 @@ class Command(BaseCommand):
"[{:%H:%M:%S}] Running {}.{}...".format(timezone.now(), module_name, report_name)
)
report = report_cls()
results = report.run()
result = report.run()
# Record the results
ReportResult.objects.filter(report=report_name_full).delete()
ReportResult(report=report_name_full, failed=report.failed, data=results).save()
ReportResult(report=report_name_full, failed=report.failed, data=result).save()
# Report on success/failure
status = self.style.ERROR('FAILED') if report.failed else self.style.SUCCESS('SUCCESS')
for test_name, attrs in results.items():
for test_name, attrs in result.items():
self.stdout.write(
"\t{}: {} success, {} info, {} warning, {} failed".format(
test_name, attrs['success'], attrs['info'], attrs['warning'], attrs['failed']

View File

@ -18,6 +18,14 @@ def is_report(obj):
return False
def get_report(module_name, report_name):
"""
Return a specific report from within a module.
"""
module = importlib.import_module('reports.{}'.format(module_name))
return getattr(module, report_name)
def get_reports():
"""
Compile a list of all reports available across all modules in the reports path. Returns a list of tuples: