From 82080ef49124a88fa2a50dbffd3efe00412c4472 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 27 Mar 2023 13:33:23 -0400 Subject: [PATCH] Remove the old JobResult model --- .../migrations/0092_delete_jobresult.py | 16 ++ netbox/extras/models/models.py | 196 +----------------- 2 files changed, 17 insertions(+), 195 deletions(-) create mode 100644 netbox/extras/migrations/0092_delete_jobresult.py diff --git a/netbox/extras/migrations/0092_delete_jobresult.py b/netbox/extras/migrations/0092_delete_jobresult.py new file mode 100644 index 000000000..c1b121c69 --- /dev/null +++ b/netbox/extras/migrations/0092_delete_jobresult.py @@ -0,0 +1,16 @@ +# Generated by Django 4.1.7 on 2023-03-27 17:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0091_create_managedfiles'), + ] + + operations = [ + migrations.DeleteModel( + name='JobResult', + ), + ] diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index ce8cdd6f4..61c19bb0d 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -1,18 +1,15 @@ import json -import uuid -import django_rq from django.conf import settings from django.contrib import admin from django.contrib.auth.models import User from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.core.cache import cache -from django.core.validators import MinValueValidator, ValidationError +from django.core.validators import ValidationError from django.db import models from django.http import HttpResponse, QueryDict from django.urls import reverse -from django.urls.exceptions import NoReverseMatch from django.utils import timezone from django.utils.formats import date_format from django.utils.translation import gettext as _ @@ -22,14 +19,11 @@ from extras.choices import * from extras.conditions import ConditionSet from extras.constants import * from extras.utils import FeatureQuery, image_upload -from netbox.config import get_config -from netbox.constants import RQ_QUEUE_DEFAULT from netbox.models import ChangeLoggedModel from netbox.models.features import ( CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, ) from utilities.querysets import RestrictedQuerySet -from utilities.rqworker import get_queue_for_model from utilities.utils import render_jinja2 __all__ = ( @@ -37,7 +31,6 @@ __all__ = ( 'CustomLink', 'ExportTemplate', 'ImageAttachment', - 'JobResult', 'JournalEntry', 'SavedFilter', 'Webhook', @@ -583,193 +576,6 @@ class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ExportTemplat return JournalEntryKindChoices.colors.get(self.kind) -class JobResult(models.Model): - """ - This model stores the results from running a user-defined report. - """ - name = models.CharField( - max_length=255 - ) - obj_type = models.ForeignKey( - to=ContentType, - related_name='job_results', - verbose_name='Object types', - limit_choices_to=FeatureQuery('jobs'), - help_text=_("The object type to which this job result applies"), - on_delete=models.CASCADE, - ) - created = models.DateTimeField( - auto_now_add=True - ) - scheduled = models.DateTimeField( - null=True, - blank=True - ) - interval = models.PositiveIntegerField( - blank=True, - null=True, - validators=( - MinValueValidator(1), - ), - help_text=_("Recurrence interval (in minutes)") - ) - started = models.DateTimeField( - null=True, - blank=True - ) - completed = models.DateTimeField( - null=True, - blank=True - ) - user = models.ForeignKey( - to=User, - on_delete=models.SET_NULL, - related_name='+', - blank=True, - null=True - ) - status = models.CharField( - max_length=30, - choices=JobResultStatusChoices, - default=JobResultStatusChoices.STATUS_PENDING - ) - data = models.JSONField( - null=True, - blank=True - ) - job_id = models.UUIDField( - unique=True - ) - - objects = RestrictedQuerySet.as_manager() - - class Meta: - ordering = ['-created'] - - def __str__(self): - return str(self.job_id) - - def delete(self, *args, **kwargs): - super().delete(*args, **kwargs) - - rq_queue_name = get_config().QUEUE_MAPPINGS.get(self.obj_type.model, RQ_QUEUE_DEFAULT) - queue = django_rq.get_queue(rq_queue_name) - job = queue.fetch_job(str(self.job_id)) - - if job: - job.cancel() - - def get_absolute_url(self): - try: - return reverse(f'extras:{self.obj_type.model}_result', args=[self.pk]) - except NoReverseMatch: - return None - - def get_status_color(self): - return JobResultStatusChoices.colors.get(self.status) - - @property - def duration(self): - if not self.completed: - return None - - start_time = self.started or self.created - - if not start_time: - return None - - duration = self.completed - start_time - minutes, seconds = divmod(duration.total_seconds(), 60) - - 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 not None: - return - - # Start the job - self.started = timezone.now() - self.status = JobResultStatusChoices.STATUS_RUNNING - JobResult.objects.filter(pk=self.pk).update(started=self.started, status=self.status) - - # Handle webhooks - self.trigger_webhooks(event=EVENT_JOB_START) - - def terminate(self, status=JobResultStatusChoices.STATUS_COMPLETED): - """ - Mark the job as completed, optionally specifying a particular termination status. - """ - valid_statuses = JobResultStatusChoices.TERMINAL_STATE_CHOICES - if status not in valid_statuses: - raise ValueError(f"Invalid status for job termination. Choices are: {', '.join(valid_statuses)}") - - # Mark the job as completed - self.status = status - self.completed = timezone.now() - JobResult.objects.filter(pk=self.pk).update(status=self.status, completed=self.completed) - - # Handle webhooks - self.trigger_webhooks(event=EVENT_JOB_END) - - @classmethod - def enqueue_job(cls, func, name, obj_type, user, schedule_at=None, interval=None, *args, **kwargs): - """ - Create a JobResult instance and enqueue a job using the given callable - - Args: - func: The callable object to be enqueued for execution - name: Name for the JobResult instance - obj_type: ContentType to link to the JobResult instance obj_type - user: User object to link to the JobResult instance - schedule_at: Schedule the job to be executed at the passed date and time - interval: Recurrence interval (in minutes) - """ - rq_queue_name = get_queue_for_model(obj_type.model) - queue = django_rq.get_queue(rq_queue_name) - status = JobResultStatusChoices.STATUS_SCHEDULED if schedule_at else JobResultStatusChoices.STATUS_PENDING - job_result: JobResult = JobResult.objects.create( - name=name, - status=status, - obj_type=obj_type, - scheduled=schedule_at, - interval=interval, - user=user, - job_id=uuid.uuid4() - ) - - if schedule_at: - 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) - - return job_result - - def trigger_webhooks(self, event): - rq_queue_name = get_config().QUEUE_MAPPINGS.get('webhook', RQ_QUEUE_DEFAULT) - rq_queue = django_rq.get_queue(rq_queue_name, is_async=False) - - # Fetch any webhooks matching this object type and action - webhooks = Webhook.objects.filter( - **{f'type_{event}': True}, - content_types=self.obj_type, - enabled=True - ) - - for webhook in webhooks: - rq_queue.enqueue( - "extras.webhooks_worker.process_webhook", - webhook=webhook, - model_name=self.obj_type.model, - event=event, - data=self.data, - timestamp=str(timezone.now()), - username=self.user.username - ) - - class ConfigRevision(models.Model): """ An atomic revision of NetBox's configuration.