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

Work on job scheduling:

* Added JobResult form filtersets
* Change housekeeping cleanup delete from `_raw_delete` to `delete` to make sure scheduled tasks are cancelled
* Change default sort of JobResult table to -created
* Added `delete` override to `JobResult` to remove scheduled tasks from RQ when a JobResult is deleted
* Updated js/css dist files. Will need to be redone when develop is merged to feature.
This commit is contained in:
kkthxbye-code
2022-10-09 21:05:31 +02:00
parent 53c8a48244
commit 679a9e839b
14 changed files with 94 additions and 106 deletions

View File

@ -141,7 +141,7 @@ class LogLevelChoices(ChoiceSet):
class JobResultStatusChoices(ChoiceSet):
STATUS_PENDING = 'pending'
STATUS_SCHEDULED = 'pending'
STATUS_SCHEDULED = 'scheduled'
STATUS_RUNNING = 'running'
STATUS_COMPLETED = 'completed'
STATUS_ERRORED = 'errored'
@ -149,7 +149,7 @@ class JobResultStatusChoices(ChoiceSet):
CHOICES = (
(STATUS_PENDING, 'Pending'),
(STATUS_SCHEDULED, 'Pending'),
(STATUS_SCHEDULED, 'Scheduled'),
(STATUS_RUNNING, 'Running'),
(STATUS_COMPLETED, 'Completed'),
(STATUS_ERRORED, 'Errored'),

View File

@ -87,6 +87,7 @@ class CustomFieldFilterSet(BaseFilterSet):
Q(description__icontains=value)
)
class CustomLinkFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
@ -434,8 +435,8 @@ class JobResultFilterSet(BaseFilterSet):
method='search',
label='Search',
)
created = django_filters.DateTimeFilter()
completed = django_filters.DateTimeFilter()
created = django_filters.DateTimeFromToRangeFilter()
completed = django_filters.DateTimeFromToRangeFilter()
status = django_filters.MultipleChoiceFilter(
choices=JobResultStatusChoices,
null_value=None

View File

@ -69,7 +69,43 @@ class CustomFieldFilterForm(FilterForm):
class JobResultFilterForm(FilterForm):
fieldsets = (
(None, ('q',)),
#('Attributes', ('type', 'content_type_id', 'group_name', 'weight', 'required', 'ui_visibility')),
('Attributes', ('obj_type', 'status')),
('Creation', ('created_before', 'created_after', 'completed_before', 'completed_after', 'user')),
)
obj_type = ContentTypeChoiceField(
label=_('Object Type'),
queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('job_results'), # TODO: This doesn't actually work
required=False,
)
status = MultipleChoiceField(
choices=JobResultStatusChoices,
required=False
)
created_after = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
created_before = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
completed_after = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
completed_before = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
user = DynamicModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
label=_('User'),
widget=APISelectMultiple(
api_url='/api/users/users/',
)
)

View File

@ -13,4 +13,4 @@ class ReportForm(BootstrapMixin, forms.Form):
widget=DateTimePicker(),
label="Schedule at",
help_text="Schedule execution of report to a set time",
)
)

View File

@ -81,7 +81,7 @@ class Command(BaseCommand):
ending=""
)
self.stdout.flush()
JobResult.objects.filter(created__lt=cutoff)._raw_delete(using=DEFAULT_DB_ALIAS)
JobResult.objects.filter(created__lt=cutoff).delete(using=DEFAULT_DB_ALIAS)
if options['verbosity']:
self.stdout.write("Done.", self.style.SUCCESS)
elif options['verbosity']:

View File

@ -0,0 +1,17 @@
# Generated by Django 4.1.1 on 2022-10-09 18:37
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('extras', '0078_unique_constraints'),
]
operations = [
migrations.AlterModelOptions(
name='jobresult',
options={'ordering': ['-created']},
),
]

View File

@ -528,13 +528,22 @@ class JobResult(models.Model):
objects = RestrictedQuerySet.as_manager()
class Meta:
ordering = ['obj_type', 'name', '-created']
ordering = ['-created']
def __str__(self):
return str(self.job_id)
def delete(self, *args, **kwargs):
queue = django_rq.get_queue("default")
job = queue.fetch_job(str(self.job_id))
if job:
job.cancel()
return super().delete(*args, **kwargs)
def get_absolute_url(self):
return reverse('extras:jobresult', args=[self.pk])
return reverse(f'extras:{self.obj_type.name}_result', args=[self.pk])
@property
def duration(self):
@ -579,7 +588,7 @@ class JobResult(models.Model):
if schedule_at := kwargs.pop("schedule_at", None):
job_result.status = JobResultStatusChoices.STATUS_SCHEDULED
job_result.save()
queue.enqueue_at(schedule_at, func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
else:
queue.enqueue(func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)

View File

@ -56,9 +56,9 @@ class JobResultTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = JobResult
fields = (
'pk', 'id', 'name', 'obj_type', 'created', 'completed', 'user', 'status', 'job_id',
'pk', 'id', 'name', 'obj_type', 'job_id', 'created', 'completed', 'user', 'status',
)
default_columns = ('pk', 'id', 'name', 'obj_type', 'created', 'completed', 'user', 'status', 'job_id')
default_columns = ('pk', 'id', 'name', 'obj_type', 'status', 'created', 'completed', 'user',)
#

View File

@ -76,7 +76,6 @@ urlpatterns = [
# Job results
path('job-results/', views.JobResultListView.as_view(), name='jobresult_list'),
path('job-results/<int:pk>/', views.JobResultView.as_view(), name='jobresult'),
path('job-results/delete/', views.JobResultBulkDeleteView.as_view(), name='jobresult_bulk_delete'),
path('job-results/<int:pk>/delete/', views.JobResultDeleteView.as_view(), name='jobresult_delete'),

View File

@ -815,6 +815,7 @@ class JobResultListView(generic.ObjectListView):
table = tables.JobResultTable
actions = ('delete', 'bulk_delete', )
class JobResultDeleteView(generic.ObjectDeleteView):
queryset = JobResult.objects.all()
@ -822,4 +823,4 @@ class JobResultDeleteView(generic.ObjectDeleteView):
class JobResultBulkDeleteView(generic.BulkDeleteView):
queryset = JobResult.objects.all()
filterset = filtersets.JobResultFilterSet
table = tables.JobResultTable
table = tables.JobResultTable

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,60 +0,0 @@
{% extends 'generic/object.html' %}
{% load helpers %}
{% load plugins %}
{% block title %}{{ object.name }} ({{object.job_id}}){% endblock %}
{# JobResult does not support add/edit controls #}
{% block controls %}{% endblock %}
{% block subtitle %}{% endblock %}
{% block content %}
<div class="row">
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">
Tag
</h5>
<div class="card-body">
<table class="table table-hover panel-body attr-table">
<tr>
<th scope="row">Name</th>
<td>
{{ object.name }}
</td>
</tr>
<tr>
<th scope="row">Created</th>
<td>
{{ object.created|annotated_date }}
</td>
</tr>
<tr>
<th scope="row">Completed</th>
<td>
{{ object.completed|annotated_date }}
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">
TODO
</h5>
<div class="card-body">
<table class="table table-hover panel-body attr-table">
TODO
</table>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col col-md-12">
{% plugin_full_width_page object %}
</div>
</div>
{% endblock %}