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

Cleaned up the API quite a bit

This commit is contained in:
Jeremy Stretch
2017-09-26 16:36:43 -04:00
parent d35a2b0faa
commit 3395b51086
3 changed files with 70 additions and 71 deletions

View File

@ -95,74 +95,69 @@ class ReportViewSet(ViewSet):
exclude_from_schema = True exclude_from_schema = True
lookup_value_regex = '[^/]+' # Allow dots lookup_value_regex = '[^/]+' # Allow dots
def _retrieve_report(self, pk):
# Read the PK as "<module>.<report>"
if '.' not in pk:
raise Http404
module_name, report_name = pk.split('.', 1)
# Raise a 404 on an invalid Report module/name
report = get_report(module_name, report_name)
if report is None:
raise Http404
return report
def list(self, request): def list(self, request):
"""
# Compile all reports Compile all reports and their related results (if any). Result data is deferred in the list view.
"""
report_list = [] report_list = []
for module_name, reports in get_reports():
for report_name, report_cls in reports:
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)
serializer = serializers.ReportSerializer(report_list, many=True, context={'request': request}) # Iterate through all available Reports.
for module_name, reports in get_reports():
for report in reports:
# Attach the relevant ReportResult (if any) to each Report.
report.result = ReportResult.objects.filter(report=report.full_name).defer('data').first()
report_list.append(report)
serializer = serializers.ReportSerializer(report_list, many=True)
return Response(serializer.data) return Response(serializer.data)
def retrieve(self, request, pk): def retrieve(self, request, pk):
"""
Retrieve a single Report identified as "<module>.<report>".
"""
# Retrieve report by <module>.<report> # Retrieve the Report and ReportResult, if any.
if '.' not in pk: report = self._retrieve_report(pk)
raise Http404 report.result = ReportResult.objects.filter(report=report.full_name).first()
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 serializer = serializers.ReportDetailSerializer(report)
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) return Response(serializer.data)
@detail_route() @detail_route()
def run(self, request, pk): def run(self, request, pk):
"""
Run a Report and create a new ReportResult, overwriting any previous result for the Report.
"""
# Retrieve report by <module>.<report> # Retrieve and run the Report.
if '.' not in pk: report = self._retrieve_report(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() result = report.run()
# Save the ReportResult # Delete the old ReportResult (if any) and save the new one.
ReportResult.objects.filter(report=pk).delete() ReportResult.objects.filter(report=pk).delete()
ReportResult(report=pk, failed=report.failed, data=result).save() report.result = ReportResult(report=pk, failed=report.failed, data=result)
report.result.save()
return Response('Report completed.') serializer = serializers.ReportDetailSerializer(report)
return Response(serializer.data)
class RecentActivityViewSet(ReadOnlyModelViewSet): class RecentActivityViewSet(ReadOnlyModelViewSet):

View File

@ -6,7 +6,7 @@ import pkgutil
from django.utils import timezone from django.utils import timezone
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_LEVEL_CODES, LOG_SUCCESS, LOG_WARNING from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_LEVEL_CODES, LOG_SUCCESS, LOG_WARNING
import reports as user_reports import reports as custom_reports
def is_report(obj): def is_report(obj):
@ -23,7 +23,8 @@ def get_report(module_name, report_name):
Return a specific report from within a module. Return a specific report from within a module.
""" """
module = importlib.import_module('reports.{}'.format(module_name)) module = importlib.import_module('reports.{}'.format(module_name))
return getattr(module, report_name) report = getattr(module, report_name, None)
return report()
def get_reports(): def get_reports():
@ -31,27 +32,18 @@ def get_reports():
Compile a list of all reports available across all modules in the reports path. Returns a list of tuples: Compile a list of all reports available across all modules in the reports path. Returns a list of tuples:
[ [
(module_name, ( (module_name, (report_class, report_class, report_class, ...)),
(report_name, report_class), (module_name, (report_class, report_class, report_class, ...)),
(report_name, report_class) ...
),
(module_name, (
(report_name, report_class),
(report_name, report_class)
)
] ]
""" """
module_list = [] module_list = []
# Iterate through all modules within the reports path # Iterate through all modules within the reports path. These are the user-defined files in which reports are
for importer, module_name, is_pkg in pkgutil.walk_packages(user_reports.__path__): # defined.
for importer, module_name, is_pkg in pkgutil.walk_packages(custom_reports.__path__):
module = importlib.import_module('reports.{}'.format(module_name)) module = importlib.import_module('reports.{}'.format(module_name))
report_list = [] report_list = [cls() for _, cls in inspect.getmembers(module, is_report)]
# Iterate through all Report classes within the module
for report_name, report_class in inspect.getmembers(module, is_report):
report_list.append((report_name, report_class))
module_list.append((module_name, report_list)) module_list.append((module_name, report_list))
return module_list return module_list
@ -105,6 +97,18 @@ class Report(object):
raise Exception("A report must contain at least one test method.") raise Exception("A report must contain at least one test method.")
self.test_methods = test_methods self.test_methods = test_methods
@property
def module(self):
return self.__module__.rsplit('.', 1)[1]
@property
def name(self):
return self.__class__.__name__
@property
def full_name(self):
return '.'.join([self.module, self.name])
def _log(self, obj, message, level=LOG_DEFAULT): def _log(self, obj, message, level=LOG_DEFAULT):
""" """
Log a message from a test method. Do not call this method directly; use one of the log_* wrappers below. Log a message from a test method. Do not call this method directly; use one of the log_* wrappers below.

View File

@ -58,11 +58,11 @@ class ReportListView(View):
foo = [] foo = []
for module, report_list in reports: for module, report_list in reports:
module_reports = [] module_reports = []
for report_name, report_class in report_list: for report in report_list:
module_reports.append({ module_reports.append({
'name': report_name, 'name': report.name,
'description': report_class.description, 'description': report.description,
'results': results.get('{}.{}'.format(module, report_name), None) 'results': results.get(report.full_name, None)
}) })
foo.append((module, module_reports)) foo.append((module, module_reports))