Skip to content

Event Rules

Use Event Rules to run a Script in response to an event, or to react to changes to the plugin's objects.

Running a Script from an Event Rule

Choose Run Script as the action type and select a published Script. The picker includes disabled Scripts so you can prepare a rule before enabling them.

What the script receives

Input Value
data The rule's Data field merged with the event payload.
self.event The JSON-safe event context described below.
self.request A stripped copy of the triggering request, without uploaded files. None when the event has no request.

Event Rule input is passed directly to run() without validation through the Script's form. Form defaults are not applied, and object identifiers remain plain values. Check the fields and types your Script requires.

Event-driven runs always commit. A dry-run option is not available.

Each run is queued as a Job. Open the Script's Jobs tab under Scripts > Scripts to follow its status and results.

What self.event carries

Read the event context from self.event. It is None for a manually requested run, so check it before use. See Authoring.

Key Value
event_type The event type, such as object_created or job_completed.
event_rule The rule's name.
event_rule_id The rule's numeric ID.
object_type The object's type as app_label.model, or None when the event has no object.
object_id The object's numeric ID, or None.
snapshots The before and after representations captured by NetBox, when available.

The user and HTTP request are not included in this stored payload. They reach the Script separately through its request context.

What is refused, and when

Some Script states are checked when saving the rule, and others when it fires.

State When it is reported
Retired When saving the rule. A later activation can republish the class and lift its retirement.
Disabled When the rule fires. The reason is logged and no run is queued.
Its Project is disabled, or serves no revision When the rule fires. The reason is logged and no run is queued.

Rules may reference temporarily disabled Scripts or Projects and start working when those conditions are resolved. One rule's inability to run its Script does not stop the other rules responding to that event.

Permissions

The Event Rule authorizes the run, not the permissions of the user who triggered the event. Restrict who can create or edit Event Rules, because those rules choose which Scripts run. See Permissions for plugin action permissions.

Practical examples

These examples report device changes in the Job log. Upload and activate each Script as described in Uploading, then create its rule under Operations > Integrations > Event Rules. See Event Rule execution permissions before granting access to manage these rules.

With Conditions empty, each rule queues a Job for every selected device event, and the Script decides what to report. NetBox's snapshot conditions can filter events before queuing a Job. For the status example, use {"attr": "status", "op": "changed"} to skip unrelated updates. Keep the Script's checks: changed can also match an update without a prechange snapshot.

Snapshots describe the event, not the object's current state. They use model values: status is a string such as active, and tags is a list of tag names. A create event normally has no prechange snapshot, and a delete event has no postchange snapshot. An update needs both snapshots to compare values. An update has no prechange snapshot if the code that saved it did not call snapshot() before saving. This can happen in Scripts or when NetBox saves devices installed in a parent device's bays.

Report device status changes

This Script reports creation and deletion, and skips updates where the status did not change. It identifies deleted devices by their recorded ID without looking them up in the database.

Setting Value
Name Report device status changes
Object types DCIM > Device
Enabled Yes
Event types Object created, Object updated, Object deleted
Conditions Leave empty
Action type Run Script
Script Report device status changes
Action data Leave empty
from netbox_scripts import Script


class ReportDeviceStatus(Script):
    class Meta:
        name = 'Report device status changes'
        notifications_default = 'on_failure'

    def run(self, data, commit):
        event = self.event
        if event is None:
            self.log_info('No event context. Nothing to report.')
            return
        if event.get('object_type') != 'dcim.device':
            return

        device_id = event['object_id']
        event_type = event.get('event_type')
        if event_type == 'object_created':
            self.log_info(f'Device {device_id} was created.')
            return
        if event_type == 'object_deleted':
            self.log_info(f'Device {device_id} was deleted.')
            return
        if event_type != 'object_updated':
            return

        snapshots = event.get('snapshots') or {}
        before = snapshots.get('prechange')
        after = snapshots.get('postchange')
        if before is None or after is None or 'status' not in before or 'status' not in after:
            self.log_warning('Status snapshots are incomplete. Skipping this event.')
            return
        if before['status'] == after['status']:
            return

        self.log_info(f'Device {device_id}: status changed from {before["status"]} to {after["status"]}.')

Report a tag being added or removed

This Script reports changes to membership of the monitored tag. Replace monitored with the exact tag name you use. Changes to other tags are ignored. A device created with the tag is not reported, because the rule reacts only to updates.

Setting Value
Name Report monitoring tag changes
Object types DCIM > Device
Enabled Yes
Event types Object updated
Conditions Leave empty
Action type Run Script
Script Report monitoring tag changes
Action data Leave empty
from netbox_scripts import Script


class ReportMonitoringTag(Script):
    class Meta:
        name = 'Report monitoring tag changes'
        notifications_default = 'on_failure'

    def run(self, data, commit):
        event = self.event
        if event is None:
            self.log_info('No event context. Nothing to report.')
            return
        if event.get('object_type') != 'dcim.device' or event.get('event_type') != 'object_updated':
            return

        snapshots = event.get('snapshots') or {}
        before = snapshots.get('prechange')
        after = snapshots.get('postchange')
        if before is None or after is None or 'tags' not in before or 'tags' not in after:
            self.log_warning('Tag snapshots are incomplete. Skipping this event.')
            return

        tag_name = 'monitored'
        was_monitored = tag_name in before['tags']
        is_monitored = tag_name in after['tags']
        if was_monitored == is_monitored:
            return

        change = 'added' if is_monitored else 'removed'
        self.log_info(f'Device {event["object_id"]}: tag {tag_name!r} was {change}.')

A missing snapshot or field does not mean an empty tag list. Skipping incomplete snapshots avoids reporting a change that cannot be established. An empty list, however, is valid and allows the first tag addition or last tag removal to be detected.

Adapting the examples

The examples only report events. Repeated delivery can repeat a log entry, but does not modify devices or call an external service. Each matching rule queues its own run, so multiple rules can report the same change more than once.

Before adding a write, fetch the live object and check its current state. It may have changed again or been deleted while the Job was waiting. Use snapshots to understand the original change. Do not reconstruct it from a current database query.

Return without saving when the intended state is already present. Otherwise, call the object's snapshot() method before changing any fields, so change logging and subsequent events include the original values. Committed Scripts can trigger further Event Rules, so ensure any update you make no longer matches the same transition check. Comparing snapshots alone does not prevent duplicate actions: the same event still contains the same change on a repeat run. For external actions, use an idempotent operation or the service's supported deduplication mechanism.

Log only the identifiers and selected values needed to explain the action. Anyone who can view the Job can read its logs, so do not log complete snapshots, request data or secrets.

Scripts as event sources

The plugin's four object types can be Event Rule sources, like Devices or IP addresses.

Object A rule can react to
Script Project A Project being created, changed or deleted.
Script Project Revision A revision appearing.
Script File A declaration being added, changed or removed.
Script A Script appearing, retiring, or being enabled or disabled.

Webhooks use the object's REST representation. A revision's stored manifest and Script File snapshot are not included.

Changes made through UI or REST requests can trigger matching rules. A successful committed Script run also publishes its queued object-change events, even without a request. Dry runs and failed runs do not publish those events.

Background staging, validation, migration and job-driven activation do not deliver object-change events. Follow their outcomes through revision status and migration Job results. Job start and completion events are separate.