Skip to content

Commit 82080ef

Browse files
committed
Remove the old JobResult model
1 parent b3d2020 commit 82080ef

File tree

2 files changed

+17
-195
lines changed

2 files changed

+17
-195
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Generated by Django 4.1.7 on 2023-03-27 17:31
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('extras', '0091_create_managedfiles'),
10+
]
11+
12+
operations = [
13+
migrations.DeleteModel(
14+
name='JobResult',
15+
),
16+
]

netbox/extras/models/models.py

Lines changed: 1 addition & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
import json
2-
import uuid
32

4-
import django_rq
53
from django.conf import settings
64
from django.contrib import admin
75
from django.contrib.auth.models import User
86
from django.contrib.contenttypes.fields import GenericForeignKey
97
from django.contrib.contenttypes.models import ContentType
108
from django.core.cache import cache
11-
from django.core.validators import MinValueValidator, ValidationError
9+
from django.core.validators import ValidationError
1210
from django.db import models
1311
from django.http import HttpResponse, QueryDict
1412
from django.urls import reverse
15-
from django.urls.exceptions import NoReverseMatch
1613
from django.utils import timezone
1714
from django.utils.formats import date_format
1815
from django.utils.translation import gettext as _
@@ -22,22 +19,18 @@
2219
from extras.conditions import ConditionSet
2320
from extras.constants import *
2421
from extras.utils import FeatureQuery, image_upload
25-
from netbox.config import get_config
26-
from netbox.constants import RQ_QUEUE_DEFAULT
2722
from netbox.models import ChangeLoggedModel
2823
from netbox.models.features import (
2924
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin,
3025
)
3126
from utilities.querysets import RestrictedQuerySet
32-
from utilities.rqworker import get_queue_for_model
3327
from utilities.utils import render_jinja2
3428

