Event Rule Action Data passed to Script #9122

Closed
opened 2025-12-29 20:45:54 +01:00 by adam · 18 comments
Owner

Originally created by @renatoalmeidaoliveira on GitHub (Jan 22, 2024).

Originally assigned to: @arthanson on GitHub.

NetBox version

v3.7.0

Feature type

Change to existing functionality

Proposed functionality

Currently EventRules passes a serialized version of the model as data to the linked Script, I think it would be better if the Action Data was processed like the Body Template of Webhoocks and passed to the Script.

Use case

It would allow users to build Script to react NetBox changes with the change context, currently the user cannot get directly the changelog. And by passing a parsed data with Event Data gives the plugin developer a lot of flexibility to build automations

Database changes

None

External dependencies

None

Originally created by @renatoalmeidaoliveira on GitHub (Jan 22, 2024). Originally assigned to: @arthanson on GitHub. ### NetBox version v3.7.0 ### Feature type Change to existing functionality ### Proposed functionality Currently EventRules passes a serialized version of the model as data to the linked Script, I think it would be better if the Action Data was processed like the Body Template of Webhoocks and passed to the Script. ### Use case It would allow users to build Script to react NetBox changes with the change context, currently the user cannot get directly the changelog. And by passing a parsed data with Event Data gives the plugin developer a lot of flexibility to build automations ### Database changes None ### External dependencies None
adam closed this issue 2025-12-29 20:45:54 +01:00
Author
Owner

@jeremystretch commented on GitHub (Jan 22, 2024):

I don't think we have a mechanism in place within a script right now to accept this data. Could you please expand your proposal above to specify exactly how a script would receive this data, in addition to the form data it currently accepts?

@jeremystretch commented on GitHub (Jan 22, 2024): I don't think we have a mechanism in place within a script right now to accept this data. Could you please expand your proposal above to specify exactly how a script would receive this data, in addition to the form data it currently accepts?
Author
Owner

@renatoalmeidaoliveira commented on GitHub (Jan 22, 2024):

In the current implementation the EventRule passes a serialized version of the instance as data to the script., so it isn't possible to pass any input to the Script using the EventRule.
For example:
The user wants that for every interface change a Script runs and perform Napalm checks on the interface, to implement that the user might need the Interface, the Device and the changes performed by the end user.
But in the current implementation is only receives the changed object and the way it is passed to the Script it can't even be used as Script Inputs.
The feature request aims to give the user an interface to setup what data should be passed to the Script when the changes happens

@renatoalmeidaoliveira commented on GitHub (Jan 22, 2024): In the current implementation the EventRule passes a serialized version of the instance as data to the script., so it isn't possible to pass any input to the Script using the EventRule. For example: The user wants that for every interface change a Script runs and perform Napalm checks on the interface, to implement that the user might need the Interface, the Device and the changes performed by the end user. But in the current implementation is only receives the changed object and the way it is passed to the Script it can't even be used as Script Inputs. The feature request aims to give the user an interface to setup what data should be passed to the Script when the changes happens
Author
Owner

@renatoalmeidaoliveira commented on GitHub (Jan 22, 2024):

In run_script data is passed as a dict where the keys are the Script Input, but when the Job is schedules in process_event_rules it passed as built in enqueue_object, (the serialized model) and that way it ain't gonna pass the expected dict to the Script since its expecting a dict with keys as the Script Inputs.
I think that the Action Data (or any other field) could be used similar as the Templete body of webhooks using something like rende_body

