mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 12:12:53 -06:00
Job Scheduling WIP
This commit is contained in:
parent
c8671ce8e8
commit
cbb3378d10
@ -139,6 +139,7 @@ class LogLevelChoices(ChoiceSet):
|
|||||||
class JobResultStatusChoices(ChoiceSet):
|
class JobResultStatusChoices(ChoiceSet):
|
||||||
|
|
||||||
STATUS_PENDING = 'pending'
|
STATUS_PENDING = 'pending'
|
||||||
|
STATUS_SCHEDULED = 'pending'
|
||||||
STATUS_RUNNING = 'running'
|
STATUS_RUNNING = 'running'
|
||||||
STATUS_COMPLETED = 'completed'
|
STATUS_COMPLETED = 'completed'
|
||||||
STATUS_ERRORED = 'errored'
|
STATUS_ERRORED = 'errored'
|
||||||
@ -146,6 +147,7 @@ class JobResultStatusChoices(ChoiceSet):
|
|||||||
|
|
||||||
CHOICES = (
|
CHOICES = (
|
||||||
(STATUS_PENDING, 'Pending'),
|
(STATUS_PENDING, 'Pending'),
|
||||||
|
(STATUS_SCHEDULED, 'Pending'),
|
||||||
(STATUS_RUNNING, 'Running'),
|
(STATUS_RUNNING, 'Running'),
|
||||||
(STATUS_COMPLETED, 'Completed'),
|
(STATUS_COMPLETED, 'Completed'),
|
||||||
(STATUS_ERRORED, 'Errored'),
|
(STATUS_ERRORED, 'Errored'),
|
||||||
|
@ -16,6 +16,7 @@ __all__ = (
|
|||||||
'ConfigContextFilterSet',
|
'ConfigContextFilterSet',
|
||||||
'ContentTypeFilterSet',
|
'ContentTypeFilterSet',
|
||||||
'CustomFieldFilterSet',
|
'CustomFieldFilterSet',
|
||||||
|
'JobResultFilterSet',
|
||||||
'CustomLinkFilterSet',
|
'CustomLinkFilterSet',
|
||||||
'ExportTemplateFilterSet',
|
'ExportTemplateFilterSet',
|
||||||
'ImageAttachmentFilterSet',
|
'ImageAttachmentFilterSet',
|
||||||
@ -86,6 +87,26 @@ class CustomFieldFilterSet(BaseFilterSet):
|
|||||||
Q(description__icontains=value)
|
Q(description__icontains=value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class JobResultFilterSet(BaseFilterSet):
|
||||||
|
q = django_filters.CharFilter(
|
||||||
|
method='search',
|
||||||
|
label='Search',
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Add filters
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = JobResult
|
||||||
|
fields = [
|
||||||
|
'id', 'name', 'obj_type', 'created', 'completed', 'user', 'status'
|
||||||
|
]
|
||||||
|
|
||||||
|
def search(self, queryset, name, value):
|
||||||
|
if not value.strip():
|
||||||
|
return queryset
|
||||||
|
return queryset.filter(
|
||||||
|
Q(name__icontains=value)
|
||||||
|
)
|
||||||
|
|
||||||
class CustomLinkFilterSet(BaseFilterSet):
|
class CustomLinkFilterSet(BaseFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
|
@ -19,6 +19,7 @@ from virtualization.models import Cluster, ClusterGroup, ClusterType
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'ConfigContextFilterForm',
|
'ConfigContextFilterForm',
|
||||||
'CustomFieldFilterForm',
|
'CustomFieldFilterForm',
|
||||||
|
'JobResultFilterForm',
|
||||||
'CustomLinkFilterForm',
|
'CustomLinkFilterForm',
|
||||||
'ExportTemplateFilterForm',
|
'ExportTemplateFilterForm',
|
||||||
'JournalEntryFilterForm',
|
'JournalEntryFilterForm',
|
||||||
@ -65,6 +66,13 @@ class CustomFieldFilterForm(FilterForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class JobResultFilterForm(FilterForm):
|
||||||
|
fieldsets = (
|
||||||
|
(None, ('q',)),
|
||||||
|
#('Attributes', ('type', 'content_type_id', 'group_name', 'weight', 'required', 'ui_visibility')),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomLinkFilterForm(FilterForm):
|
class CustomLinkFilterForm(FilterForm):
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q',)),
|
(None, ('q',)),
|
||||||
|
@ -509,12 +509,18 @@ class JobResult(models.Model):
|
|||||||
unique=True
|
unique=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = RestrictedQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['obj_type', 'name', '-created']
|
ordering = ['obj_type', 'name', '-created']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.job_id)
|
return str(self.job_id)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
# TODO: Fix this to point the right place
|
||||||
|
return reverse('virtualization:clustertype', args=[self.pk])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def duration(self):
|
def duration(self):
|
||||||
if not self.completed:
|
if not self.completed:
|
||||||
@ -546,7 +552,7 @@ class JobResult(models.Model):
|
|||||||
args: additional args passed to the callable
|
args: additional args passed to the callable
|
||||||
kwargs: additional kargs passed to the callable
|
kwargs: additional kargs passed to the callable
|
||||||
"""
|
"""
|
||||||
job_result = cls.objects.create(
|
job_result: JobResult = cls.objects.create(
|
||||||
name=name,
|
name=name,
|
||||||
obj_type=obj_type,
|
obj_type=obj_type,
|
||||||
user=user,
|
user=user,
|
||||||
@ -556,6 +562,9 @@ class JobResult(models.Model):
|
|||||||
queue = django_rq.get_queue("default")
|
queue = django_rq.get_queue("default")
|
||||||
|
|
||||||
if schedule_at := kwargs.pop("schedule_at", None):
|
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)
|
queue.enqueue_at(schedule_at, func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
|
||||||
else:
|
else:
|
||||||
queue.enqueue(func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
|
queue.enqueue(func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
|
||||||
|
@ -8,6 +8,7 @@ from .template_code import *
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'ConfigContextTable',
|
'ConfigContextTable',
|
||||||
'CustomFieldTable',
|
'CustomFieldTable',
|
||||||
|
'JobResultTable',
|
||||||
'CustomLinkTable',
|
'CustomLinkTable',
|
||||||
'ExportTemplateTable',
|
'ExportTemplateTable',
|
||||||
'JournalEntryTable',
|
'JournalEntryTable',
|
||||||
@ -39,6 +40,30 @@ class CustomFieldTable(NetBoxTable):
|
|||||||
default_columns = ('pk', 'name', 'content_types', 'label', 'group_name', 'type', 'required', 'description')
|
default_columns = ('pk', 'name', 'content_types', 'label', 'group_name', 'type', 'required', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Custom fields
|
||||||
|
#
|
||||||
|
|
||||||
|
class JobResultTable(NetBoxTable):
|
||||||
|
name = tables.Column(
|
||||||
|
linkify=True
|
||||||
|
)
|
||||||
|
#obj_type = columns.ContentTypesColumn()
|
||||||
|
required = columns.BooleanColumn()
|
||||||
|
ui_visibility = columns.ChoiceFieldColumn(verbose_name="UI visibility")
|
||||||
|
|
||||||
|
actions = columns.ActionsColumn(
|
||||||
|
actions=() # TODO: Delete
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(NetBoxTable.Meta):
|
||||||
|
model = JobResult
|
||||||
|
fields = (
|
||||||
|
'pk', 'id', 'name', 'obj_type', 'created', 'completed', 'user', 'status', 'job_id',
|
||||||
|
)
|
||||||
|
default_columns = ('pk', 'id', 'name', 'obj_type', 'created', 'completed', 'user', 'status', 'job_id')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Custom links
|
# Custom links
|
||||||
#
|
#
|
||||||
|
@ -103,6 +103,10 @@ urlpatterns = [
|
|||||||
path('reports/results/<int:job_result_pk>/', views.ReportResultView.as_view(), name='report_result'),
|
path('reports/results/<int:job_result_pk>/', views.ReportResultView.as_view(), name='report_result'),
|
||||||
re_path(r'^reports/(?P<module>.([^.]+)).(?P<name>.(.+))/', views.ReportView.as_view(), name='report'),
|
re_path(r'^reports/(?P<module>.([^.]+)).(?P<name>.(.+))/', views.ReportView.as_view(), name='report'),
|
||||||
|
|
||||||
|
# Job results
|
||||||
|
path('job-results/', views.JobResultListView.as_view(), name='jobresult_view'),
|
||||||
|
# path('custom-fields/<int:pk>/', views.CustomFieldView.as_view(), name='customfield'),
|
||||||
|
|
||||||
# Scripts
|
# Scripts
|
||||||
path('scripts/', views.ScriptListView.as_view(), name='script_list'),
|
path('scripts/', views.ScriptListView.as_view(), name='script_list'),
|
||||||
path('scripts/results/<int:job_result_pk>/', views.ScriptResultView.as_view(), name='script_result'),
|
path('scripts/results/<int:job_result_pk>/', views.ScriptResultView.as_view(), name='script_result'),
|
||||||
|
@ -775,3 +775,14 @@ class ScriptResultView(ContentTypePermissionRequiredMixin, GetScriptMixin, View)
|
|||||||
'result': result,
|
'result': result,
|
||||||
'class_name': script.__class__.__name__
|
'class_name': script.__class__.__name__
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Job results
|
||||||
|
#
|
||||||
|
|
||||||
|
class JobResultListView(generic.ObjectListView):
|
||||||
|
queryset = JobResult.objects.all()
|
||||||
|
filterset = filtersets.JobResultFilterSet
|
||||||
|
filterset_form = forms.JobResultFilterForm
|
||||||
|
table = tables.JobResultTable
|
Loading…
Reference in New Issue
Block a user