Skip to content

Commit

Permalink
Rename JobResult to Job and move to core
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremystretch committed Mar 27, 2023
1 parent 669cfe8 commit 40572b5
Show file tree
Hide file tree
Showing 41 changed files with 650 additions and 361 deletions.
2 changes: 1 addition & 1 deletion docs/development/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Depending on its classification, each NetBox model may support various features
| [Custom links](../customization/custom-links.md) | `CustomLinksMixin` | `custom_links` | These models support the assignment of custom links |
| [Custom validation](../customization/custom-validation.md) | `CustomValidationMixin` | - | Supports the enforcement of custom validation rules |
| [Export templates](../customization/export-templates.md) | `ExportTemplatesMixin` | `export_templates` | Users can create custom export templates for these models |
| [Job results](../features/background-jobs.md) | `JobResultsMixin` | `job_results` | Users can create custom export templates for these models |
| [Job results](../features/background-jobs.md) | `JobsMixin` | `jobs` | Users can create custom export templates for these models |
| [Journaling](../features/journaling.md) | `JournalingMixin` | `journaling` | These models support persistent historical commentary |
| [Synchronized data](../integrations/synchronized-data.md) | `SyncedDataMixin` | `synced_data` | Certain model data can be automatically synchronized from a remote data source |
| [Tagging](../models/extras/tag.md) | `TagsMixin` | `tags` | The models can be tagged with user-defined tags |
Expand Down
2 changes: 1 addition & 1 deletion docs/features/background-jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ NetBox includes the ability to execute certain functions as background tasks. Th
* [Custom script](../customization/custom-scripts.md) execution
* Synchronization of [remote data sources](../integrations/synchronized-data.md)

Additionally, NetBox plugins can enqueue their own background tasks. This is accomplished using the [JobResult model](../models/extras/jobresult.md). Background tasks are executed by the `rqworker` process(es).
Additionally, NetBox plugins can enqueue their own background tasks. This is accomplished using the [Job model](../models/core/job.md). Background tasks are executed by the `rqworker` process(es).

## Scheduled Jobs

Expand Down
4 changes: 2 additions & 2 deletions docs/models/extras/jobresult.md → docs/models/core/job.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Job Results
# Jobs

The JobResult model is used to schedule and record the execution of [background tasks](../../features/background-jobs.md).
The Job model is used to schedule and record the execution of [background tasks](../../features/background-jobs.md).

## Fields

Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ nav:
- Core:
- DataFile: 'models/core/datafile.md'
- DataSource: 'models/core/datasource.md'
- Job: 'models/core/job.md'
- DCIM:
- Cable: 'models/dcim/cable.md'
- ConsolePort: 'models/dcim/consoleport.md'
Expand Down Expand Up @@ -208,7 +209,6 @@ nav:
- CustomLink: 'models/extras/customlink.md'
- ExportTemplate: 'models/extras/exporttemplate.md'
- ImageAttachment: 'models/extras/imageattachment.md'
- JobResult: 'models/extras/jobresult.md'
- JournalEntry: 'models/extras/journalentry.md'
- SavedFilter: 'models/extras/savedfilter.md'
- StagedChange: 'models/extras/stagedchange.md'
Expand Down
20 changes: 18 additions & 2 deletions netbox/core/api/nested_serializers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from rest_framework import serializers

from core.choices import JobStatusChoices
from core.models import *
from netbox.api.fields import ChoiceField
from netbox.api.serializers import WritableNestedSerializer
from users.api.nested_serializers import NestedUserSerializer

__all__ = [
__all__ = (
'NestedDataFileSerializer',
'NestedDataSourceSerializer',
]
'NestedJobSerializer',
)


class NestedDataSourceSerializer(WritableNestedSerializer):
Expand All @@ -23,3 +27,15 @@ class NestedDataFileSerializer(WritableNestedSerializer):
class Meta:
model = DataFile
fields = ['id', 'url', 'display', 'path']


class NestedJobSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
status = ChoiceField(choices=JobStatusChoices)
user = NestedUserSerializer(
read_only=True
)

class Meta:
model = Job
fields = ['url', 'created', 'completed', 'user', 'status']
25 changes: 23 additions & 2 deletions netbox/core/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

from core.choices import *
from core.models import *
from netbox.api.fields import ChoiceField
from netbox.api.serializers import NetBoxModelSerializer
from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer
from users.api.nested_serializers import NestedUserSerializer
from .nested_serializers import *

__all__ = (
'DataFileSerializer',
'DataSourceSerializer',
'JobSerializer',
)


Expand Down Expand Up @@ -49,3 +52,21 @@ class Meta:
fields = [
'id', 'url', 'display', 'source', 'path', 'last_updated', 'size', 'hash',
]


class JobSerializer(BaseModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
user = NestedUserSerializer(
read_only=True
)
status = ChoiceField(choices=JobStatusChoices, read_only=True)
object_type = ContentTypeField(
read_only=True
)

class Meta:
model = Job
fields = [
'id', 'url', 'display', 'status', 'created', 'scheduled', 'interval', 'started', 'completed', 'name',
'object_type', 'user', 'data', 'job_id',
]
3 changes: 3 additions & 0 deletions netbox/core/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
router.register('data-sources', views.DataSourceViewSet)
router.register('data-files', views.DataFileViewSet)

# Jobs
router.register('job-results', views.JobViewSet)

app_name = 'core-api'
urlpatterns = router.urls
14 changes: 10 additions & 4 deletions netbox/core/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
from rest_framework.routers import APIRootView
from rest_framework.viewsets import ReadOnlyModelViewSet

from core import filtersets
from core.models import *
Expand All @@ -20,10 +21,6 @@ def get_view_name(self):
return 'Core'


#
# Data sources
#

class DataSourceViewSet(NetBoxModelViewSet):
queryset = DataSource.objects.annotate(
file_count=count_related(DataFile, 'source')
Expand All @@ -50,3 +47,12 @@ class DataFileViewSet(NetBoxReadOnlyModelViewSet):
queryset = DataFile.objects.defer('data').prefetch_related('source')
serializer_class = serializers.DataFileSerializer
filterset_class = filtersets.DataFileFilterSet


class JobViewSet(ReadOnlyModelViewSet):
"""
Retrieve a list of job results
"""
queryset = Job.objects.prefetch_related('user')
serializer_class = serializers.JobSerializer
filterset_class = filtersets.JobFilterSet
29 changes: 29 additions & 0 deletions netbox/core/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,32 @@ class ManagedFileRootPathChoices(ChoiceSet):
(SCRIPTS, _('Scripts')),
(REPORTS, _('Reports')),
)


#
# Jobs
#

class JobStatusChoices(ChoiceSet):

STATUS_PENDING = 'pending'
STATUS_SCHEDULED = 'scheduled'
STATUS_RUNNING = 'running'
STATUS_COMPLETED = 'completed'
STATUS_ERRORED = 'errored'
STATUS_FAILED = 'failed'

CHOICES = (
(STATUS_PENDING, 'Pending', 'cyan'),
(STATUS_SCHEDULED, 'Scheduled', 'gray'),
(STATUS_RUNNING, 'Running', 'blue'),
(STATUS_COMPLETED, 'Completed', 'green'),
(STATUS_ERRORED, 'Errored', 'red'),
(STATUS_FAILED, 'Failed', 'red'),
)

TERMINAL_STATE_CHOICES = (
STATUS_COMPLETED,
STATUS_ERRORED,
STATUS_FAILED,
)
62 changes: 61 additions & 1 deletion netbox/core/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

import django_filters

from netbox.filtersets import ChangeLoggedModelFilterSet, NetBoxModelFilterSet
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet
from .choices import *
from .models import *

__all__ = (
'DataFileFilterSet',
'DataSourceFilterSet',
'JobFilterSet',
)


Expand Down Expand Up @@ -62,3 +63,62 @@ def search(self, queryset, name, value):
return queryset.filter(
Q(path__icontains=value)
)


class JobFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
)
created = django_filters.DateTimeFilter()
created__before = django_filters.DateTimeFilter(
field_name='created',
lookup_expr='lte'
)
created__after = django_filters.DateTimeFilter(
field_name='created',
lookup_expr='gte'
)
scheduled = django_filters.DateTimeFilter()
scheduled__before = django_filters.DateTimeFilter(
field_name='scheduled',
lookup_expr='lte'
)
scheduled__after = django_filters.DateTimeFilter(
field_name='scheduled',
lookup_expr='gte'
)
started = django_filters.DateTimeFilter()
started__before = django_filters.DateTimeFilter(
field_name='started',
lookup_expr='lte'
)
started__after = django_filters.DateTimeFilter(
field_name='started',
lookup_expr='gte'
)
completed = django_filters.DateTimeFilter()
completed__before = django_filters.DateTimeFilter(
field_name='completed',
lookup_expr='lte'
)
completed__after = django_filters.DateTimeFilter(
field_name='completed',
lookup_expr='gte'
)
status = django_filters.MultipleChoiceFilter(
choices=JobStatusChoices,
null_value=None
)

