1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Remove the old JobResult model

This commit is contained in:
jeremystretch
2023-03-27 13:33:23 -04:00
committed by Jeremy Stretch
parent b3d2020045
commit 82080ef491
2 changed files with 17 additions and 195 deletions

View File

@ -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.