3529
__all__ = (
3630
'ConfigRevision',
3731
'CustomLink',
3832
'ExportTemplate',
3933
'ImageAttachment',
40-
'JobResult',
4134
'JournalEntry',
4235
'SavedFilter',
4336
'Webhook',
@@ -583,193 +576,6 @@ def get_kind_color(self):
583576
return JournalEntryKindChoices.colors.get(self.kind)
584577

585578

586-
class JobResult(models.Model):
587-
"""
588-
This model stores the results from running a user-defined report.
589-
"""
590-
name = models.CharField(
591-
max_length=255
592-
)
593-
obj_type = models.ForeignKey(
594-
to=ContentType,
595-
related_name='job_results',
596-
verbose_name='Object types',
597-
limit_choices_to=FeatureQuery('jobs'),
598-
help_text=_("The object type to which this job result applies"),
599-
on_delete=models.CASCADE,
600-
)
601-
created = models.DateTimeField(
602-
auto_now_add=True
603-
)
604-
scheduled = models.DateTimeField(
605-
null=True,
606-
blank=True
607-
)
608-
interval = models.PositiveIntegerField(
609-
blank=True,
610-
null=True,
611-
validators=(
612-
MinValueValidator(1),
613-
),
614-
help_text=_("Recurrence interval (in minutes)")
615-
)
616-
started = models.DateTimeField(
617-
null=True,
618-
blank=True
619-
)
620-
completed = models.DateTimeField(
621-
null=True,
622-
blank=True
623-
)
624-
user = models.ForeignKey(
625-
to=User,
626-
on_delete=models.SET_NULL,
627-
related_name='+',
628-
blank=True,
629-
null=True
630-
)
631-
status = models.CharField(
632-
max_length=30,
633-
choices=JobResultStatusChoices,
634-
default=JobResultStatusChoices.STATUS_PENDING
635-
)
636-
data = models.JSONField(
637-
null=True,
638-
blank=True
639-
)
640-
job_id = models.UUIDField(
641-
unique=True
642-
)
643-
644-
objects = RestrictedQuerySet.as_manager()
645-
646-
class Meta:
647-
ordering = ['-created']
648-
649-
def __str__(self):
650-
return str(self.job_id)
651-
652-
def delete(self, *args, **kwargs):
653-
super().delete(*args, **kwargs)
654-
655-
rq_queue_name = get_config().QUEUE_MAPPINGS.get(self.obj_type.model, RQ_QUEUE_DEFAULT)
656-
queue = django_rq.get_queue(rq_queue_name)
657-
job = queue.fetch_job(str(self.job_id))
658-
659-
if job:
660-
job.cancel()
661-
662-
def get_absolute_url(self):
663-
try:
664-
return reverse(f'extras:{self.obj_type.model}_result', args=[self.pk])
665-
except NoReverseMatch:
666-
return None
667-
668-
def get_status_color(self):
669-
return JobResultStatusChoices.colors.get(self.status)
670-
671-
@property
672-
def duration(self):
673-
if not self.completed:
674-
return None
675-
676-
start_time = self.started or self.created
677-
678-
if not start_time:
679-
return None
680-
681-
duration = self.completed - start_time
682-
minutes, seconds = divmod(duration.total_seconds(), 60)
683-
684-
return f"{int(minutes)} minutes, {seconds:.2f} seconds"
685-
686-
def start(self):
687-
"""
688-
Record the job's start time and update its status to "running."
689-
"""
690-
if self.started is not None:
691-
return
692-
693-
# Start the job
694-
self.started = timezone.now()
695-
self.status = JobResultStatusChoices.STATUS_RUNNING
696-
JobResult.objects.filter(pk=self.pk).update(started=self.started, status=self.status)
697-
698-
# Handle webhooks
699-
self.trigger_webhooks(event=EVENT_JOB_START)
700-
701-
def terminate(self, status=JobResultStatusChoices.STATUS_COMPLETED):
702-
"""
703-
Mark the job as completed, optionally specifying a particular termination status.
704-
"""
705-
valid_statuses = JobResultStatusChoices.TERMINAL_STATE_CHOICES
706-
if status not in valid_statuses:
707-
raise ValueError(f"Invalid status for job termination. Choices are: {', '.join(valid_statuses)}")
708-
709-
# Mark the job as completed
710-
self.status = status
711-
self.completed = timezone.now()
712-
JobResult.objects.filter(pk=self.pk).update(status=self.status, completed=self.completed)
713-
714-
# Handle webhooks
715-
self.trigger_webhooks(event=EVENT_JOB_END)
716-
717-
@classmethod
718-
def enqueue_job(cls, func, name, obj_type, user, schedule_at=None, interval=None, *args, **kwargs):
719-
"""
720-
Create a JobResult instance and enqueue a job using the given callable
721-
722-
Args:
723-
func: The callable object to be enqueued for execution
724-
name: Name for the JobResult instance
725-
obj_type: ContentType to link to the JobResult instance obj_type
726-
user: User object to link to the JobResult instance
727-
schedule_at: Schedule the job to be executed at the passed date and time
728-
interval: Recurrence interval (in minutes)
729-
"""
730-
rq_queue_name = get_queue_for_model(obj_type.model)
731-
queue = django_rq.get_queue(rq_queue_name)
732-
status = JobResultStatusChoices.STATUS_SCHEDULED if schedule_at else JobResultStatusChoices.STATUS_PENDING
733-
job_result: JobResult = JobResult.objects.create(
734-
name=name,
735-
status=status,
736-
obj_type=obj_type,
737-
scheduled=schedule_at,
738-
interval=interval,
739-
user=user,
740-
job_id=uuid.uuid4()
741-
)
742-
743-
if schedule_at:
744-
queue.enqueue_at(schedule_at, func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
745-
else:
746-
queue.enqueue(func, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
747-
748-
return job_result
749-
750-
def trigger_webhooks(self, event):
751-
rq_queue_name = get_config().QUEUE_MAPPINGS.get('webhook', RQ_QUEUE_DEFAULT)
752-
rq_queue = django_rq.get_queue(rq_queue_name, is_async=False)
753-
754-
# Fetch any webhooks matching this object type and action
755-
webhooks = Webhook.objects.filter(
756-
**{f'type_{event}': True},
757-
content_types=self.obj_type,
758-
enabled=True
759-
)
760-
761-
for webhook in webhooks:
762-
rq_queue.enqueue(
763-
"extras.webhooks_worker.process_webhook",
764-
webhook=webhook,
765-
model_name=self.obj_type.model,
766-
event=event,
767-
data=self.data,
768-
timestamp=str(timezone.now()),
769-
username=self.user.username
770-
)
771-
772-
773579
class ConfigRevision(models.Model):
774580
"""
775581
An atomic revision of NetBox's configuration.

0 commit comments

Comments
 (0)