@renatoalmeidaoliveira commented on GitHub (Jan 22, 2024): In [run_script](https://github.com/netbox-community/netbox/blob/1d15ba56b90e253eca395e1f45c9d04128a46e69/netbox/extras/scripts.py#L475) data is passed as a dict where the keys are the Script Input, but when the Job is schedules in [process_event_rules](https://github.com/netbox-community/netbox/blob/1d15ba56b90e253eca395e1f45c9d04128a46e69/netbox/extras/events.py#L74) it passed as built in [enqueue_object](https://github.com/netbox-community/netbox/blob/1d15ba56b90e253eca395e1f45c9d04128a46e69/netbox/extras/events.py#L52C5-L52C19), (the serialized model) and that way it ain't gonna pass the expected dict to the Script since its expecting a dict with keys as the Script Inputs. I think that the Action Data (or any other field) could be used similar as the Templete body of webhooks using something like [rende_body](https://github.com/netbox-community/netbox/blob/1d15ba56b90e253eca395e1f45c9d04128a46e69/netbox/extras/models/models.py#L299)
Author
Owner

@DanSheps commented on GitHub (Jan 24, 2024):

I think I get what this is saying.

Basically, you can define your data template for what is passed to a script.

This is originally what I thought "action data" wass for.

@DanSheps commented on GitHub (Jan 24, 2024): I think I get what this is saying. Basically, you can define your data template for what is passed to a script. This is originally what I thought "action data" wass for.
Author
Owner

@renatoalmeidaoliveira commented on GitHub (Jan 24, 2024):

@DanSheps I thougt that it was the purpose of "action data" too.
And when I look to the rest of the implementation it makes sense for me change the context injected to the template body in the webhook to whatever the user wants to setup inside the action data

@renatoalmeidaoliveira commented on GitHub (Jan 24, 2024): @DanSheps I thougt that it was the purpose of "action data" too. And when I look to the rest of the implementation it makes sense for me change the context injected to the template body in the webhook to whatever the user wants to setup inside the action data
Author
Owner

@jeremystretch commented on GitHub (Feb 14, 2024):

I've assigned this to @renatoalmeidaoliveira with the understanding that its scope is limited to passing the action_data associated with an event rule directly to the script being executed, as if it were user input.

@jeremystretch commented on GitHub (Feb 14, 2024): I've assigned this to @renatoalmeidaoliveira with the understanding that its scope is limited to passing the `action_data` associated with an event rule directly to the script being executed, as if it were user input.
Author
Owner

@jeremystretch commented on GitHub (May 28, 2024):

@renatoalmeidaoliveira are you still planning to work on this?

@jeremystretch commented on GitHub (May 28, 2024): @renatoalmeidaoliveira are you still planning to work on this?
Author
Owner

@renatoalmeidaoliveira commented on GitHub (May 28, 2024):

@jeremystretch yes, I've talked with @arthanson in slack and waiting for some guidance to move on

@renatoalmeidaoliveira commented on GitHub (May 28, 2024): @jeremystretch yes, I've talked with @arthanson in slack and waiting for some guidance to move on
Author
Owner

@renatoalmeidaoliveira commented on GitHub (May 28, 2024):

From the Script Developer point of view I think that Action Data should be passed to the Script the same way as the Input Form and REST API.
That means the only sending the blob JSON isn't a good idea

@renatoalmeidaoliveira commented on GitHub (May 28, 2024): From the Script Developer point of view I think that Action Data should be passed to the Script the same way as the Input Form and REST API. That means the only sending the blob JSON isn't a good idea
Author
Owner

@jeffgdotorg commented on GitHub (Jul 22, 2024):

@renatoalmeidaoliveira I notice your PR got robo-closed. Do you anticipate having time to work on it soon, or should I let it go?

@jeffgdotorg commented on GitHub (Jul 22, 2024): @renatoalmeidaoliveira I notice your PR got robo-closed. Do you anticipate having time to work on it soon, or should I let it go?
Author
Owner

@misch42 commented on GitHub (Aug 16, 2024):

I'd like to see that feature, too.

@misch42 commented on GitHub (Aug 16, 2024): I'd like to see that feature, too.
Author
Owner

@renatoalmeidaoliveira commented on GitHub (Aug 17, 2024):

@jeffgdotorg I think we need to discuss a bit more about that PR, because the maintainer team wants the sent the data field as is without Jinja2 processing but IMO that isn't very usefull for the end user since if he wanna a static field he could just hard code in the Script.
And IMO the Script interface should remain the same independent of what calls it meaning that data passed to the script should be processed and parsed by the Script form.
I have time to work on that PR, but I would like to wait for a consense before giving more effort to it.

@renatoalmeidaoliveira commented on GitHub (Aug 17, 2024): @jeffgdotorg I think we need to discuss a bit more about that PR, because the maintainer team wants the sent the data field as is without Jinja2 processing but IMO that isn't very usefull for the end user since if he wanna a static field he could just hard code in the Script. And IMO the Script interface should remain the same independent of what calls it meaning that data passed to the script should be processed and parsed by the Script form. I have time to work on that PR, but I would like to wait for a consense before giving more effort to it.
Author
Owner

@molusk commented on GitHub (Nov 6, 2024):

I can see at least 2 reasons to do it even if the parameters are static :

  • be able to reuse a script not meant to be triggered by event rules : they may require parameters that are available for scheduling, being able to pass them in the event_data could be useful.
  • be able to handle event types without multiplying scripts and only multiplying event rules until event_type is included by default in the parameters passed to the script.

Today I have to maintain 2 almost identical scripts, the first one to handle objects creations and modifications and another one to handle deletions. A simple parameter in action data passed to the script would be a lot better.

Of course, dynamic parameters could be a plus but we can also start with static ones and negotiate later for Jinja2 templates.

@molusk commented on GitHub (Nov 6, 2024): I can see at least 2 reasons to do it even if the parameters are static : - be able to reuse a script not meant to be triggered by event rules : they may require parameters that are available for scheduling, being able to pass them in the event_data could be useful. - be able to handle event types without multiplying scripts and only multiplying event rules until event_type is included by default in the parameters passed to the script. Today I have to maintain 2 almost identical scripts, the first one to handle objects creations and modifications and another one to handle deletions. A simple parameter in action data passed to the script would be a lot better. Of course, dynamic parameters could be a plus but we can also start with static ones and negotiate later for Jinja2 templates.
Author
Owner

@jeremystretch commented on GitHub (Mar 14, 2025):

@renatoalmeidaoliveira do you still want to work on this? It seems to have gone stale.

@jeremystretch commented on GitHub (Mar 14, 2025): @renatoalmeidaoliveira do you still want to work on this? It seems to have gone stale.
Author
Owner

@renatoalmeidaoliveira commented on GitHub (Apr 10, 2025):

In the current implementation, the run_script method receives different data according to the way it was called. For example, using this very simple script:

from extras.scripts import Script, ObjectVar
from ipam.models import IPAddress

class BranchTesting(Script):

    ip_address = ObjectVar(
        model=IPAddress,
        description='IP Address to test',
        required=True,
    )

    def run(self, data, commit):
        return f"data is {data}"

When the script is executed by a user in the UI, the output is something like this depending on the selected ip_address:

data is {'ip_address': <IPAddress: 172.16.0.1/24>}

But when the same script is executed by an EventRule, the output is like this:

data is {'sample_data': 'test', 'id': 31, 'url': '/api/ipam/ip-addresses/31/', 'display_url': '/ipam/ip-addresses/31/', 'display': '172.16.0.1/24', 'family': {'value': 4, 'label': 'IPv4'}, 'address': '172.16.0.1/24', 'vrf': {'id': 1, 'url': '/api/ipam/vrfs/1/', 'display': 'Alpha (65000:100)', 'name': 'Alpha', 'rd': '65000:100', 'description': ''}, 'tenant': None, 'status': {'value': 'active', 'label': 'Active'}, 'role': None, 'assigned_object_type': None, 'assigned_object_id': None, 'assigned_object': None, 'nat_inside': None, 'nat_outside': [], 'dns_name': '', 'description': 'Event Test', 'comments': '', 'tags': [], 'custom_fields': {}, 'created': '2022-04-08T00:25:21.668000Z', 'last_updated': '2025-04-10T02:57:41.975820Z'}

That difference in both methods makes the script very particular to the use case. I mean, a script built to be used in the UI by a user cannot be reused for an EventRule.

And when the user writes a CustomScript for an EventRule, the data form with all ORM models directly available is not accessible, making it more difficult to write a CustomScript.

Another topic related to the Action Data field is that, in the current implementation, it is hardcoded by the user. In other words, it isn't possible to change that data based on the model or whatever the user wants. Since it's a static value, IMO, it is the same as adding a hardcoded dictionary inside the CustomScript.

So, IMO, that field should be Jinja-processed, allowing the user to inject dynamic data into their scripts according to the event and also parsed by the CustomScript form. That way, the same script could be used by a user inside the UI or by an EventRule and produce the same result in both cases.

@renatoalmeidaoliveira commented on GitHub (Apr 10, 2025): In the current implementation, the `run_script` method receives different data according to the way it was called. For example, using this very simple script: ```python from extras.scripts import Script, ObjectVar from ipam.models import IPAddress class BranchTesting(Script): ip_address = ObjectVar( model=IPAddress, description='IP Address to test', required=True, ) def run(self, data, commit): return f"data is {data}" ``` When the script is executed by a user in the UI, the output is something like this depending on the selected `ip_address`: ``` data is {'ip_address': <IPAddress: 172.16.0.1/24>} ``` But when the same script is executed by an `EventRule`, the output is like this: ``` data is {'sample_data': 'test', 'id': 31, 'url': '/api/ipam/ip-addresses/31/', 'display_url': '/ipam/ip-addresses/31/', 'display': '172.16.0.1/24', 'family': {'value': 4, 'label': 'IPv4'}, 'address': '172.16.0.1/24', 'vrf': {'id': 1, 'url': '/api/ipam/vrfs/1/', 'display': 'Alpha (65000:100)', 'name': 'Alpha', 'rd': '65000:100', 'description': ''}, 'tenant': None, 'status': {'value': 'active', 'label': 'Active'}, 'role': None, 'assigned_object_type': None, 'assigned_object_id': None, 'assigned_object': None, 'nat_inside': None, 'nat_outside': [], 'dns_name': '', 'description': 'Event Test', 'comments': '', 'tags': [], 'custom_fields': {}, 'created': '2022-04-08T00:25:21.668000Z', 'last_updated': '2025-04-10T02:57:41.975820Z'} ``` That difference in both methods makes the script very particular to the use case. I mean, a script built to be used in the UI by a user cannot be reused for an `EventRule`. And when the user writes a `CustomScript` for an `EventRule`, the `data` form with all ORM models directly available is not accessible, making it more difficult to write a `CustomScript`. Another topic related to the `Action Data` field is that, in the current implementation, it is hardcoded by the user. In other words, it isn't possible to change that data based on the model or whatever the user wants. Since it's a static value, IMO, it is the same as adding a hardcoded dictionary inside the `CustomScript`. So, IMO, that field should be Jinja-processed, allowing the user to inject dynamic data into their scripts according to the event and also parsed by the `CustomScript` form. That way, the same script could be used by a user inside the UI or by an `EventRule` and produce the same result in both cases.
Author
Owner

@llamafilm commented on GitHub (Aug 29, 2025):

Would it make sense for the custom script to receive all same data as a webhook? The CustomScript model doesn't need any changes, because everything can be contained in the data object so it looks like this:

{
    "event": "updated",
    "timestamp": "2025-08-28T22:45:17.406545+00:00",
    "model": "ipaddress",
    "username": "elliott",
    "request_id": "6b6d9095-254b-45fc-982c-0f10ad07809a",
    "model": { ... all properties as `data` is now ...},
    "snapshots": {
        "prechange": { ... },
        "postchange": { ... },
    }
}
@llamafilm commented on GitHub (Aug 29, 2025): Would it make sense for the custom script to receive all same data as a webhook? The `CustomScript` model doesn't need any changes, because everything can be contained in the `data` object so it looks like this: ``` { "event": "updated", "timestamp": "2025-08-28T22:45:17.406545+00:00", "model": "ipaddress", "username": "elliott", "request_id": "6b6d9095-254b-45fc-982c-0f10ad07809a", "model": { ... all properties as `data` is now ...}, "snapshots": { "prechange": { ... }, "postchange": { ... }, } } ```
Author
Owner

@arthanson commented on GitHub (Oct 16, 2025):

The comments are fairly misleading in this issue. If you run the script directly you get:

{
    "log": [],
    "output": "data is {'ip_address': <IPAddress: 172.16.0.1/24>}",
    "tests": {}
}

If you run it from an Event Rule you get the following:

{
    "log": [],
    "output": "data is {'ip_address': 31, 'id': 24, 'url': '/api/dcim/sites/24/', 'display_url': '/dcim/sites/24/', 'display': 'Butler Communications', 'name': 'Butler Communications', 'slug': 'ncsu-128', 'status': {'value': 'active', 'label': 'Active'}, 'region': {'id': 40, 'url': '/api/dcim/regions/40/', 'display': 'North Carolina', 'name': 'North Carolina', 'slug': 'us-nc', 'description': '', 'site_count': 0, '_depth': 2}, 'group': None, 'tenant': {'id': 13, 'url': '/api/tenancy/tenants/13/', 'display': 'NC State University', 'name': 'NC State University', 'slug': 'nc-state', 'description': ''}, 'facility': 'BUT', 'time_zone': None, 'description': 'asdf', 'physical_address': '3210 Faucette Dr., Raleigh, NC 27607', 'shipping_address': '', 'latitude': None, 'longitude': None, 'comments': '', 'asns': [], 'tags': [{'id': 7, 'url': '/api/extras/tags/7/', 'display_url': '/extras/tags/7/', 'display': 'Golf', 'name': 'Golf', 'slug': 'golf', 'color': '673ab7'}, {'id': 12, 'url': '/api/extras/tags/12/', 'display_url': '/extras/tags/12/', 'display': 'Lima', 'name': 'Lima', 'slug': 'lima', 'color': '009688'}, {'id': 24, 'url': '/api/extras/tags/24/', 'display_url': '/extras/tags/24/', 'display': 'X-ray', 'name': 'X-ray', 'slug': 'x-ray', 'color': '9e9e9e'}], 'custom_fields': {}, 'created': '2021-04-02T00:00:00Z', 'last_updated': '2025-10-15T21:17:43.035621Z'}",
    "tests": {}
}

The EventRule is passing both the action_data and the object that caused the EventRule (in this case I was using Update Site) - so most of the extra data is correct. The only issue I see is that in the script run case you are getting ip_address pointing to the actual IPAddress object, whereas when you run It from an EventRule you are getting just the straight data you typed into action_data (so not de-referenced into an object).

The work here will be to make that consistent. However in the case of the EventRule you will still get the extra data that is from the actual Event (that is correct).

@arthanson commented on GitHub (Oct 16, 2025): The comments are fairly misleading in this issue. If you run the script directly you get: ``` { "log": [], "output": "data is {'ip_address': <IPAddress: 172.16.0.1/24>}", "tests": {} } ``` If you run it from an Event Rule you get the following: ``` { "log": [], "output": "data is {'ip_address': 31, 'id': 24, 'url': '/api/dcim/sites/24/', 'display_url': '/dcim/sites/24/', 'display': 'Butler Communications', 'name': 'Butler Communications', 'slug': 'ncsu-128', 'status': {'value': 'active', 'label': 'Active'}, 'region': {'id': 40, 'url': '/api/dcim/regions/40/', 'display': 'North Carolina', 'name': 'North Carolina', 'slug': 'us-nc', 'description': '', 'site_count': 0, '_depth': 2}, 'group': None, 'tenant': {'id': 13, 'url': '/api/tenancy/tenants/13/', 'display': 'NC State University', 'name': 'NC State University', 'slug': 'nc-state', 'description': ''}, 'facility': 'BUT', 'time_zone': None, 'description': 'asdf', 'physical_address': '3210 Faucette Dr., Raleigh, NC 27607', 'shipping_address': '', 'latitude': None, 'longitude': None, 'comments': '', 'asns': [], 'tags': [{'id': 7, 'url': '/api/extras/tags/7/', 'display_url': '/extras/tags/7/', 'display': 'Golf', 'name': 'Golf', 'slug': 'golf', 'color': '673ab7'}, {'id': 12, 'url': '/api/extras/tags/12/', 'display_url': '/extras/tags/12/', 'display': 'Lima', 'name': 'Lima', 'slug': 'lima', 'color': '009688'}, {'id': 24, 'url': '/api/extras/tags/24/', 'display_url': '/extras/tags/24/', 'display': 'X-ray', 'name': 'X-ray', 'slug': 'x-ray', 'color': '9e9e9e'}], 'custom_fields': {}, 'created': '2021-04-02T00:00:00Z', 'last_updated': '2025-10-15T21:17:43.035621Z'}", "tests": {} } ``` The EventRule is passing both the action_data and the object that caused the EventRule (in this case I was using Update Site) - so most of the extra data is correct. The only issue I see is that in the script run case you are getting `ip_address` pointing to the actual IPAddress object, whereas when you run It from an EventRule you are getting just the straight data you typed into action_data (so not de-referenced into an object). The work here will be to make that consistent. However in the case of the EventRule you will still get the extra data that is from the actual Event (that is correct).
Author
Owner

@arthanson commented on GitHub (Oct 21, 2025):

After reviewing this, I’m going to close the FR.

Scripts run via the UI and those triggered from event rules are typically designed to handle different kinds of workflows, and forcing consistent behavior between the two would break backward compatibility for existing scripts.

In practice, this can be handled cleanly and easily at the script level by checking the parameter type—whether it’s already an object or just an ID—and handling each case appropriately.

@arthanson commented on GitHub (Oct 21, 2025): After reviewing this, I’m going to close the FR. Scripts run via the UI and those triggered from event rules are typically designed to handle different kinds of workflows, and forcing consistent behavior between the two would break backward compatibility for existing scripts. In practice, this can be handled cleanly and easily at the script level by checking the parameter type—whether it’s already an object or just an ID—and handling each case appropriately.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#9122