In our quest to get all things into Matrix, we've also sent Salt events into a Matrix room. This is extremely useful to monitor the results of automatic highstate runs, individual commands, etc.

Salt logging in Matrix

For this effort, we looked at implementing a Matrix returner, which is probably the best solution. But not being that strong of a Python programmer, and having some desire to control/filter what gets posted, instead we went down the path of a custom Reactor, based on this post.

This involves 2 configuration changes, a Python script, and the matrix_client Python library. First of all, install the library:

pip install matrix_client

... with that available, here's the script we created, starting with the one in the blog post linked above, but modifying heavily for our needs. We put it in our main Salt state directory, under a _runners subdirectory - /srv/salt/_runners/process_minion_data.py:

import subprocess
from matrix_client.api import MatrixHttpApi

def post_changes(matrix_hs, room_id, token, message, data_str):
   data = eval(data_str)
   error = False
   changes = False

   funtype = data['fun'].split('.')[0]
   # Skip saltutil calls... can add others here as needed.
   if funtype == 'saltutil':
      return True

   if type(data['return']) is dict:
      for state, result in data['return'].iteritems():
         if type(result) is not dict:
            error = True
            message = message + ' Res: ' + str(result)
            break;
         if not result['result']:
            error = True
            break
         if result['changes']:
            changes = True
            break
   else:
      if not data['success']:
         error = True

   matrix = MatrixHttpApi(matrix_hs, token=token)
   if error or changes:
      state = subprocess.check_output(["salt-run", "jobs.lookup_jid", data['jid'], "--out=highs
tate"])
      response = matrix.send_message(room_id, message + "\n" + state)
   else:
      response = matrix.send_message(room_id, message)
   return True

Next, the Reactor Yaml file, /srv/reactor/notify-changes.sls:

notify-changes:
  runner.process_minion_data.post_changes:
    - kwarg:
        matrix_hs: [Your homeserver URL]
        room_id: "[Room ID to post -- if there's a !, it needs to be quoted]"
        token: "[Token for Matrix account to post as]"
        message: "Salt master: minion run: {{ data['fun'] }} id: {{ data['id'] }} jid: {{ data[
'jid'] }}"
        data_str: {{ data|yaml_dquote }}

... we did have to alter the Yaml structure compared to the blog post we based this on, due to changes in how Salt calls its runners.

Finally, you need to register the reactor and the runner path in the Master configuration file. We did this by adding a file, /etc/salt/master.d/reactor.conf:

reactor:
  - 'salt/job/*/ret/*':
    - /srv/reactor/notify-changes.sls

runner_dirs:
  - /srv/salt/_runners

# Also set the highstate output to short for unchanged states:
state_output: changes

And voila! We now have Salt logging its activity into a Matrix room.

Share this article with your friends!

Comments (0)

Add new comment

This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.