Procházet zdrojové kódy

Closes #14395: Move & rename process_webhook()

Jeremy Stretch před 2 roky
rodič
revize
85ab7adca6

+ 1 - 1
netbox/extras/events.py

@@ -108,7 +108,7 @@ def process_event_rules(event_rules, model_name, event, data, username, snapshot
 
             # Enqueue the task
             rq_queue.enqueue(
-                "extras.webhooks_worker.process_webhook",
+                "extras.webhooks.send_webhook",
                 **params
             )
 

+ 3 - 4
netbox/extras/tests/test_event_rules.py

@@ -11,8 +11,7 @@ from django.urls import reverse
 from extras.choices import EventRuleActionChoices, ObjectChangeActionChoices
 from extras.events import enqueue_object, flush_events, serialize_for_event
 from extras.models import EventRule, Tag, Webhook
-from extras.webhooks import generate_signature
-from extras.webhooks_worker import process_webhook
+from extras.webhooks import generate_signature, send_webhook
 from requests import Session
 from rest_framework import status
 from utilities.testing import APITestCase
@@ -331,7 +330,7 @@ class EventRuleTest(APITestCase):
             self.assertEqual(job.kwargs['snapshots']['prechange']['name'], sites[i].name)
             self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
 
-    def test_webhooks_worker(self):
+    def test_send_webhook(self):
         request_id = uuid.uuid4()
 
         def dummy_send(_, request, **kwargs):
@@ -376,4 +375,4 @@ class EventRuleTest(APITestCase):
 
         # Patch the Session object with our dummy_send() method, then process the webhook for sending
         with patch.object(Session, 'send', dummy_send) as mock_send:
-            process_webhook(**job.kwargs)
+            send_webhook(**job.kwargs)

+ 86 - 0
netbox/extras/webhooks.py

@@ -1,5 +1,15 @@
 import hashlib
 import hmac
+import logging
+
+import requests
+from django.conf import settings
+from django_rq import job
+from jinja2.exceptions import TemplateError
+
+from .constants import WEBHOOK_EVENT_TYPES
+
+logger = logging.getLogger('netbox.webhooks')
 
 
 def generate_signature(request_body, secret):
@@ -12,3 +22,79 @@ def generate_signature(request_body, secret):
         digestmod=hashlib.sha512
     )
     return hmac_prep.hexdigest()
+
+
+@job('default')
+def send_webhook(event_rule, model_name, event, data, timestamp, username, request_id=None, snapshots=None):
+    """
+    Make a POST request to the defined Webhook
+    """
+    webhook = event_rule.action_object
+
+    # Prepare context data for headers & body templates
+    context = {
+        'event': WEBHOOK_EVENT_TYPES[event],
+        'timestamp': timestamp,
+        'model': model_name,
+        'username': username,
+        'request_id': request_id,
+        'data': data,
+    }
+    if snapshots:
+        context.update({
+            'snapshots': snapshots
+        })
+
+    # Build the headers for the HTTP request
+    headers = {
+        'Content-Type': webhook.http_content_type,
+    }
+    try:
+        headers.update(webhook.render_headers(context))
+    except (TemplateError, ValueError) as e:
+        logger.error(f"Error parsing HTTP headers for webhook {webhook}: {e}")
+        raise e
+
+    # Render the request body
+    try:
+        body = webhook.render_body(context)
+    except TemplateError as e:
+        logger.error(f"Error rendering request body for webhook {webhook}: {e}")
+        raise e
+
+    # Prepare the HTTP request
+    params = {
+        'method': webhook.http_method,
+        'url': webhook.render_payload_url(context),
+        'headers': headers,
+        'data': body.encode('utf8'),
+    }
+    logger.info(
+        f"Sending {params['method']} request to {params['url']} ({context['model']} {context['event']})"
+    )
+    logger.debug(params)
+    try:
+        prepared_request = requests.Request(**params).prepare()
+    except requests.exceptions.RequestException as e:
+        logger.error(f"Error forming HTTP request: {e}")
+        raise e
+
+    # If a secret key is defined, sign the request with a hash of the key and its content
+    if webhook.secret != '':
+        prepared_request.headers['X-Hook-Signature'] = generate_signature(prepared_request.body, webhook.secret)
+
+    # Send the request
+    with requests.Session() as session:
+        session.verify = webhook.ssl_verification
+        if webhook.ca_file_path:
+            session.verify = webhook.ca_file_path
+        response = session.send(prepared_request, proxies=settings.HTTP_PROXIES)
+
+    if 200 <= response.status_code <= 299:
+        logger.info(f"Request succeeded; response status {response.status_code}")
+        return f"Status {response.status_code} returned, webhook successfully processed."
+    else:
+        logger.warning(f"Request failed; response status {response.status_code}: {response.content}")
+        raise requests.exceptions.RequestException(
+            f"Status {response.status_code} returned with content '{response.content}', webhook FAILED to process."
+        )

