Misc cleanup

This commit is contained in:
jeremystretch 2023-03-24 13:14:02 -04:00
parent b2257b613e
commit 090a28131e
8 changed files with 78 additions and 65 deletions

View File

@ -917,6 +917,10 @@ 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')
@property
def name(self):
return self.file_path
@cached_property @cached_property
def reports(self): def reports(self):
module = self.get_module() module = self.get_module()

View File

@ -3,6 +3,7 @@ import traceback
from datetime import timedelta from datetime import timedelta
from django.utils import timezone from django.utils import timezone
from django.utils.functional import classproperty
from django_rq import job from django_rq import job
from .choices import JobResultStatusChoices, LogLevelChoices from .choices import JobResultStatusChoices, LogLevelChoices
@ -26,7 +27,7 @@ def run_report(job_result, *args, **kwargs):
method for queueing into the background processor. method for queueing into the background processor.
""" """
module_name, report_name = job_result.name.split('.', 1) module_name, report_name = job_result.name.split('.', 1)
report = get_report(module_name, report_name) report = get_report(module_name, report_name)()
try: try:
job_result.start() job_result.start()
@ -83,7 +84,7 @@ class Report(object):
self.active_test = None self.active_test = None
self.failed = False self.failed = False
self.logger = logging.getLogger(f"netbox.reports.{self.full_name}") self.logger = logging.getLogger(f"netbox.reports.{self.__module__}.{self.__class__.__name__}")
# Compile test methods and initialize results skeleton # Compile test methods and initialize results skeleton
test_methods = [] test_methods = []
@ -101,13 +102,17 @@ 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 @classproperty
def module(self): def module(self):
return self.__module__ return self.__module__
@property @classproperty
def class_name(self): def class_name(self):
return self.__class__.__name__ return self.__name__
@classproperty
def full_name(self):
return f'{self.module}.{self.class_name}'
@property @property
def name(self): def name(self):
@ -116,9 +121,9 @@ class Report(object):
""" """
return self.class_name return self.class_name
@property #
def full_name(self): # Logging methods
return f'{self.module}.{self.class_name}' #
def _log(self, obj, message, level=LogLevelChoices.LOG_DEFAULT): def _log(self, obj, message, level=LogLevelChoices.LOG_DEFAULT):
""" """
@ -175,6 +180,10 @@ class Report(object):
self.logger.info(f"Failure | {obj}: {message}") self.logger.info(f"Failure | {obj}: {message}")
self.failed = True self.failed = True
#
# Run methods
#
def run(self, job_result): def run(self, job_result):
""" """
Run the report and save its results. Each test method will be executed in order. Run the report and save its results. Each test method will be executed in order.

View File

@ -267,7 +267,7 @@ class BaseScript:
def __init__(self): def __init__(self):
# Initiate the log # Initiate the log
self.logger = logging.getLogger(f"netbox.scripts.{self.module()}.{self.__class__.__name__}") self.logger = logging.getLogger(f"netbox.scripts.{self.__module__}.{self.__class__.__name__}")
self.log = [] self.log = []
# Declare the placeholder for the current request # Declare the placeholder for the current request
@ -280,22 +280,26 @@ class BaseScript:
def __str__(self): def __str__(self):
return self.name return self.name
@classproperty
def module(self):
return self.__module__
@classproperty
def class_name(self):
return self.__name__
@classproperty
def full_name(self):
return f'{self.module}.{self.class_name}'
@classproperty @classproperty
def name(self): def name(self):
return getattr(self.Meta, 'name', self.__name__) return getattr(self.Meta, 'name', self.__name__)
@classproperty
def full_name(self):
return '.'.join([self.__module__, self.__name__])
@classproperty @classproperty
def description(self): def description(self):
return getattr(self.Meta, 'description', '') return getattr(self.Meta, 'description', '')
@classmethod
def module(cls):
return cls.__module__
@classmethod @classmethod
def root_module(cls): def root_module(cls):
return cls.__module__.split(".")[0] return cls.__module__.split(".")[0]

View File

