rXg Notifications and Event driven script execution
February 10, 2025
Event Notification Mechanism
The event notification can be achieved via Notification Actions in the ‘Services::Notifications’ scaffold, where specific events are monitored and a backend script can be then triggered to perform specific actions. As an example for this KB, a mechanism is configured whereby a change in the PING Target state (up/down) triggers the execution of a Ruby script sending SNMP traps with specific structure to a pre-configured trap receiver.
The event notification mechanism relies on two elements, i.e., a Notification Action and an associated Backend Script. Whenever a condition for the configured Notification Action is triggered, the selected Backend Script is executed, providing a very flexible mechanism to enrich the already existing notification capabilities of the rXg platform.
Create a Notification Action
To create a new Notification Action, the ‘Services::Notifications::Notification Actions’ scaffold is used, and a following entry is created:
- ‘Name’ field contains an arbitrary name for this particular notification action entry,
- ‘Enabled’ field is checked, to make sure the action is indeed active
- ‘Event Type’ is configured as ‘Watch Scaffold’, which essentially watches and notifies the action about any changes in the given scaffold
- ‘Watch Model’ indicates which of the system scaffolds are to be watched for changes - in this case, the ‘Ping Target’ scaffold is selected
- ‘Watch Create’ and ‘Watch Delete’ fields are marked, in which case both the up and down events for each and every Ping Target is generated
All other fields are left in their default state and not modified.
Once created, a new entry in the ‘Services::Notifications::Notification Actions’ scaffold becomes visible, as shown below.
The given action can be disabled, if needed, without being permanently deleted. Also, it is possible to track the execution of the given action using the ‘Event Logs’ action, which will display any execution errors for the given script, when such errors take place.
There are many event types that can be created, including periodic execution, manual execution, scaffold status changes, trigger on general error conditions, threshold events, and others. Available event configuration options depend on the given event type. For example, for a periodic event, the period, start and end times, as well as random delay can be set, as shown below
Create a Backend Script
To create a new Backend Script, the ‘Services::Notifications::Backend Scripts’ scaffold is used, and a following entry is created with the following fields to be filled in:
- ‘Name’ is an arbitrary name for the backend script,
- ‘Notification Actions’ indicates which of the available actions this script is tied to; in this case, the previously created ‘PING Target SNMP trap’ is selected
- ‘Body’ is filled in with the target execution script, which in this case sends a SNMPv1 trap to a specific target, with an indication of whether the given PING Target is online or offline, depending on the status of the given ping_target. The script uses Ruby, and no other scripting languages are supported at this time.
Once created, a new entry in the ‘Services::Notifications::Backend Scripts’ scaffold becomes visible, as shown below.
Note that it is possible to test the given created backend script, using the ‘Trigger’ action associated with the given script. However, when internal rXg objects are used in the script (‘ping_target’ in the example used in this KB), the ‘Trigger’ action will result in execution errors due to the object missing in the scope. Internal rXg objects become available only when triggered through the associated Notification Action.
For reference, the structure of the ping_target object is as follows, showing a number of fields which can be used for internal scripting purposes. Individual objects can be previewed in the rXg shell using the Ruby console.
#<PingTarget:0x000038a380ef50b8
id: 5,
name: "9.9.9.9",
target: "9.9.9.9",
timeout: 0.3e1,
attempts: 6,
online: true,
note: nil,
created_by: "adminuser",
updated_by: "rxgd(PingMonitor)",
created_at: Thu, 30 Jan 2025 09:24:53.456740000 PST -08:00,
updated_at: Thu, 30 Jan 2025 10:40:38.619050000 PST -08:00,
cluster_node_id: nil,
scratch: nil,
rtt_tolerance: nil,
jitter_tolerance: nil,
packet_loss_tolerance: nil,
wlan_id: nil,
interval: 0.3e1,
psk_override: nil,
wireguard_tunnel_id: nil,
traceroute_interval: nil,
fom_configurable: false>
Testing Process
To trigger the condition from the rXg shell without having to wait for the Ping Target timeout, execute the following command set in the repl (Pearl) console.
my $pt = Rxg::ActiveRecord::PingTarget->last(); $pt->flipBooleanAttribute('online'); $pt->saveAndTrigger(); Rxg::ActiveRecord->commitDeferredSql()
Every time the script is executed, the last Ping Target state is flipped and SNMP traps are generated, as shown on SNMP trap collector below. The linkUp/linkDown event is showing up in the log in a quick succession.
#00:17:46.091437 08:62:66:48:67:83 > bc:24:11:01:8f:af, ethertype IPv4 (0x0800), length 87: (tos 0x0, ttl 64, id 24299, offset 0, flags [none], proto UDP (17), length 73) 192.168.150.38.30776 > 192.168.150.4.162: [udp sum ok] { SNMPv1 { Trap(30) .1.3.6.1.4.1.57404 9.9.9.9 linkDown[specific-trap(42)!=0] 1738369066 } } #00:18:35.113910 08:62:66:48:67:83 > bc:24:11:01:8f:af, ethertype IPv4 (0x0800), length 87: (tos 0x0, ttl 64, id 37016, offset 0, flags [none], proto UDP (17), length 73) 192.168.150.38.48770 > 192.168.150.4.162: [udp sum ok] { SNMPv1 { Trap(30) .1.3.6.1.4.1.57404 9.9.9.9 linkUp[specific-trap(42)!=0] 1738369115 } } #00:18:47.357938 08:62:66:48:67:83 > bc:24:11:01:8f:af, ethertype IPv4 (0x0800), length 87: (tos 0x0, ttl 64, id 57315, offset 0, flags [none], proto UDP (17), length 73) 192.168.150.38.29247 > 192.168.150.4.162: [udp sum ok] { SNMPv1 { Trap(30) .1.3.6.1.4.1.57404 9.9.9.9 linkDown[specific-trap(42)!=0] 1738369127 } } #00:18:49.443970 08:62:66:48:67:83 > bc:24:11:01:8f:af, ethertype IPv4 (0x0800), length 87: (tos 0x0, ttl 64, id 24438, offset 0, flags [none], proto UDP (17), length 73) 192.168.150.38.33871 > 192.168.150.4.162: [udp sum ok] { SNMPv1 { Trap(30) .1.3.6.1.4.1.57404 9.9.9.9 linkUp[specific-trap(42)!=0] 1738369129 } } #00:18:53.628644 08:62:66:48:67:83 > bc:24:11:01:8f:af, ethertype IPv4 (0x0800), length 87: (tos 0x0, ttl 64, id 37059, offset 0, flags [none], proto UDP (17), length 73) 192.168.150.38.26210 > 192.168.150.4.162: [udp sum ok] { SNMPv1 { Trap(30) .1.3.6.1.4.1.57404 9.9.9.9 linkDown[specific-trap(42)!=0] 1738369133 } }
The recorded packets indicate that the rXg (at 192.168.150.38 in this case) sends SNMP traps towards the collector at 192.168.150.4 with the appropriate structure, changing between the target up and down states, as expected.