+ 7 - 84
netbox/extras/webhooks_worker.py

@@ -1,87 +1,10 @@
-import logging
+import warnings
 
-import requests
-from django.conf import settings
-from django_rq import job
-from jinja2.exceptions import TemplateError
+from .webhooks import send_webhook as process_webhook
 
-from .constants import WEBHOOK_EVENT_TYPES
-from .webhooks import generate_signature
 
-logger = logging.getLogger('netbox.webhooks_worker')
-
-
-@job('default')
-def process_webhook(event_rule, model_name, event, data, timestamp, username, request_id=None, snapshots=None):
-    """
-    Make a POST request to the defined Webhook
-    """
-    webhook = event_rule.action_object
-
-    # Prepare context data for headers & body templates
-    context = {
-        'event': WEBHOOK_EVENT_TYPES[event],
-        'timestamp': timestamp,
-        'model': model_name,
-        'username': username,
-        'request_id': request_id,
-        'data': data,
-    }
-    if snapshots:
-        context.update({
-            'snapshots': snapshots
-        })
-
-    # Build the headers for the HTTP request
-    headers = {
-        'Content-Type': webhook.http_content_type,
-    }
-    try:
-        headers.update(webhook.render_headers(context))
-    except (TemplateError, ValueError) as e:
-        logger.error(f"Error parsing HTTP headers for webhook {webhook}: {e}")
-        raise e
-
-    # Render the request body
-    try:
-        body = webhook.render_body(context)
-    except TemplateError as e:
-        logger.error(f"Error rendering request body for webhook {webhook}: {e}")
-        raise e
-
-    # Prepare the HTTP request
-    params = {
-        'method': webhook.http_method,
-        'url': webhook.render_payload_url(context),
-        'headers': headers,
-        'data': body.encode('utf8'),
-    }
-    logger.info(
-        f"Sending {params['method']} request to {params['url']} ({context['model']} {context['event']})"
-    )
-    logger.debug(params)
-    try:
-        prepared_request = requests.Request(**params).prepare()
-    except requests.exceptions.RequestException as e:
-        logger.error(f"Error forming HTTP request: {e}")
-        raise e
-
-    # If a secret key is defined, sign the request with a hash of the key and its content
-    if webhook.secret != '':
-        prepared_request.headers['X-Hook-Signature'] = generate_signature(prepared_request.body, webhook.secret)
-
-    # Send the request
-    with requests.Session() as session:
-        session.verify = webhook.ssl_verification
-        if webhook.ca_file_path:
-            session.verify = webhook.ca_file_path
-        response = session.send(prepared_request, proxies=settings.HTTP_PROXIES)
-
-    if 200 <= response.status_code <= 299:
-        logger.info(f"Request succeeded; response status {response.status_code}")
-        return f"Status {response.status_code} returned, webhook successfully processed."
-    else:
-        logger.warning(f"Request failed; response status {response.status_code}: {response.content}")
-        raise requests.exceptions.RequestException(
-            f"Status {response.status_code} returned with content '{response.content}', webhook FAILED to process."
-        )
+# TODO: Remove in v4.0
+warnings.warn(
+    f"webhooks_worker.process_webhook has been moved to webhooks.send_webhook.",
+    DeprecationWarning
+)