@ -852,20 +852,17 @@ class ReportView(ContentTypePermissionRequiredMixin, View):
).first() ).first()
return render(request, 'extras/report.html', { return render(request, 'extras/report.html', {
'module': module,
'report': report, 'report': report,
'form': ReportForm(), 'form': ReportForm(),
}) })
def post(self, request, module, name): def post(self, request, module, name):
# Permissions check
if not request.user.has_perm('extras.run_report'): if not request.user.has_perm('extras.run_report'):
return HttpResponseForbidden() return HttpResponseForbidden()
report = get_report(module, name) module = get_object_or_404(ReportModule.objects.restrict(request.user), file_path=f'{module}.py')
if report is None: report = module.reports[name]()
raise Http404
form = ReportForm(request.POST) form = ReportForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -891,6 +888,7 @@ class ReportView(ContentTypePermissionRequiredMixin, View):
return redirect('extras:report_result', job_result_pk=job_result.pk) return redirect('extras:report_result', job_result_pk=job_result.pk)
return render(request, 'extras/report.html', { return render(request, 'extras/report.html', {
'module': module,
'report': report, 'report': report,
'form': form, 'form': form,
}) })

View File

@ -10,7 +10,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'extras:report_list' %}">Reports</a></li> <li class="breadcrumb-item"><a href="{% url 'extras:report_list' %}">Reports</a></li>
<li class="breadcrumb-item"><a href="{% url 'extras:report_list' %}#module.{{ report.module }}">{{ report.module|bettertitle }}</a></li> <li class="breadcrumb-item"><a href="{% url 'extras:report_list' %}#module{{ module.pk }}">{{ report.module|bettertitle }}</a></li>
{% endblock breadcrumbs %} {% endblock breadcrumbs %}
{% block subtitle %} {% block subtitle %}

View File

