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

Add trigger_webhooks() to JobResult

This commit is contained in:
jeremystretch
2023-02-28 16:21:01 -05:00
committed by Jeremy Stretch
parent a8c331f88a
commit 4de64d783e
3 changed files with 56 additions and 12 deletions

View File

@ -1,8 +1,16 @@
from django.contrib.contenttypes.models import ContentType
# Webhook content types
# Webhooks
HTTP_CONTENT_TYPE_JSON = 'application/json'
WEBHOOK_EVENT_TYPES = {
'create': 'created',
'update': 'updated',
'delete': 'deleted',
'job_start': 'job_started',
'job_end': 'job_ended',
}
# Dashboard
DEFAULT_DASHBOARD = [
{

View File

@ -26,7 +26,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT
from netbox.models import ChangeLoggedModel
from netbox.models.features import (
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, SyncedDataMixin,
TagsMixin,
TagsMixin, WebhooksMixin,
)
from utilities.querysets import RestrictedQuerySet
from utilities.utils import render_jinja2
@ -689,10 +689,16 @@ class JobResult(models.Model):
"""
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)
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='job_start')
def terminate(self, status=JobResultStatusChoices.STATUS_COMPLETED):
"""
@ -701,10 +707,15 @@ class JobResult(models.Model):
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='job_end')
@classmethod
def enqueue_job(cls, func, name, obj_type, user, schedule_at=None, interval=None, *args, **kwargs):
"""
@ -738,6 +749,28 @@ class JobResult(models.Model):
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):
"""
@ -780,7 +813,7 @@ class ConfigRevision(models.Model):
# Custom scripts & reports
#
class Script(JobResultsMixin, models.Model):
class Script(JobResultsMixin, WebhooksMixin, models.Model):
"""
Dummy model used to generate permissions for custom scripts. Does not exist in the database.
"""
@ -792,7 +825,7 @@ class Script(JobResultsMixin, models.Model):
# Reports
#
class Report(JobResultsMixin, models.Model):
class Report(JobResultsMixin, WebhooksMixin, models.Model):
"""
Dummy model used to generate permissions for reports. Does not exist in the database.
"""

View File

@ -5,8 +5,8 @@ from django.conf import settings
from django_rq import job
from jinja2.exceptions import TemplateError
from .choices import ObjectChangeActionChoices
from .conditions import ConditionSet
from .constants import WEBHOOK_EVENT_TYPES
from .webhooks import generate_signature
logger = logging.getLogger('netbox.webhooks_worker')
@ -28,7 +28,7 @@ def eval_conditions(webhook, data):
@job('default')
def process_webhook(webhook, model_name, event, data, snapshots, timestamp, username, request_id):
def process_webhook(webhook, model_name, event, data, timestamp, username, request_id=None, snapshots=None):
"""
Make a POST request to the defined Webhook
"""
@ -38,14 +38,17 @@ def process_webhook(webhook, model_name, event, data, snapshots, timestamp, user
# Prepare context data for headers & body templates
context = {
'event': dict(ObjectChangeActionChoices)[event].lower(),
'event': WEBHOOK_EVENT_TYPES[event],
'timestamp': timestamp,
'model': model_name,
'username': username,
'request_id': request_id,
'data': data,
'snapshots': snapshots,
}
if snapshots:
context.update({
'snapshots': snapshots
})
# Build the headers for the HTTP request
headers = {