From 0bcc59a1e99065c1c0a143983fed4d0828d744f4 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 15 Nov 2022 14:38:58 -0500 Subject: [PATCH] #8366: Add started field to JobResult --- docs/release-notes/version-3.4.md | 2 +- netbox/extras/api/serializers.py | 4 +-- netbox/extras/filtersets.py | 31 ++++++++++++------- netbox/extras/forms/filtersets.py | 29 ++++++++++------- ...lt_scheduled.py => 0079_scheduled_jobs.py} | 5 +++ .../0080_customlink_content_types.py | 2 +- netbox/extras/models/models.py | 15 ++++++++- netbox/extras/reports.py | 1 + netbox/extras/scripts.py | 8 ++--- netbox/extras/tables/tables.py | 6 ++-- netbox/extras/views.py | 4 +-- .../templates/extras/htmx/report_result.html | 9 ++++-- .../templates/extras/htmx/script_result.html | 9 ++++-- netbox/templates/extras/report_result.html | 2 +- netbox/templates/extras/script_result.html | 2 +- 15 files changed, 84 insertions(+), 45 deletions(-) rename netbox/extras/migrations/{0079_jobresult_scheduled.py => 0079_scheduled_jobs.py} (74%) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index 36ed48a6a..caa39fc2a 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -131,7 +131,7 @@ This release introduces a new programmatic API that enables plugins and custom s * extras.ExportTemplate * Renamed `content_type` field to `content_types` * extras.JobResult - * Added the `scheduled` field + * Added `scheduled` and `started` datetime fields * ipam.Aggregate * Added a `comments` field * ipam.ASN diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index dfca997d8..7dbecc5af 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -385,8 +385,8 @@ class JobResultSerializer(BaseModelSerializer): class Meta: model = JobResult fields = [ - 'id', 'url', 'display', 'status', 'created', 'scheduled', 'completed', 'name', 'obj_type', 'user', 'data', - 'job_id', + 'id', 'url', 'display', 'status', 'created', 'scheduled', 'started', 'completed', 'name', 'obj_type', + 'user', 'data', 'job_id', ] diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 9609f45db..0dbbaa314 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -503,15 +503,6 @@ class JobResultFilterSet(BaseFilterSet): field_name='created', 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' - ) scheduled = django_filters.DateTimeFilter() scheduled__before = django_filters.DateTimeFilter( field_name='scheduled', @@ -521,6 +512,24 @@ class JobResultFilterSet(BaseFilterSet): 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=JobResultStatusChoices, null_value=None @@ -528,9 +537,7 @@ class JobResultFilterSet(BaseFilterSet): class Meta: model = JobResult - fields = [ - 'id', 'status', 'created', 'scheduled', 'completed', 'user', 'obj_type', 'name' - ] + fields = ('id', 'status', 'user', 'obj_type', 'name') def search(self, queryset, name, value): if not value.strip(): diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index 4464c227f..e6a9089bc 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -73,11 +73,10 @@ class JobResultFilterForm(SavedFiltersMixin, FilterForm): (None, ('q', 'filter_id')), ('Attributes', ('obj_type', 'status')), ('Creation', ( - 'created__before', 'created__after', 'completed__before', 'completed__after', 'scheduled__before', - 'scheduled__after', 'user', + 'created__before', 'created__after', 'scheduled__before', 'scheduled__after', 'started__before', + 'started__after', 'completed__before', 'completed__after', 'user', )), ) - obj_type = ContentTypeChoiceField( label=_('Object Type'), queryset=ContentType.objects.all(), @@ -96,14 +95,6 @@ class JobResultFilterForm(SavedFiltersMixin, FilterForm): required=False, widget=DateTimePicker() ) - completed__after = forms.DateTimeField( - required=False, - widget=DateTimePicker() - ) - completed__before = forms.DateTimeField( - required=False, - widget=DateTimePicker() - ) scheduled__after = forms.DateTimeField( required=False, widget=DateTimePicker() @@ -112,6 +103,22 @@ class JobResultFilterForm(SavedFiltersMixin, FilterForm): 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, diff --git a/netbox/extras/migrations/0079_jobresult_scheduled.py b/netbox/extras/migrations/0079_scheduled_jobs.py similarity index 74% rename from netbox/extras/migrations/0079_jobresult_scheduled.py rename to netbox/extras/migrations/0079_scheduled_jobs.py index b970042c2..807e980a4 100644 --- a/netbox/extras/migrations/0079_jobresult_scheduled.py +++ b/netbox/extras/migrations/0079_scheduled_jobs.py @@ -13,6 +13,11 @@ class Migration(migrations.Migration): name='scheduled', field=models.DateTimeField(blank=True, null=True), ), + migrations.AddField( + model_name='jobresult', + name='started', + field=models.DateTimeField(blank=True, null=True), + ), migrations.AlterModelOptions( name='jobresult', options={'ordering': ['-created']}, diff --git a/netbox/extras/migrations/0080_customlink_content_types.py b/netbox/extras/migrations/0080_customlink_content_types.py index 539db3f0f..7f8456c67 100644 --- a/netbox/extras/migrations/0080_customlink_content_types.py +++ b/netbox/extras/migrations/0080_customlink_content_types.py @@ -12,7 +12,7 @@ class Migration(migrations.Migration): dependencies = [ ('contenttypes', '0002_remove_content_type_name'), - ('extras', '0079_jobresult_scheduled'), + ('extras', '0079_scheduled_jobs'), ] operations = [ diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 9f99d37ff..95a414225 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -585,6 +585,10 @@ class JobResult(models.Model): null=True, blank=True ) + started = models.DateTimeField( + null=True, + blank=True + ) completed = models.DateTimeField( null=True, blank=True @@ -639,9 +643,18 @@ class JobResult(models.Model): return f"{int(minutes)} minutes, {seconds:.2f} seconds" + def start(self): + """ + Record the job's start time and update its status to "running." + """ + if self.started is None: + self.started = timezone.now() + self.status = JobResultStatusChoices.STATUS_RUNNING + JobResult.objects.filter(pk=self.pk).update(started=self.started, status=self.status) + def set_status(self, status): """ - Helper method to change the status of the job result. If the target status is terminal, the completion + Helper method to change the status of the job result. If the target status is terminal, the completion time is also set. """ self.status = status diff --git a/netbox/extras/reports.py b/netbox/extras/reports.py index 525608c86..647f17149 100644 --- a/netbox/extras/reports.py +++ b/netbox/extras/reports.py @@ -83,6 +83,7 @@ def run_report(job_result, *args, **kwargs): report = get_report(module_name, report_name) try: + job_result.start() report.run(job_result) except Exception as e: job_result.set_status(JobResultStatusChoices.STATUS_ERRORED) diff --git a/netbox/extras/scripts.py b/netbox/extras/scripts.py index 23a778789..a4bcd0748 100644 --- a/netbox/extras/scripts.py +++ b/netbox/extras/scripts.py @@ -433,16 +433,14 @@ def is_variable(obj): def run_script(data, request, commit=True, *args, **kwargs): """ A wrapper for calling Script.run(). This performs error handling and provides a hook for committing changes. It - exists outside of the Script class to ensure it cannot be overridden by a script author. + exists outside the Script class to ensure it cannot be overridden by a script author. """ job_result = kwargs.pop('job_result') + job_result.start() + module, script_name = job_result.name.split('.', 1) - script = get_script(module, script_name)() - job_result.status = JobResultStatusChoices.STATUS_RUNNING - job_result.save() - logger = logging.getLogger(f"netbox.scripts.{module}.{script_name}") logger.info(f"Running script (commit={commit})") diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index d918bdf5a..7e5357dcd 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -49,9 +49,11 @@ class JobResultTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = JobResult fields = ( - 'pk', 'id', 'name', 'obj_type', 'status', 'created', 'scheduled', 'completed', 'user', 'job_id', + 'pk', 'id', 'name', 'obj_type', 'status', 'created', 'scheduled', 'started', 'completed', 'user', 'job_id', + ) + default_columns = ( + 'pk', 'id', 'name', 'obj_type', 'status', 'created', 'scheduled', 'started', 'completed', 'user', ) - default_columns = ('pk', 'id', 'name', 'obj_type', 'status', 'created', 'scheduled', 'completed', 'user',) class CustomLinkTable(NetBoxTable): diff --git a/netbox/extras/views.py b/netbox/extras/views.py index fec82a13b..9ce643ca5 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -726,7 +726,7 @@ class ReportResultView(ContentTypePermissionRequiredMixin, View): 'report': report, 'result': result, }) - if result.completed: + if result.completed or not result.started: response.status_code = 286 return response @@ -860,7 +860,7 @@ class ScriptResultView(ContentTypePermissionRequiredMixin, GetScriptMixin, View) 'script': script, 'result': result, }) - if result.completed: + if result.completed or not result.started: response.status_code = 286 return response diff --git a/netbox/templates/extras/htmx/report_result.html b/netbox/templates/extras/htmx/report_result.html index cfa8b2523..acc0fe9ab 100644 --- a/netbox/templates/extras/htmx/report_result.html +++ b/netbox/templates/extras/htmx/report_result.html @@ -1,9 +1,12 @@ {% load helpers %}