@ -26,7 +26,7 @@
<div class="tab-content"> <div class="tab-content">
{% for module in report_modules %} {% for module in report_modules %}
<div class="card"> <div class="card">
<h5 class="card-header"> <h5 class="card-header" id="module{{ module.pk }}">
{% if perms.extras.delete_reportmodule %} {% if perms.extras.delete_reportmodule %}
<div class="float-end"> <div class="float-end">
<a href="{% url 'extras:reportmodule_delete' pk=module.pk %}" class="btn btn-danger btn-sm"> <a href="{% url 'extras:reportmodule_delete' pk=module.pk %}" class="btn btn-danger btn-sm">
@ -34,7 +34,6 @@
</a> </a>
</div> </div>
{% endif %} {% endif %}
<a name="module.{{ module.name }}"></a>
<i class="mdi mdi-file-document-outline"></i> {{ module.name|bettertitle }} <i class="mdi mdi-file-document-outline"></i> {{ module.name|bettertitle }}
</h5> </h5>
<div class="card-body"> <div class="card-body">
@ -51,15 +50,15 @@
</thead> </thead>
<tbody> <tbody>
{% for report_name, report in module.reports.items %} {% for report_name, report in module.reports.items %}
<tr> {% with last_result=job_results|get_key:report.full_name %}
<td> <tr>
<a href="{% url 'extras:report' module=report.module name=report.class_name %}" id="{{ report.module }}.{{ report.class_name }}">{{ report.name }}</a> <td>
</td> <a href="{% url 'extras:report' module=report.module name=report.class_name %}" id="{{ report.module }}.{{ report.class_name }}">{{ report.name }}</a>
<td> </td>
{% include 'extras/inc/job_label.html' with result=report.result %} <td>
</td> {% include 'extras/inc/job_label.html' with result=report.result %}
<td>{{ report.description|markdown|placeholder }}</td> </td>
{% with last_result=job_results|get_key:report.full_name %} <td>{{ report.description|markdown|placeholder }}</td>
{% if last_result %} {% if last_result %}
<td> <td>
<a href="{% url 'extras:report_result' job_result_pk=last_result.pk %}">{{ last_result.created|annotated_date }}</a> <a href="{% url 'extras:report_result' job_result_pk=last_result.pk %}">{{ last_result.created|annotated_date }}</a>
@ -87,21 +86,21 @@
</div> </div>
{% endif %} {% endif %}
</td> </td>
{% endwith %}
</tr>
{% for method, stats in report.result.data.items %}
<tr>
<td colspan="4" class="method">
<span class="ps-3">{{ method }}</span>
</td>
<td class="text-end text-nowrap report-stats">
<span class="badge bg-success">{{ stats.success }}</span>
<span class="badge bg-info">{{ stats.info }}</span>
<span class="badge bg-warning">{{ stats.warning }}</span>
<span class="badge bg-danger">{{ stats.failure }}</span>
</td>
</tr> </tr>
{% endfor %} {% for method, stats in last_result.data.items %}
<tr>
<td colspan="4" class="method">
<span class="ps-3">{{ method }}</span>
</td>
<td class="text-end text-nowrap report-stats">
<span class="badge bg-success">{{ stats.success }}</span>
<span class="badge bg-info">{{ stats.info }}</span>
<span class="badge bg-warning">{{ stats.warning }}</span>
<span class="badge bg-danger">{{ stats.failure }}</span>
</td>
</tr>
{% endfor %}
{% endwith %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>

View File

@ -11,7 +11,7 @@
{% block breadcrumbs %} {% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'extras:script_list' %}">Scripts</a></li> <li class="breadcrumb-item"><a href="{% url 'extras:script_list' %}">Scripts</a></li>
<li class="breadcrumb-item"><a href="{% url 'extras:script_list' %}#module.{{ module }}">{{ module|bettertitle }}</a></li> <li class="breadcrumb-item"><a href="{% url 'extras:script_list' %}#module{{ module.pk }}">{{ module|bettertitle }}</a></li>
{% endblock breadcrumbs %} {% endblock breadcrumbs %}
{% block subtitle %} {% block subtitle %}

View File

@ -25,7 +25,7 @@
<div class="tab-content"> <div class="tab-content">
{% for module in script_modules %} {% for module in script_modules %}
<div class="card"> <div class="card">
<h5 class="card-header"> <h5 class="card-header" id="module{{ module.pk }}">
{% if perms.extras.delete_scriptmodule %} {% if perms.extras.delete_scriptmodule %}
<div class="float-end"> <div class="float-end">
<a href="{% url 'extras:scriptmodule_delete' pk=module.pk %}" class="btn btn-danger btn-sm"> <a href="{% url 'extras:scriptmodule_delete' pk=module.pk %}" class="btn btn-danger btn-sm">
@ -33,7 +33,6 @@
</a> </a>
</div> </div>
{% endif %} {% endif %}
<a name="module.{{ module.name }}"></a>
<i class="mdi mdi-file-document-outline"></i> {{ module.name|bettertitle }} <i class="mdi mdi-file-document-outline"></i> {{ module.name|bettertitle }}
</h5> </h5>
<div class="card-body"> <div class="card-body">
@ -49,17 +48,17 @@
</thead> </thead>
<tbody> <tbody>
{% for script_name, script_class in module.scripts.items %} {% for script_name, script_class in module.scripts.items %}
<tr> {% with last_result=job_results|get_key:script_class.full_name %}
<td> <tr>
<a href="{% url 'extras:script' module=script_class.root_module name=script_name %}" name="script.{{ script_name }}">{{ script_class.name }}</a> <td>
</td> <a href="{% url 'extras:script' module=script_class.root_module name=script_name %}" name="script.{{ script_name }}">{{ script_class.name }}</a>
<td> </td>
{% include 'extras/inc/job_label.html' with result=script_class.result %} <td>
</td> {% include 'extras/inc/job_label.html' with result=script_class.result %}
<td> </td>
{{ script_class.Meta.description|markdown|placeholder }} <td>
</td> {{ script_class.Meta.description|markdown|placeholder }}
{% with last_result=job_results|get_key:script_class.full_name %} </td>
{% if last_result %} {% if last_result %}
<td> <td>
<a href="{% url 'extras:script_result' job_result_pk=last_result.pk %}">{{ last_result.created|annotated_date }}</a> <a href="{% url 'extras:script_result' job_result_pk=last_result.pk %}">{{ last_result.created|annotated_date }}</a>
@ -71,8 +70,8 @@
<td class="text-muted">Never</td> <td class="text-muted">Never</td>
<td class="text-end">{{ ''|placeholder }}</td> <td class="text-end">{{ ''|placeholder }}</td>
{% endif %} {% endif %}
{% endwith %} </tr>
</tr> {% endwith %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>