Monitoring Salt Minions with Beacons

Updated by Linode Written by Linode

Contribute on GitHub

Report an Issue | View File | Edit File

Marquee image for Monitoring Salt Minions with Beacons

Every action performed by Salt, such as applying a highstate or restarting a minion, generates an event. Beacons emit events for non-salt processes, such as system state changes or file changes. This guide will use Salt beacons to notify the Salt master of changes to minions, and Salt reactors to react to those changes.

Before You Begin

If you don’t already have a Salt master and minion, follow the first steps in our Getting Started with Salt - Basic Installation and Setup guide.

Note
The steps in this guide require root privileges. Be sure to run the steps below as root or with the sudo prefix. For more information on privileges, see our Users and Groups guide.

Example 1: Preventing Configuration Drift

Configuration drift occurs when there are untracked changes to a system configuration file. Salt can help prevent configuration drift by ensuring that a file is immediately reverted to a safe state upon change. In order to do this, we first have to let Salt manage the file. This section will use an NGINX configuration file as an example, but you can choose any file.

Manage Your File

  1. On your Salt master, create a directory for your managed files in /srv/salt/files:

    mkdir /srv/salt/files
    
  2. On your Salt master, place your nginx.conf, or whichever file you would like to manage, in the /srv/salt/files folder.

  3. On your Salt master, create a state file to manage the NGINX configuration file:

    /srv/salt/nginx_conf.sls
    1
    2
    3
    4
    5
    
    /etc/nginx/nginx.conf:
      file.managed:
        - source:
          - salt://files/nginx.conf
        - makedirs: True

    There are two file paths in this .sls file. The first file path is the path to your managed file on your minion. The second, under source and prefixed with salt://, points to the file path on your master. salt:// is a convenience file path that maps to /srv/salt.

  4. On your Salt master, create a top file if it does not already exist and add your nginx_conf.sls:

    /srv/salt/top.sls
    1
    2
    3
    
    base:
      '*':
        - nginx_conf
  5. Apply a highstate from your Salt master to run the nginx_conf.sls state on your minions.

    salt '*' state.apply
    

Create a Beacon

  1. In order to be notified when a file changes, you will need the Python pyinotify package. Create a Salt state that will handle installing the pyinotify package on your minions:

    /srv/salt/packages.sls
    1
    2
    3
    4
    5
    6
    7
    8
    
    python-pip:
      pkg.installed
    
    pyinotify:
      pip.installed:
        - require:
          - pkg: python-pip
            
    Note
    The inotify beacon only works on OSes that have inotify kernel support. Currently this excludes FreeBSD, macOS, and Windows.
  2. On the Salt master create a minion.d directory to store the beacon configuration file:

    mkdir /srv/salt/files/minion.d
    
  3. Now create a beacon that will emit an event every time the nginx.conf file changes on your minion. Create the /etc/salt/minion.d/beacons.conf file and add the following lines:

    /etc/salt/minion.d/beacons.conf
    1
    2
    3
    4
    5
    6
    7
    
    beacons:
      inotify:
        - files:
            /etc/nginx/nginx.conf:
              mask:
                - modify
        - disable_during_state_run: True
  4. To apply this beacon to your minions, create a new file.managed Salt state:

    /srv/salt/beacons.sls
    1
    2
    3
    4
    5
    6
    
    /etc/salt/minion.d/beacons.conf:
      file.managed:
        - source:
          - salt://files/minion.d/beacons.conf
        - makedirs: True
        
  5. Add the new packages and beacons states to your Salt master’s top file:

    /srv/salt/top.sls
    1
    2
    3
    4
    5
    
    base:
      '*':
        - nginx_conf
        - packages
        - beacons
  6. Apply a highstate from your Salt master to implement these changes on your minions:

    salt '*' state.apply
    
  7. Open another shell to your Salt master and start the Salt event runner. You will use this to monitor for file change events from your beacon.

    salt-run state.event pretty=True
    
  8. On your Salt minion, make a change to your nginx.conf file, and then check out your Salt event runner shell. You should see an event like the following:

      
    salt/beacon/salt-minion/inotify//etc/nginx/nginx.conf	{
        "_stamp": "2018-10-10T13:53:47.163499",
        "change": "IN_MODIFY",
        "id": "salt-minion",
        "path": "/etc/nginx/nginx.conf"
    }
    
    

    Note that the first line is the name of the event, and it includes your Salt minion name and the path to your managed file. We will use this event name in the next section.

  9. To revert the nginx.conf file to it’s initial state, you can apply a highstate from your Salt master.

    salt '*' state.apply nginx_conf
    

    Open your managed file on your Salt minion and notice that the change has been reverted. We will automate this last step in the next section.