class Meta:
model = Job
fields = ('id', 'interval', 'status', 'user', 'object_type', 'name')

def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(user__username__icontains=value) |
Q(name__icontains=value)
)
70 changes: 69 additions & 1 deletion netbox/core/forms/filtersets.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
from django import forms
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _

from core.choices import *
from core.models import *
from extras.forms.mixins import SavedFiltersMixin
from extras.utils import FeatureQuery
from netbox.forms import NetBoxModelFilterSetForm
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, DynamicModelMultipleChoiceField
from utilities.forms import (
APISelectMultiple, BOOLEAN_WITH_BLANK_CHOICES, ContentTypeChoiceField, DateTimePicker,
DynamicModelMultipleChoiceField, FilterForm,
)

__all__ = (
'DataFileFilterForm',
'DataSourceFilterForm',
'JobFilterForm',
)


Expand Down Expand Up @@ -45,3 +53,63 @@ class DataFileFilterForm(NetBoxModelFilterSetForm):
required=False,
label=_('Data source')
)


class JobFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = (
(None, ('q', 'filter_id')),
('Attributes', ('object_type', 'status')),
('Creation', (
'created__before', 'created__after', 'scheduled__before', 'scheduled__after', 'started__before',
'started__after', 'completed__before', 'completed__after', 'user',
)),
)
object_type = ContentTypeChoiceField(
label=_('Object Type'),
queryset=ContentType.objects.filter(FeatureQuery('jobs').get_query()),
required=False,
)
status = forms.MultipleChoiceField(
choices=JobStatusChoices,
required=False
)
created__after = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
created__before = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
scheduled__after = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
scheduled__before = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
started__after = forms.DateTimeField(
required=False,
widget=DateTimePicker()
)
started__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/',
)
)
4 changes: 2 additions & 2 deletions netbox/core/jobs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging

from extras.choices import JobResultStatusChoices
from .choices import JobStatusChoices
from netbox.search.backends import search_backend
from .choices import *
from .exceptions import SyncError
Expand All @@ -25,6 +25,6 @@ def sync_datasource(job_result, *args, **kwargs):
job_result.terminate()

except SyncError as e:
job_result.terminate(status=JobResultStatusChoices.STATUS_ERRORED)
job_result.terminate(status=JobStatusChoices.STATUS_ERRORED)
DataSource.objects.filter(pk=datasource.pk).update(status=DataSourceStatusChoices.FAILED)
logging.error(e)
Loading

0 comments on commit 40572b5

Please sign in to comment.