Chapter 9. Salt Reactor

The reactor is an engine module that listens to Salt’s event bus and matches incoming event tags with commands that should be run in response. It is useful to automatically trigger actions in immediate response to things happening across an infrastructure.

For example, a file changed event from the inotify beacon could trigger a state run to restore the correct version of that file, and a custom event pattern could post info/warning/error notifications to a Slack or IRC channel.

Note

The reactor is an engine module (see Chapter 8) and uses the event bus (Chapter 6) so it will be helpful to read those chapters before this one. In addition, the reactor is often used to respond to events generated by beacon (Chapter 7) or engine modules.

Getting Started

Salt’s reactor adheres to the workflow: match an event tag; invoke a function. It is best suited to invoking simple actions, as we’ll see in “Best Practices”. The configuration is placed in the master config file and so adding and removing a reaction configuration will require restarting the salt-master daemon.

To start we will create a reaction that listens for an event and then initiates a highstate run on that minion (Example 6-5). The end result is the same as with the startup_states setting except that the master will trigger the state run rather than the minion. Add the code shown in Example 9-1 to your master config.

Example 9-1. /etc/salt/master
reactor:
  - 'napalm/syslog/*/NTP_SERVER_UNREACHABLE/*':
    - salt://reactor/exec_ntp_state.sls

As is evident from the data structure, we can listen for an arbitrary list of event types and in response trigger an arbitrary list of SLS files. The configuration from Example 9-1 instructs the reactor to invoke the salt://reactor/exec_ntp_state.sls reactor SLS file, whenever there is an event on the bus matching napalm/syslog/*/NTP_SERVER_UNREACHABLE/*, the asterisk meaning that it can match anything. For example, this pattern would match the tag from Example 8-4—that is, napalm/syslog/junos/NTP_SERVER_UNREACHABLE/device1. In other words, whenever there is a NTP_SERVER_UNREACHABLE notification, from any platform, from any device, the reactor system would invoke the salt://reactor/exec_ntp_state.sls SLS.

The reactor SLS respects all the characteristics presented in “Extensible and Scalable Configuration Files: SLS”, with the particularity that there are two more special variables available: tag, which constitutes the tag of the event that triggers the action, and data, which is the data of the event. Next, we will create the reactor file, shown in Example 9-2 (you’ll also need to create any necessary directories).

Example 9-2. salt://reactor/exec_ntp_state.sls
triggered_ntp_state: 1
  cmd.state.sls: 2
    - tgt: {{ data.host }} 3 4
    - arg:
      - ntp

Let’s unpack that example, line by line:

1

The ID declaration (i.e., triggered_ntp_state) is best used as a human-friendly description of the intent of the state.

2

You’ll notice that the function declaration differs from Salt states in that it is prefixed by an additional segment, cmd. This denotes the state.sls function will be broadcast to minion(s) exactly like the salt CLI program. Other values are runner and wheel for master-local invocations.

3

The tgt argument is the same value the salt CLI program expects. So is arg. In fact, this reactor file is exactly equivalent to this CLI (Jinja variables replaced): salt --async device1 state.sls ntp. Both the CLI and the reactor call to Salt’s Python API to perform the same task; the only difference is syntax.

4

In this case, host is the field from the event data, which can be used to target the minion, when the ID is the same value as the hostname configured on the device. There can be many match possibilities, depending on the pattern the user chooses to define the minion IDs.

Looking at the entire setup, when the napalm-syslog engine is started, in combination with the configuration bits from Examples 9-1 and 9-2, we instruct Salt to automatically run the ntp state when the device complains that a NTP server is unreachable. This is a genuine example of event-driven network automation.

Best Practices

The reactor is a simple thing: match an event tag, invoke a function. Avoid anything more complicated than that. For example, even invoking two functions is probably too much. This is for two reasons: debugging the reactor involves many, heavy steps; and the reactor is limited in functionality by design.

The best place to encapsulate running complex workflows from the Salt master is, of course, in a Salt orchestrate file—and the reactor can, of course, invoke an orchstrate file via runner.state.orch. Once again this is exactly equivalent to the CLI command salt-run state.orch my_orchestrate_file pillar='{param1: foo}':

something_complex:
  runner.state.orch:
    - mods: my_orchestrate_file
    - pillar:
        param1: foo

Invoking orchestrate from the reactor has two primary benefits:

  • The complex functionality can be tested directly from the CLI using salt-run without having to wait for an event to be triggered. And the results can be seen directly on the CLI without having to look through the master log files. Once it is working, just call it from the reactor verbatim.

  • This functionality can be invoked not only by the reactor but by anything else in the Salt ecosystem that can invoke a Runner, including other orchestrate runs. It becomes reusable.

For very complex workflows where the action is triggered as a result of multiple events or aggregate data, we recommend using the Thorium complex reactor.

Debugging

The easiest way to debug the reactor is to stop the salt-master daemon, and then to start it again in the foreground with debug-level logging enabled: salt-master -l debug. The only useful in-development logging the reactor performs is at the debug level. There are primarily two log entries to search for:

  • Compiling reactions for tag <tag here>

  • Rendered data from file: <file path here>

The first log entry will tell you whether the incoming event tag actually matched the configured event tag. Typos are common and don’t forget to restart the salt-master daemon after making any changes. If you don’t see this log message troubleshoot that before moving on.

The second log entry will contain the rendered output of the SLS file. Read it carefully to be sure that the file Jinja produced is valid YAML, and is in the correct format and will call the function you want using the arguments you want.

That’s all there is to debugging the reactor, although it can be harder than it sounds. Remember to keep your reactor files simple! Once you have things working, stop the salt-master daemon and then start it again using the init system as normal.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.148.115.202