Event handler scripts
An event handler script contains the logic that operates on the input JSON string passed
to it by the event_mgr
process each time a state change is detected for
the paths monitored by the event handler instance.
Event handler scripts are executed by a MicroPython interpreter, and therefore have a limited set of modules available in the standard libraries compared to Python. You can use a regular Python interpreter to write the scripts for the event handler as long as you use standard libraries available for MicroPython.
Script input
Whenever a state change is detected for any of the monitored paths defined in the
event handler instance, event handler calls the MicroPython script referenced in the
event handler instance configuration. Event handler calls the
event_handler_main()
function in the script, passing it a JSON
string indicating the current values of the monitored paths, as well as any other
configured options.
Using the example in Event handler configuration, when the
oper-state
for the two links defined in paths
changes to down
, the event_mgr
process generates
the following JSON string and passes it to a script (named
oper-group.py
in the example) as input:
{
"paths": [
{
"path": "interface ethernet-1/55 oper-state",
"value": "down"
},
{
"path": "interface ethernet-1/56 oper-state",
"value": "down"
}
],
"options": {
"required-num-up-links": "1",
"down-links": [
"ethernet-1/1",
"ethernet-1/2",
]
}
}
Script processing
The JSON string generated by the event handler is processed by a MicroPython script.
In the following example, the script takes the state of the links in the supplied
paths
objects, and based on the
required-num-up-links
option:value pair, decides whether the
links in the down-links
option:value pair should be up or down. The
script then generates a response consisting of actions for the SR Linux device to
execute.
import sys
import json
# count_up_uplinks returns the number of monitored uplinks that have oper-state=up
def count_up_uplinks(paths):
up_cnt = 0
for path in paths:
if path.get("value", "down") == "up":
up_cnt = up_cnt + 1
return up_cnt
# required_up_uplinks returns the value of the `required-up-uplinks` option
def required_up_uplinks(options):
return int(options.get("required-up-uplinks", 1))
# main entry function for event handler
def event_handler_main(in_json_str):
# parse input json string passed by event handler
in_json = json.loads(in_json_str)
paths = in_json["paths"]
options = in_json["options"]
num_up_uplinks = count_up_uplinks(paths)
downlinks_new_state = (
"down" if num_up_uplinks < required_up_uplinks(options) else "up"
)
# add `debug="true"` option to event-handler configuration to output parsed parameters
if options.get("debug") == "true":
print(
f"num of required up uplinks = {required_up_uplinks(options)}\n\
detected num of up uplinks = {num_up_uplinks}\n\
downlinks new state = {downlinks_new_state}"
)
response_actions = []
for downlink in options.get("down-links", []):
response_actions.append(
{
"set-ephemeral-path": {
"path": "interface {downlink} oper-state",
"value": downlinks_new_state,
}
}
)
response = {"actions": response_actions}
return json.dumps(response)
This script is an example of using event handler with the SR Linux operational groups feature. See Script processing for details about how each function of this script is processed.
Persistent-data object
The persistent-data
object allows a script to maintain state between
executions; for example, to count the number of times a particular action has been
taken. The persistent-data
object may be included in the JSON
string returned by the script when invoked by event handler.
For example, if a script needs to count the number of times it has taken an action, it can return the following counter:
{
-- snip --
"persistent-data": {
"action-count": 5
}
}
The next time event handler invokes the script, it includes the following as part of the input supplied to the script:
{
-- snip --
"persistent-data": {
"action-count": 5
}
}
If configured to do so, the script can read this input and increment the counter, potentially returning the following:
{
-- snip --
"persistent-data": {
"action-count": 6
}
}
Script output
The MicroPython script returns a single parameter, which is a JSON string with a
structure expected by event handler. The script output contains a list of actions
and persistent-data
objects (if configured), which are passed to
event_mgr
for processing. See Actions for
descriptions of the supported actions.
Using the example from Event handler configuration, if the script determines
that the link in the down-links
option must be brought down, it
sends the following output JSON string to the Event Handler:
{
"actions": [
{
"set-ephemeral-path": {
"path": "/interface ethernet-1/1 oper-state",
"value": "down",
}
}
]
}
Reloading the script
Whenever the configuration for an Event Handler instance changes, or the Event Handler instance is administratively disabled and re-enabled, any running calls to the previous main function are terminated, and the script is reloaded, losing any state information in the process. You can also reload the script manually using a tools command.
For example, the following command reloads the oper-group.py
script:
--{ running }--[ ]--
# tools system event-handler instance oper-group.py reload
Actions
You can specify the following actions in a MicroPython script used with event handler:
set-ephemeral-path
Make an ephemeral change to a state leaf
set-cfg-path
Make a persistent change to the SR Linux configuration
delete-cfg-path
Delete a path in the SR Linux configuration
set-tools-path
Execute an SR Linux tools command
run-script
Issue a command to execute another script
reinvoke-with-delay
Re-invoke the script following a specified delay time
always-execute
Always process an action, regardless of whether the same action was processed previously
The event_mgr
process expects the structure of the output JSON string
from the script to adhere to the following schema:
{
"actions": [
{
"set-ephemeral-path": {
"path": "",
"value": "",
"always-execute": false
}
},
{
"set-cfg-path": {
"path": "",
"json-value": {},
"always-execute": false
}
},
{
"delete-cfg-path": {
"path": "",
"always-execute": false
}
},
{
"set-tools-path": {
"path": "",
"json-value": {},
"always-execute": false
}
},
{
"run-script": {
"cmdline": "",
"always-execute": false
}
},
{
"reinvoke-with-delay": 5000
}
],
"persistent-data": {
"last-state-up": false
}
}
Actions are processed in the order they are defined above, in that
set-ephemeral-path
is processed first, and
reinvoke-with-delay
last. The only exceptions are for
set-cfg-path
and delete-cfg-path
, which are
processed in the order they are received.
set-ephemeral-path
Makes an ephemeral change to a state leaf.
This action can be used to ephemerally change the oper-state
for a
set of interfaces based on some criteria (for example, the number of uplinks in
up
state).
-
path
is a leaf list in CLI notation that refers to theoper-state
setting for a set of interfaces. Wildcards are not supported; ranges are supported. -
value
can be eitherdown
orup
.
oper-state
for a set of four
interfaces to down
:{
"actions": [
{
"set-ephemeral-path": {
"path": "interface ethernet-1/{1..4} oper-state",
"value": "down"
}
}
]
}
If more than one event handler instance sets oper-state
for the same
interface, actions changing the oper-state
to down
override actions changing the oper-state
to
up
.
In the current release, only the interface oper-state
is valid
as a path used with set-ephemeral-path
.
set-cfg-path
Makes a persistent change to the SR Linux configuration.
The change is applied to the running configuration, but it is not saved to the startup configuration unless an explicit save startup command is executed.
-
path
is a leaf or leaf-list in CLI notation. Wildcards are not supported; ranges are supported -
value
is a configuration setting relevant to thepath
.
The following example uses the set-cfg-path
action to configure the
admin-state
for an interface. The path
contains the CLI command to set the admin-state
, and the
value
contains the setting to apply to the interface.
{
"actions": [
{
"set-cfg-path": {
"path": "interface ethernet-1/3 admin-state",
"value": "disable"
}
},
]
}
delete-cfg-path
Deletes a path in the SR Linux configuration.
The change is applied to the running configuration, but it is not saved to the startup configuration unless an explicit save startup command is executed.
-
path
is a leaf or leaf-list in full, expanded CLI notation. No wildcards or ranges are supported. Deleted settings are reset to their default values where applicable.
The following example deletes the configuration for an interface:
{
"actions": [
{
"delete-cfg-path": {
"path": "interface ethernet-1/3"
}
}
]
}
set-tools-path
Executes an SR Linux tools command.
-
path
is the CLI notation for a tools command (without thetools
keyword). Wildcards are not supported; ranges are supported. -
value
specifies a required value for the tools command in thepath
. If the tools command does not require a value, thevalue
must still be included, but left empty.
The following example uses the set-tools-path
action to clear
statistics for an interface. This action is equivalent to the tools
interface ethernet-1/1 statistics clear CLI command.
{
"actions": [
{
"set-tools-path": {
"path": "interface ethernet-1/1 statistics clear",
"value": ""
}
},
]
}
run-script
Issues a command to execute a script.
The command can chain into another Python or bash script, execute a binary, or
execute a script in any language for which the system has an interpreter installed.
The script is executed as the admin
user. The working context of
the script is the home directory of the user executing the script.
-
cmdline
is the full command to execute the script, including any options. The command is executed in a bash shell. Specify the command as if it were entered at a shell prompt.
The following action executes a script:
{
"actions": [
{
"run-script": {
"cmdline": "/my-script.sh --arg1=val1 -t"
}
}
]
}
reinvoke-with-delay
Re-invokes the script following a specified delay time.
When the actions returned by a script include a value for
reinvoke-with-delay
, the script is automatically re-invoked
following the number of milliseconds specified in the value. When the script is
re-invoked, it uses the then-current value of all paths.
Format: reinvoke-with-delay
: <delay-time>
<delay-time> can be from 1,000 - 300,000 milliseconds (5 minutes).
The following action causes the script to be re-invoked after 5,000 milliseconds:
{
"actions": [
{
"reinvoke-with-delay": 5000
}
]
}
always-execute
When set to true
for an action, causes event handler to always
process the action, regardless of whether the same action was processed
previously.
By default, when a list of actions is processed, event handler checks the list
against actions that have been processed previously. If an action is identical to
one that was processed previously, event handler does not re-run the duplicate
action. For example, if a script returns an action setting an interface
oper-state
to down
, and a subsequent action
sets the oper-state
for the same interface to
down
, event handler ignores the duplicate action.
If you want to disable this default behavior and run the action regardless of whether
the same action has been run previously, set always-execute
for the
action to true
.
The following action runs a tools command that clears statistics
for an interface. The always-execute
setting for the action is
true
, so the command is run each time the action is received
from a script.
{
"actions": [
{
"set-tools-path": {
"path": "interface ethernet-1/1 statistics clear",
"value": "",
"always-execute": true
}
]
}
If always-execute
is not set to true
, then the
interface statistics are cleared the first time the action is processed, but not if
the same action is received again.