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

Closes #12068: Establish a direct relationship from jobs to objects (#12075)

* Reference database object by GFK when running scripts & reports via UI

* Reference database object by GFK when running scripts & reports via API

* Remove old enqueue_job() method

* Enable filtering jobs by object

* Introduce ObjectJobsView

* Add tabbed views for report & script jobs

* Add object_id to JobSerializer

* Move generic relation to JobsMixin

* Clean up old naming
This commit is contained in:
Jeremy Stretch
2023-03-28 15:47:09 -04:00
committed by GitHub
parent 15590f1f48
commit d2a694a878
33 changed files with 583 additions and 353 deletions

View File

@@ -5,7 +5,7 @@ from fnmatch import fnmatchcase
from urllib.parse import urlparse
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.db import models
@@ -15,6 +15,7 @@ from django.utils.module_loading import import_string
from django.utils.translation import gettext as _
from netbox.models import PrimaryModel
from netbox.models.features import JobsMixin
from netbox.registry import registry
from utilities.files import sha256_hash
from utilities.querysets import RestrictedQuerySet
@@ -31,7 +32,7 @@ __all__ = (
logger = logging.getLogger('netbox.core.data')
class DataSource(PrimaryModel):
class DataSource(JobsMixin, PrimaryModel):
"""
A remote source, such as a git repository, from which DataFiles are synchronized.
"""
@@ -118,15 +119,12 @@ class DataSource(PrimaryModel):
DataSource.objects.filter(pk=self.pk).update(status=self.status)
# Enqueue a sync job
job_result = Job.enqueue_job(
return Job.enqueue(
import_string('core.jobs.sync_datasource'),
name=self.name,
obj_type=ContentType.objects.get_for_model(DataSource),
user=request.user,
instance=self,
user=request.user
)
return job_result
def get_backend(self):
backend_cls = registry['data_backends'].get(self.type)
backend_params = self.parameters or {}

View File

@@ -7,7 +7,6 @@ from django.contrib.contenttypes.models import ContentType
from django.core.validators import MinValueValidator
from django.db import models
from django.urls import reverse
from django.urls.exceptions import NoReverseMatch
from django.utils import timezone
from django.utils.translation import gettext as _
@@ -96,21 +95,12 @@ class Job(models.Model):
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.object_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.object_type.model}_result', args=[self.pk])
except NoReverseMatch:
return None
# TODO: Employ dynamic registration
if self.object_type.model == 'reportmodule':
return reverse(f'extras:report_result', kwargs={'job_pk': self.pk})
if self.object_type.model == 'scriptmodule':
return reverse(f'extras:script_result', kwargs={'job_pk': self.pk})
def get_status_color(self):
return JobStatusChoices.colors.get(self.status)
@@ -130,6 +120,16 @@ class Job(models.Model):
return f"{int(minutes)} minutes, {seconds:.2f} seconds"
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
rq_queue_name = get_config().QUEUE_MAPPINGS.get(self.object_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 start(self):
"""
Record the job's start time and update its status to "running."
@@ -162,25 +162,27 @@ class Job(models.Model):
self.trigger_webhooks(event=EVENT_JOB_END)
@classmethod
def enqueue_job(cls, func, name, obj_type, user, schedule_at=None, interval=None, *args, **kwargs):
def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval=None, **kwargs):
"""
Create a Job instance and enqueue a job using the given callable
Args:
func: The callable object to be enqueued for execution
instance: The NetBox object to which this job pertains
name: Name for the job (optional)
obj_type: ContentType to link to the Job instance object_type
user: User object to link to the Job instance
user: The user responsible for running the job
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)
object_type = ContentType.objects.get_for_model(instance, for_concrete_model=False)
rq_queue_name = get_queue_for_model(object_type.model)
queue = django_rq.get_queue(rq_queue_name)
status = JobStatusChoices.STATUS_SCHEDULED if schedule_at else JobStatusChoices.STATUS_PENDING
job = Job.objects.create(
object_type=object_type,
object_id=instance.pk,
name=name,
status=status,
object_type=obj_type,
scheduled=schedule_at,
interval=interval,
user=user,
@@ -188,9 +190,9 @@ class Job(models.Model):
)
if schedule_at:
queue.enqueue_at(schedule_at, func, job_id=str(job.job_id), job_result=job, **kwargs)
queue.enqueue_at(schedule_at, func, job_id=str(job.job_id), job=job, **kwargs)
else:
queue.enqueue(func, job_id=str(job.job_id), job_result=job, **kwargs)
queue.enqueue(func, job_id=str(job.job_id), job=job, **kwargs)
return job