|
@@ -6,6 +6,8 @@ from django.db.models.signals import m2m_changed, post_save, pre_delete
|
|
|
from django.dispatch import receiver, Signal
|
|
from django.dispatch import receiver, Signal
|
|
|
from django_prometheus.models import model_deletes, model_inserts, model_updates
|
|
from django_prometheus.models import model_deletes, model_inserts, model_updates
|
|
|
|
|
|
|
|
|
|
+from netbox import thread_locals
|
|
|
|
|
+from netbox.request_context import get_request
|
|
|
from netbox.signals import post_clean
|
|
from netbox.signals import post_clean
|
|
|
from .choices import ObjectChangeActionChoices
|
|
from .choices import ObjectChangeActionChoices
|
|
|
from .models import CustomField, ObjectChange
|
|
from .models import CustomField, ObjectChange
|
|
@@ -20,10 +22,16 @@ from .webhooks import enqueue_object, get_snapshots, serialize_for_webhook
|
|
|
clear_webhooks = Signal()
|
|
clear_webhooks = Signal()
|
|
|
|
|
|
|
|
|
|
|
|
|
-def _handle_changed_object(request, webhook_queue, sender, instance, **kwargs):
|
|
|
|
|
|
|
+def handle_changed_object(sender, instance, **kwargs):
|
|
|
"""
|
|
"""
|
|
|
Fires when an object is created or updated.
|
|
Fires when an object is created or updated.
|
|
|
"""
|
|
"""
|
|
|
|
|
+ if not hasattr(instance, 'to_objectchange'):
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ request = get_request()
|
|
|
|
|
+ m2m_changed = False
|
|
|
|
|
+
|
|
|
def is_same_object(instance, webhook_data):
|
|
def is_same_object(instance, webhook_data):
|
|
|
return (
|
|
return (
|
|
|
ContentType.objects.get_for_model(instance) == webhook_data['content_type'] and
|
|
ContentType.objects.get_for_model(instance) == webhook_data['content_type'] and
|
|
@@ -31,11 +39,6 @@ def _handle_changed_object(request, webhook_queue, sender, instance, **kwargs):
|
|
|
request.id == webhook_data['request_id']
|
|
request.id == webhook_data['request_id']
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- if not hasattr(instance, 'to_objectchange'):
|
|
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- m2m_changed = False
|
|
|
|
|
-
|
|
|
|
|
# Determine the type of change being made
|
|
# Determine the type of change being made
|
|
|
if kwargs.get('created'):
|
|
if kwargs.get('created'):
|
|
|
action = ObjectChangeActionChoices.ACTION_CREATE
|
|
action = ObjectChangeActionChoices.ACTION_CREATE
|
|
@@ -65,6 +68,7 @@ def _handle_changed_object(request, webhook_queue, sender, instance, **kwargs):
|
|
|
objectchange.save()
|
|
objectchange.save()
|
|
|
|
|
|
|
|
# If this is an M2M change, update the previously queued webhook (from post_save)
|
|
# If this is an M2M change, update the previously queued webhook (from post_save)
|
|
|
|
|
+ webhook_queue = thread_locals.webhook_queue
|
|
|
if m2m_changed and webhook_queue and is_same_object(instance, webhook_queue[-1]):
|
|
if m2m_changed and webhook_queue and is_same_object(instance, webhook_queue[-1]):
|
|
|
instance.refresh_from_db() # Ensure that we're working with fresh M2M assignments
|
|
instance.refresh_from_db() # Ensure that we're working with fresh M2M assignments
|
|
|
webhook_queue[-1]['data'] = serialize_for_webhook(instance)
|
|
webhook_queue[-1]['data'] = serialize_for_webhook(instance)
|
|
@@ -79,13 +83,15 @@ def _handle_changed_object(request, webhook_queue, sender, instance, **kwargs):
|
|
|
model_updates.labels(instance._meta.model_name).inc()
|
|
model_updates.labels(instance._meta.model_name).inc()
|
|
|
|
|
|
|
|
|
|
|
|
|
-def _handle_deleted_object(request, webhook_queue, sender, instance, **kwargs):
|
|
|
|
|
|
|
+def handle_deleted_object(sender, instance, **kwargs):
|
|
|
"""
|
|
"""
|
|
|
Fires when an object is deleted.
|
|
Fires when an object is deleted.
|
|
|
"""
|
|
"""
|
|
|
if not hasattr(instance, 'to_objectchange'):
|
|
if not hasattr(instance, 'to_objectchange'):
|
|
|
return
|
|
return
|
|
|
|
|
|
|
|
|
|
+ request = get_request()
|
|
|
|
|
+
|
|
|
# Record an ObjectChange if applicable
|
|
# Record an ObjectChange if applicable
|
|
|
if hasattr(instance, 'to_objectchange'):
|
|
if hasattr(instance, 'to_objectchange'):
|
|
|
objectchange = instance.to_objectchange(ObjectChangeActionChoices.ACTION_DELETE)
|
|
objectchange = instance.to_objectchange(ObjectChangeActionChoices.ACTION_DELETE)
|
|
@@ -94,19 +100,21 @@ def _handle_deleted_object(request, webhook_queue, sender, instance, **kwargs):
|
|
|
objectchange.save()
|
|
objectchange.save()
|
|
|
|
|
|
|
|
# Enqueue webhooks
|
|
# Enqueue webhooks
|
|
|
|
|
+ webhook_queue = thread_locals.webhook_queue
|
|
|
enqueue_object(webhook_queue, instance, request.user, request.id, ObjectChangeActionChoices.ACTION_DELETE)
|
|
enqueue_object(webhook_queue, instance, request.user, request.id, ObjectChangeActionChoices.ACTION_DELETE)
|
|
|
|
|
|
|
|
# Increment metric counters
|
|
# Increment metric counters
|
|
|
model_deletes.labels(instance._meta.model_name).inc()
|
|
model_deletes.labels(instance._meta.model_name).inc()
|
|
|
|
|
|
|
|
|
|
|
|
|
-def _clear_webhook_queue(webhook_queue, sender, **kwargs):
|
|
|
|
|
|
|
+def clear_webhook_queue(sender, **kwargs):
|
|
|
"""
|
|
"""
|
|
|
Delete any queued webhooks (e.g. because of an aborted bulk transaction)
|
|
Delete any queued webhooks (e.g. because of an aborted bulk transaction)
|
|
|
"""
|
|
"""
|
|
|
logger = logging.getLogger('webhooks')
|
|
logger = logging.getLogger('webhooks')
|
|
|
- logger.info(f"Clearing {len(webhook_queue)} queued webhooks ({sender})")
|
|
|
|
|
|
|
+ webhook_queue = thread_locals.webhook_queue
|
|
|
|
|
|
|
|
|
|
+ logger.info(f"Clearing {len(webhook_queue)} queued webhooks ({sender})")
|
|
|
webhook_queue.clear()
|
|
webhook_queue.clear()
|
|
|
|
|
|
|
|
|
|
|