Fixes #18222: Include action data from event rule in webhook and custom script data

This commit is contained in:
Jeremy Stretch 2024-12-27 12:17:17 -05:00
parent f03489f58e
commit 10748edc3a
3 changed files with 34 additions and 8 deletions

View File

@ -10,7 +10,7 @@ See the [event rules documentation](../../features/event-rules.md) for more inf
A unique human-friendly name. A unique human-friendly name.
### Content Types ### Object Types
The type(s) of object in NetBox that will trigger the rule. The type(s) of object in NetBox that will trigger the rule.
@ -38,3 +38,15 @@ The event types which will trigger the rule. At least one event type must be sel
### Conditions ### Conditions
A set of [prescribed conditions](../../reference/conditions.md) against which the triggering object will be evaluated. If the conditions are defined but not met by the object, no action will be taken. An event rule that does not define any conditions will _always_ trigger. A set of [prescribed conditions](../../reference/conditions.md) against which the triggering object will be evaluated. If the conditions are defined but not met by the object, no action will be taken. An event rule that does not define any conditions will _always_ trigger.
### Action Type
The type of action to take when the rule triggers. This must be one of the following choices:
* Webhook
* Custom script
* Notification
### Action Data
An optional dictionary of JSON data to pass when executing the rule. This can be useful to include additional context data, e.g. when transmitting a webhook.

View File

