summaryrefslogtreecommitdiff
path: root/docs/configuration
diff options
context:
space:
mode:
Diffstat (limited to 'docs/configuration')
-rw-r--r--docs/configuration/service/eventhandler.md193
1 files changed, 125 insertions, 68 deletions
diff --git a/docs/configuration/service/eventhandler.md b/docs/configuration/service/eventhandler.md
index 6413c24d..ab813b93 100644
--- a/docs/configuration/service/eventhandler.md
+++ b/docs/configuration/service/eventhandler.md
@@ -1,129 +1,186 @@
+---
+myst:
+ html_meta:
+ description: |
+ The event handler watches the system log and runs a user-supplied
+ script when a preconfigured event occurs. Configure a pattern,
+ optionally a syslog identifier, and a script path per event.
+ keywords: event-handler, syslog, log monitoring, script, automation
+---
+
(event-handler)=
-# Event Handler
+# Event handler
-## Event Handler Technology Overview
+The event handler watches the system log and runs a user-supplied
+script when a preconfigured event occurs. For each event, you configure
+a pattern to look for in the log, optionally restrict matching to a
+specific syslog identifier, and a script to run when a match occurs.
-Event handler allows you to execute scripts when a string that matches
-a regex or a regex with a service name appears in journald logs. You
-can pass variables, arguments, and a full matching string to the script.
+Upon a match, the event handler launches the script. The script can
+read the matched log entry from an environment variable named
+`message` (for example, to extract an IP address or include the log
+line in a notification). You can also pass your own environment
+variables or a fixed argument string to the script.
-## How to configure Event Handler
+## Configuration
-> [1. Create an event handler](#create-an-event-handler)
->
-> [2. Add regex to the script](#add-regex-to-the-script)
->
-> [3. Add a full path to the script](#add-a-full-path-to-the-script)
->
-> [4. Add optional parameters](#add-optional-parameters)
+Each event must be configured with a name, a pattern, and a script
+path. All other settings are optional.
-## Event Handler Configuration Steps
+### Mandatory settings
-### 1. Create an event handler
+```{cfgcmd} set service event-handler event \<name\> filter pattern \<regex\>
-```{cfgcmd} set service event-handler event \<event-handler name\>
+**Configure a regular expression to match against log entries for the
+specified event.**
-This is an optional command because the event handler will be
-automatically created after any of the next commands.
+The regular expression must match the entire log entry, not just a
+part of it. For example, to match any log entry that contains `eth0`,
+wrap it as `.*eth0.*`. Matching is case-sensitive.
```
+Example:
-### 2. Add regex to the script
-
-```{cfgcmd} set service event-handler event \<event-handler name\> filter pattern \<regex\>
+```none
+set service event-handler event LINK-DOWN filter pattern '.*eth0.*,RUNNING,.*->.*'
+```
-This is a mandatory command. Sets regular expression to match
-against log string message.
+```{cfgcmd} set service event-handler event \<name\> script path \<path\>
-:::{note}
-The regular expression matches if and only if the entire
-string matches the pattern.
-:::
+**Configure the path to the script run for the specified event.**
```
+```{note}
+Event-handler scripts must be executable (see
+{ref}`command-scripting`). Storing them under `/config/scripts/`
+ensures they are preserved across image upgrades.
+```
-### 3. Add a full path to the script
+```{warning}
+Event-handler scripts run with root privileges. Review them carefully
+before use.
+```
-```{cfgcmd} set service event-handler event \<event-handler name\> script path \<path to script\>
+Example:
-This is a mandatory command. Sets the full path to the script.
-The script file must be executable.
+```none
+set service event-handler event LINK-DOWN script path /config/scripts/link-down.py
```
+### Optional settings
-### 4. Add optional parameters
+```{cfgcmd} set service event-handler event \<name\> filter syslog-identifier \<identifier\>
-```{cfgcmd} set service event-handler event \<event-handler name\> filter syslog-identifier \<syslogid name\>
+**For the specified event, match the regular expression only against
+log entries produced by the specified process.**
+```
-This is an optional command. Filters log messages by
-syslog-identifier.
+Example:
+
+```none
+set service event-handler event LINK-DOWN filter syslog-identifier kernel
```
-```{cfgcmd} set service event-handler event \<event-handler name\> script environment \<env name\> value \<env value\>
+```{cfgcmd} set service event-handler event \<name\> script environment \<env-var\> value \<value\>
-This is an optional command. Adds environment and its value to
-the script. Use separate commands for each environment.
+**Add an environment variable, with the specified name and value, to
+the script's execution environment.**
-One implicit environment exists.
+Repeat the command for each variable.
+```
-* ``message``: Full message that has triggered the script.
+```{note}
+The variable name `message` is reserved for the matched log entry and
+cannot be reused.
+```
+
+Example:
+
+```none
+set service event-handler event LINK-DOWN script environment interface_name value eth0
```
-```{cfgcmd} set service event-handler event \<event-handler name\> script arguments \<arguments\>
+```{cfgcmd} set service event-handler event \<name\> script arguments \<arguments\>
-This is an optional command. Adds arguments to the script.
-Arguments must be separated by spaces.
+**Append an argument string to the script invocation.**
-:::{note}
-We don't recommend using arguments. Using environment variables is preferable.
-:::
+The string is appended verbatim after the script path. To pass
+multiple arguments, separate them with spaces within a single string.
```
+```{note}
+Prefer environment variables for passing data to the script.
+```
+
+Example:
+
+```none
+set service event-handler event LINK-DOWN script arguments '--notify admin@example.com'
+```
## Example
-Event handler that monitors the state of interface eth0.
+The following example configures an event handler that reacts to
+link-state messages emitted by `netplugd` for `eth0` and runs a Python
+script. When triggered, the script writes a line containing the
+original log entry and the configured `interface_name` value to
+`/tmp/link-state.log`.
+
+### Configuration
```none
-set service event-handler event INTERFACE_STATE_DOWN filter pattern '.*eth0.*,RUNNING,.*->.*'
-set service event-handler event INTERFACE_STATE_DOWN filter syslog-identifier 'netplugd'
-set service event-handler event INTERFACE_STATE_DOWN script environment interface_action value 'down'
-set service event-handler event INTERFACE_STATE_DOWN script environment interface_name value 'eth0'
-set service event-handler event INTERFACE_STATE_DOWN script path '/config/scripts/eventhandler.py'
+set service event-handler event LINK-DOWN filter pattern '.*eth0.*,RUNNING,.*->.*'
+set service event-handler event LINK-DOWN filter syslog-identifier 'netplugd'
+set service event-handler event LINK-DOWN script environment interface_name value 'eth0'
+set service event-handler event LINK-DOWN script path '/config/scripts/link-down.py'
```
-Event handler script
+### Event handler script
+
+Save the following as `/config/scripts/link-down.py`:
```none
#!/usr/bin/env python3
#
# VyOS event-handler script example
+
+from datetime import datetime
from os import environ
-import subprocess
+from pathlib import Path
from sys import exit
-# Perform actions according to requirements
+LOG_FILE = Path('/tmp/link-state.log')
+
+
def process_event() -> None:
- # Get variables
- message_text = environ.get('message')
- interface_name = environ.get('interface_name')
- interface_action = environ.get('interface_action')
- # Print the message that triggered this script
- print(f'Logged message: {message_text}')
- # Prepare a command to run
- command = f'sudo ip link set {interface_name} {interface_action}'.split()
- # Execute a command
- subprocess.run(command)
+ # 'message' is set by the event handler and holds the log entry
+ # that matched the configured pattern.
+ log_line = environ.get('message', '')
+ # User-defined environment variables are read the same way.
+ interface = environ.get('interface_name', '')
+
+ timestamp = datetime.now().isoformat()
+ with LOG_FILE.open('a') as f:
+ f.write(
+ f'{timestamp} link-state change on {interface}: {log_line}\n'
+ )
+
if __name__ == '__main__':
try:
- # Run script actions and exit
process_event()
exit(0)
except Exception as err:
- # Exit properly in case if something in the script goes wrong
- print(f'Error running script: {err}')
+ # Script stdout is discarded by the event handler, but stderr
+ # is captured and surfaces in the system journal.
+ from sys import stderr
+ print(f'Error running script: {err}', file=stderr)
exit(1)
```
+After creating the script, make it executable:
+
+```none
+sudo chmod +x /config/scripts/link-down.py
+```