Create a Reactor

  1. On your Salt master, create the /srv/reactor directory:

    mkdir /srv/reactor
    
  2. Then create a reactor state file in the /srv/reactor directory and include the following:

    /srv/reactor/nginx_conf_reactor.sls
    1
    2
    3
    4
    5
    
    /etc/nginx/nginx.conf:
      local.state.apply:
        - tgt: {{ data['id'] }}
        - arg:
          - nginx_conf

    The file path in the first line is simply the name of the reactor, and can be whatever you choose. The tgt, or target, is the Salt minion that will receive the highstate. In this case, the information passed to the reactor from the beacon event is used to programmatically choose the right Salt minion ID. This information is available as the data dictionary. The arg, or argument, is the name of the Salt state file that was created to manage the nginx.conf file.

  3. On your Salt master, create a reactor.conf file and include the new reactor state file:

    /etc/salt/master.d/reactor.conf
    1
    2
    3
    
    reactor:
      - 'salt/beacon/*/inotify//etc/nginx/nginx.conf':
        - /srv/reactor/nginx_conf_reactor.sls

    This reactor.conf file is essentially a list of event names matched to reactor state files. In this example we’ve used a glob (*) in the event name instead of specifying a specific minion ID, (which means that any change to a nginx.confon any minion will trigger the reactor), but you might find a specific minion ID better suits your needs.

  4. Restart the salt-master service to apply the reactor.conf file:

    systemctl restart salt-master
    
  5. On your Salt minion, make a change to the nginx.conf file. Then check out your event runner shell and you should see a number of events. Then, check your nginx.conf file. The changes you made should have automatically been reverted.

Congratulations, you now know how to manage configuration drift with Salt. All future updates to nginx.conf should be made on the Salt master and applied using state.apply.

Example 2: Monitoring Minion Memory Usage with Slack

Salt comes with a number of system monitoring beacons. In this example we will monitor a minion’s memory usage and send a Slack notification when the memory usage has passed a certain threshold. For this section you will need to create a Slack bot, obtain an OAuth token, and configure the bot to be able to send Slack messages on your behalf.

Configure Your Slack App

  1. Create a Slack app.

  2. From the Slack app settings page, navigate to OAuth & Permissions.

  3. Copy down the OAuth Access Token.

  4. Under Scopes, select Send Messages As < your app name >.

Create a Beacon

  1. On your Salt master, open or create the /srv/salt/files/minion.d/beacons.conf file and add the following lines. If you already have a beacons.conf file from the previous example, leave out the beacons: line, but ensure that rest of the configuration is indented two spaces:

    /srv/salt/files/minion.d/beacons.conf
    1
    2
    3
    4
    5
    
    beacons:
      memusage:
        beacon.present:
          - percent: 15%
          - interval: 15

    In this example we’ve left the memory usage percentage low to ensure the beacon event will fire, and the event interval set to 15 seconds. In a production environment you should change these to more sane values.

  2. Apply a highstate from your Salt master to add the beacon to your minions:

    salt '*' state.apply
    
  3. If you haven’t already, open another shell into your Salt master and start the event runner:

    salt-run state.event pretty=True
    
  4. After a few seconds, assuming you’ve set the memory percentage low enough, you should see an event like the following:

      
    salt/beacon/salt-minion/memusage/	{
        "_stamp": "2018-10-10T15:48:53.165368",
        "id": "salt-minion",
        "memusage": 20.7
    }
    
    

    Note that the first line is the name of the event, and contains the minion name. We will use this event name in the next section.

Create a Reactor

  1. On your Salt master, create the /srv/reactor directory if you have not already done so:

    mkdir /srv/reactor
    
  2. Then create a reactor state file and add the following lines, making sure to change the channel, api_key, and from_name keys to reflect your desired values. The api_key is the OAuth token you copied down in step 3 of the Configure Your Slack App section:

    /srv/reactor/memusage.sls
    1
    2
    3
    4
    5
    6
    7
    8
    
    Send memusage to Slack:
      local.slack.post_message:
        - tgt: {{ data['id'] }}
        - kwarg:
            channel: "#general"
            api_key: "xoxp-451607817121-453578458246..."
            message: "{{ data['id'] }} has hit a memory usage threshold: {{ data['memusage'] }}%."
            from_name: "Memusage Bot"

    We’re using the data dictionary provided to the reactor from the memusage event to populate the minion ID and the memory usage.

  3. Open or create the reactor.conf file. If you already have a reactor.conf file from the previous example, leave out the reactor: line, but ensure that rest of the configuration is indented two spaces:

    /etc/salt/master.d/reactor.conf
    1
    2
    3
    
    reactor:
      - 'salt/beacon/*/memusage/':
        - '/srv/reactor/memusage.sls'

    In this example we’ve used a glob (*) in the event name instead of specifying a specific minion ID, (which means that any memusage event will trigger the reactor), but you might find a specific minion ID better suits your needs.

  4. Restart salt-master to apply the reactor.conf:

    systemctl restart salt-master
    
  5. In your event-runner shell, after a few seconds, you should see an event like the following:

      
    salt/job/20181010161053393111/ret/salt-minion	{
        "_stamp": "2018-10-10T16:10:53.571956",
        "cmd": "_return",
        "fun": "slack.post_message",
        "fun_args": [
            {
                "api_key": "xoxp-451607817121-453578458246-452348335312-2328ce145e5c0c724c3a8bc2afafee17",
                "channel": "#general",
                "from_name": "Memusage Bot",
                "message": "salt-minion has hit a memory usage threshold: 20.7."
            }
        ],
        "id": "salt-minion",
        "jid": "20181010161053393111",
        "retcode": 0,
        "return": true,
        "success": true
    }
    
    
  6. Open Slack and you should see that your app has notified the room.

Congratulations, you now know how to monitor your Salt minion’s memory usage with Slack integration. Salt can also monitor CPU load, disk usage, and a number of other things. Refer to the More Information section below for additional resources.

More Information

You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

Join our Community

Find answers, ask questions, and help others.

This guide is published under a CC BY-ND 4.0 license.