@ -90,6 +90,10 @@ def process_event_rules(event_rules, object_type, event_type, data, username=Non
if not event_rule.eval_conditions(data): if not event_rule.eval_conditions(data):
continue continue
# Compile event data
event_data = event_rule.action_data or {}
event_data.update(data)
# Webhooks # Webhooks
if event_rule.action_type == EventRuleActionChoices.WEBHOOK: if event_rule.action_type == EventRuleActionChoices.WEBHOOK:
@ -102,7 +106,7 @@ def process_event_rules(event_rules, object_type, event_type, data, username=Non
"event_rule": event_rule, "event_rule": event_rule,
"model_name": object_type.model, "model_name": object_type.model,
"event_type": event_type, "event_type": event_type,
"data": data, "data": event_data,
"snapshots": snapshots, "snapshots": snapshots,
"timestamp": timezone.now().isoformat(), "timestamp": timezone.now().isoformat(),
"username": username, "username": username,
@ -130,7 +134,7 @@ def process_event_rules(event_rules, object_type, event_type, data, username=Non
instance=event_rule.action_object, instance=event_rule.action_object,
name=script.name, name=script.name,
user=user, user=user,
data=data data=event_data
) )
# Notification groups # Notification groups
@ -138,8 +142,8 @@ def process_event_rules(event_rules, object_type, event_type, data, username=Non
# Bulk-create notifications for all members of the notification group # Bulk-create notifications for all members of the notification group
event_rule.action_object.notify( event_rule.action_object.notify(
object_type=object_type, object_type=object_type,
object_id=data['id'], object_id=event_data['id'],
object_repr=data.get('display'), object_repr=event_data.get('display'),
event_type=event_type event_type=event_type
) )

View File

@ -50,21 +50,24 @@ class EventRuleTest(APITestCase):
event_types=[OBJECT_CREATED], event_types=[OBJECT_CREATED],
action_type=EventRuleActionChoices.WEBHOOK, action_type=EventRuleActionChoices.WEBHOOK,
action_object_type=webhook_type, action_object_type=webhook_type,
action_object_id=webhooks[0].id action_object_id=webhooks[0].id,
action_data={"foo": 1},
), ),
EventRule( EventRule(
name='Event Rule 2', name='Event Rule 2',
event_types=[OBJECT_UPDATED], event_types=[OBJECT_UPDATED],
action_type=EventRuleActionChoices.WEBHOOK, action_type=EventRuleActionChoices.WEBHOOK,
action_object_type=webhook_type, action_object_type=webhook_type,
action_object_id=webhooks[0].id action_object_id=webhooks[0].id,
action_data={"foo": 2},
), ),
EventRule( EventRule(
name='Event Rule 3', name='Event Rule 3',
event_types=[OBJECT_DELETED], event_types=[OBJECT_DELETED],
action_type=EventRuleActionChoices.WEBHOOK, action_type=EventRuleActionChoices.WEBHOOK,
action_object_type=webhook_type, action_object_type=webhook_type,
action_object_id=webhooks[0].id action_object_id=webhooks[0].id,
action_data={"foo": 3},
), ),
)) ))
for event_rule in event_rules: for event_rule in event_rules:
@ -134,6 +137,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(job.kwargs['event_type'], OBJECT_CREATED) self.assertEqual(job.kwargs['event_type'], OBJECT_CREATED)
self.assertEqual(job.kwargs['model_name'], 'site') self.assertEqual(job.kwargs['model_name'], 'site')
self.assertEqual(job.kwargs['data']['id'], response.data['id']) self.assertEqual(job.kwargs['data']['id'], response.data['id'])
self.assertEqual(job.kwargs['data']['foo'], 1)
self.assertEqual(len(job.kwargs['data']['tags']), len(response.data['tags'])) self.assertEqual(len(job.kwargs['data']['tags']), len(response.data['tags']))
self.assertEqual(job.kwargs['snapshots']['postchange']['name'], 'Site 1') self.assertEqual(job.kwargs['snapshots']['postchange']['name'], 'Site 1')
self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Bar', 'Foo']) self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Bar', 'Foo'])
@ -184,6 +188,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(job.kwargs['event_type'], OBJECT_CREATED) self.assertEqual(job.kwargs['event_type'], OBJECT_CREATED)
self.assertEqual(job.kwargs['model_name'], 'site') self.assertEqual(job.kwargs['model_name'], 'site')
self.assertEqual(job.kwargs['data']['id'], response.data[i]['id']) self.assertEqual(job.kwargs['data']['id'], response.data[i]['id'])
self.assertEqual(job.kwargs['data']['foo'], 1)
self.assertEqual(len(job.kwargs['data']['tags']), len(response.data[i]['tags'])) self.assertEqual(len(job.kwargs['data']['tags']), len(response.data[i]['tags']))
self.assertEqual(job.kwargs['snapshots']['postchange']['name'], response.data[i]['name']) self.assertEqual(job.kwargs['snapshots']['postchange']['name'], response.data[i]['name'])
self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Bar', 'Foo']) self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Bar', 'Foo'])
@ -215,6 +220,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(job.kwargs['event_type'], OBJECT_UPDATED) self.assertEqual(job.kwargs['event_type'], OBJECT_UPDATED)
self.assertEqual(job.kwargs['model_name'], 'site') self.assertEqual(job.kwargs['model_name'], 'site')
self.assertEqual(job.kwargs['data']['id'], site.pk) self.assertEqual(job.kwargs['data']['id'], site.pk)
self.assertEqual(job.kwargs['data']['foo'], 2)
self.assertEqual(len(job.kwargs['data']['tags']), len(response.data['tags'])) self.assertEqual(len(job.kwargs['data']['tags']), len(response.data['tags']))
self.assertEqual(job.kwargs['snapshots']['prechange']['name'], 'Site 1') self.assertEqual(job.kwargs['snapshots']['prechange']['name'], 'Site 1')
self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo']) self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
@ -271,6 +277,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(job.kwargs['event_type'], OBJECT_UPDATED) self.assertEqual(job.kwargs['event_type'], OBJECT_UPDATED)
self.assertEqual(job.kwargs['model_name'], 'site') self.assertEqual(job.kwargs['model_name'], 'site')
self.assertEqual(job.kwargs['data']['id'], data[i]['id']) self.assertEqual(job.kwargs['data']['id'], data[i]['id'])
self.assertEqual(job.kwargs['data']['foo'], 2)
self.assertEqual(len(job.kwargs['data']['tags']), len(response.data[i]['tags'])) self.assertEqual(len(job.kwargs['data']['tags']), len(response.data[i]['tags']))
self.assertEqual(job.kwargs['snapshots']['prechange']['name'], sites[i].name) self.assertEqual(job.kwargs['snapshots']['prechange']['name'], sites[i].name)
self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo']) self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
@ -297,6 +304,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(job.kwargs['event_type'], OBJECT_DELETED) self.assertEqual(job.kwargs['event_type'], OBJECT_DELETED)
self.assertEqual(job.kwargs['model_name'], 'site') self.assertEqual(job.kwargs['model_name'], 'site')
self.assertEqual(job.kwargs['data']['id'], site.pk) self.assertEqual(job.kwargs['data']['id'], site.pk)
self.assertEqual(job.kwargs['data']['foo'], 3)
self.assertEqual(job.kwargs['snapshots']['prechange']['name'], 'Site 1') self.assertEqual(job.kwargs['snapshots']['prechange']['name'], 'Site 1')
self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo']) self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
@ -330,6 +338,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(job.kwargs['event_type'], OBJECT_DELETED) self.assertEqual(job.kwargs['event_type'], OBJECT_DELETED)
self.assertEqual(job.kwargs['model_name'], 'site') self.assertEqual(job.kwargs['model_name'], 'site')
self.assertEqual(job.kwargs['data']['id'], sites[i].pk) self.assertEqual(job.kwargs['data']['id'], sites[i].pk)
self.assertEqual(job.kwargs['data']['foo'], 3)
self.assertEqual(job.kwargs['snapshots']['prechange']['name'], sites[i].name) self.assertEqual(job.kwargs['snapshots']['prechange']['name'], sites[i].name)
self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo']) self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
@ -358,6 +367,7 @@ class EventRuleTest(APITestCase):
self.assertEqual(body['username'], 'testuser') self.assertEqual(body['username'], 'testuser')
self.assertEqual(body['request_id'], str(request_id)) self.assertEqual(body['request_id'], str(request_id))
self.assertEqual(body['data']['name'], 'Site 1') self.assertEqual(body['data']['name'], 'Site 1')
self.assertEqual(body['data']['foo'], 1)
return HttpResponse() return HttpResponse()