mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Implemented rough UI for accessing report results
This commit is contained in:
@ -32,6 +32,10 @@ class Command(BaseCommand):
|
|||||||
report = report_cls()
|
report = report_cls()
|
||||||
results = report.run()
|
results = report.run()
|
||||||
|
|
||||||
|
# Record the results
|
||||||
|
ReportResult.objects.filter(report=report_name_full).delete()
|
||||||
|
ReportResult(report=report_name_full, failed=report.failed, data=results).save()
|
||||||
|
|
||||||
# Report on success/failure
|
# Report on success/failure
|
||||||
status = self.style.ERROR('FAILED') if report.failed else self.style.SUCCESS('SUCCESS')
|
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 results.items():
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Generated by Django 1.11.4 on 2017-09-21 20:31
|
# Generated by Django 1.11.4 on 2017-09-22 15:21
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -20,8 +20,9 @@ class Migration(migrations.Migration):
|
|||||||
name='ReportResult',
|
name='ReportResult',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('created', models.DateTimeField(auto_created=True)),
|
|
||||||
('report', models.CharField(max_length=255, unique=True)),
|
('report', models.CharField(max_length=255, unique=True)),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('failed', models.BooleanField()),
|
||||||
('data', django.contrib.postgres.fields.jsonb.JSONField()),
|
('data', django.contrib.postgres.fields.jsonb.JSONField()),
|
||||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||||
],
|
],
|
||||||
|
@ -398,8 +398,9 @@ class ReportResult(models.Model):
|
|||||||
This model stores the results from running a user-defined report.
|
This model stores the results from running a user-defined report.
|
||||||
"""
|
"""
|
||||||
report = models.CharField(max_length=255, unique=True)
|
report = models.CharField(max_length=255, unique=True)
|
||||||
created = models.DateTimeField(auto_created=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
user = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='+', blank=True, null=True)
|
user = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='+', blank=True, null=True)
|
||||||
|
failed = models.BooleanField()
|
||||||
data = JSONField()
|
data = JSONField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -20,7 +20,18 @@ def is_report(obj):
|
|||||||
|
|
||||||
def get_reports():
|
def get_reports():
|
||||||
"""
|
"""
|
||||||
Compile a list of all reports available across all modules in the reports path.
|
Compile a list of all reports available across all modules in the reports path. Returns a list of tuples:
|
||||||
|
|
||||||
|
[
|
||||||
|
(module_name, (
|
||||||
|
(report_name, report_class),
|
||||||
|
(report_name, report_class)
|
||||||
|
),
|
||||||
|
(module_name, (
|
||||||
|
(report_name, report_class),
|
||||||
|
(report_name, report_class)
|
||||||
|
)
|
||||||
|
]
|
||||||
"""
|
"""
|
||||||
module_list = []
|
module_list = []
|
||||||
|
|
||||||
@ -30,8 +41,8 @@ def get_reports():
|
|||||||
report_list = []
|
report_list = []
|
||||||
|
|
||||||
# Iterate through all Report classes within the module
|
# Iterate through all Report classes within the module
|
||||||
for report_name, report_cls in inspect.getmembers(module, is_report):
|
for report_name, report_class in inspect.getmembers(module, is_report):
|
||||||
report_list.append((report_name, report_cls))
|
report_list.append((report_name, report_class))
|
||||||
|
|
||||||
module_list.append((module_name, report_list))
|
module_list.append((module_name, report_list))
|
||||||
|
|
||||||
@ -92,7 +103,7 @@ class Report(object):
|
|||||||
"""
|
"""
|
||||||
if level not in LOG_LEVEL_CODES:
|
if level not in LOG_LEVEL_CODES:
|
||||||
raise Exception("Unknown logging level: {}".format(level))
|
raise Exception("Unknown logging level: {}".format(level))
|
||||||
logline = [timezone.now(), level, obj, message]
|
logline = [timezone.now().isoformat(), level, str(obj), message]
|
||||||
self.results[self.active_test]['log'].append(logline)
|
self.results[self.active_test]['log'].append(logline)
|
||||||
|
|
||||||
def log_success(self, obj, message=None):
|
def log_success(self, obj, message=None):
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
|
||||||
@ -52,9 +53,19 @@ class ReportListView(View):
|
|||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
|
||||||
reports = get_reports()
|
reports = get_reports()
|
||||||
results = {r.name: r for r in ReportResult.objects.all()}
|
results = {r.report: r for r in ReportResult.objects.all()}
|
||||||
|
|
||||||
|
foo = []
|
||||||
|
for module, report_list in reports:
|
||||||
|
module_reports = []
|
||||||
|
for report_name, report_class in report_list:
|
||||||
|
module_reports.append({
|
||||||
|
'name': report_name,
|
||||||
|
'description': report_class.description,
|
||||||
|
'results': results.get('{}.{}'.format(module, report_name), None)
|
||||||
|
})
|
||||||
|
foo.append((module, module_reports))
|
||||||
|
|
||||||
return render(request, 'extras/report_list.html', {
|
return render(request, 'extras/report_list.html', {
|
||||||
'reports': reports,
|
'reports': foo,
|
||||||
'results': results,
|
|
||||||
})
|
})
|
||||||
|
@ -5,13 +5,52 @@
|
|||||||
<h1>Reports</h1>
|
<h1>Reports</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
{% for module, report_list in reports %}
|
{% for module, module_reports in reports %}
|
||||||
<h2>{{ module|bettertitle }}</h2>
|
<h3>{{ module|bettertitle }}</h3>
|
||||||
<ul>
|
<table class="table table-hover">
|
||||||
{% for name, cls in report_list %}
|
<thead>
|
||||||
<li>{{ name }}</li>
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Last Run</th>
|
||||||
|
<th class="text-right">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for report in module_reports %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ report.name }}</td>
|
||||||
|
<td>{{ report.description|default:"" }}</td>
|
||||||
|
{% if report.results %}
|
||||||
|
<td>{{ report.results.created }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
{% if report.results.failed %}
|
||||||
|
<label class="label label-danger">Failed</label>
|
||||||
|
{% else %}
|
||||||
|
<label class="label label-success">Passed</label>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% else %}
|
||||||
|
<td class="text-muted">Never</td>
|
||||||
|
<td class="text-muted text-right">—</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% for method, stats in report.results.data.items %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">
|
||||||
|
<div class="pull-right">
|
||||||
|
<label class="label label-success">{{ stats.success }}</label>
|
||||||
|
<label class="label label-info">{{ stats.info }}</label>
|
||||||
|
<label class="label label-warning">{{ stats.warning }}</label>
|
||||||
|
<label class="label label-danger">{{ stats.failed }}</label>
|
||||||
|
</div>
|
||||||
|
<span style="font-family: monospace">{{ method }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user