- Initiated: {{ result.created|annotated_date }} - {% if result.scheduled %} + {% if result.started %} + Started: {{ result.started|annotated_date }} + {% elif result.scheduled %} Scheduled for: {{ result.scheduled|annotated_date }} + {% else %} + Created: {{ result.created|annotated_date }} {% endif %} {% if result.completed %} Duration: {{ result.duration }} @@ -71,6 +74,6 @@ -{% else %} +{% elif result.started %} {% include 'extras/inc/result_pending.html' %} {% endif %} diff --git a/netbox/templates/extras/htmx/script_result.html b/netbox/templates/extras/htmx/script_result.html index ca658fa2e..457548d28 100644 --- a/netbox/templates/extras/htmx/script_result.html +++ b/netbox/templates/extras/htmx/script_result.html @@ -2,9 +2,12 @@ {% load log_levels %}

- Initiated: {{ result.created|annotated_date }} - {% if result.scheduled %} + {% if result.started %} + Started: {{ result.started|annotated_date }} + {% elif result.scheduled %} Scheduled for: {{ result.scheduled|annotated_date }} + {% else %} + Created: {{ result.created|annotated_date }} {% endif %} {% if result.completed %} Duration: {{ result.duration }} @@ -48,6 +51,6 @@ {% else %}

None

{% endif %} -{% else %} +{% elif result.started %} {% include 'extras/inc/result_pending.html' %} {% endif %} diff --git a/netbox/templates/extras/report_result.html b/netbox/templates/extras/report_result.html index 0c61c63f9..ffa52f9b7 100644 --- a/netbox/templates/extras/report_result.html +++ b/netbox/templates/extras/report_result.html @@ -4,7 +4,7 @@ {% block content-wrapper %}
-
+
{% include 'extras/htmx/report_result.html' %}
diff --git a/netbox/templates/extras/script_result.html b/netbox/templates/extras/script_result.html index 2fc01e9fa..bff3fc61e 100644 --- a/netbox/templates/extras/script_result.html +++ b/netbox/templates/extras/script_result.html @@ -47,7 +47,7 @@
-
+
{% include 'extras/htmx/script_result.html' %}