Salt is a remote execution and configuration management tool that I have been using to manage the many Linux servers and desktops I have. Its state system also replaces some of my notes as a self-documenting machine-readable description of how each item is configured.

Useful salt commands

Test connectivity:

salt '*' test.ping

Test what changes would be made if state.highstate were run:

salt '*' state.highstate test=True

View a node’s pillar data:

salt minionid pillar.raw

View what the master believes should be the node’s pillar data:

salt minionid pillar.items

Refresh the node’s pillar data:

salt minionid saltutil.refresh_pillar

Run salt, sorting by duration (with terse mode output):

salt minionid --state-output=terse --state-verbose=true state.highstate test=True | grep -o '  Name: .* Duration: [0-9.]\+ ms' | sed 's/  \(Name: .*\) - \(Function: .*\) - Result:.* \(Duration: [0-9.]* ms\)/\3 \2 \1/' | sort -k 2,2 -n

Run an individual state:

salt minionid --state-output=full --state-verbose=true state.apply linux.packages.dropbox test=True

Install SaltStack on Debian

Debian Squeeze needed SaltStack’s own repository and backports. Wheezy required just SaltStack’s own repository. (Update 2018-06-25: Stretch’s version in the main repositories is up to date enough to be usable.)

Install either the salt-minion or salt-master as appropriate:

apt-get install salt-minion

or

apt-get install salt-master

If you want to use salt-ssh then that will also need to be installed:

apt-get install salt-ssh

Master

Salt minions default to connecting to DNS hostname salt for the master. This is fine but it means that it needs adding to DNS before setting up a minion to manage DNS (as the minion needs to resolve salt to get it’s configuration to configure DNS including salt - it can be a bit of a catch-22) OR adding salt to /etc/hosts that then gets managed by salt with a version without that entry when the DNS has been configured.

The master listens on TCP ports 4505 and 4506 by default, so make sure the minions can connect to these through firewalls etc.

Tab \t cannot be used to indent YAML - it must be spaces as the start of the line.

Configuration

Disable passing master configuration to minion

I disabled the default of passing the master configuration in the minion’s pillar by creating /etc/salt/master.d/pillar_opts.conf:

pillar_opts: False

Only display changed/failed states in highstate output

I disabled the default of displaying all highstate results (as opposed to just those that have changed) by creating /etc/salt/master.d/highstate_output.conf:

state_verbose: False

Improved directory structure

I don’t like the default directory layout (/srv/salt and /srv/pillar) so I fix it (to /srv/salt/states and /srv/salt/pillar).

  1. Create /etc/salt/master.d/file_roots.conf:

    file_roots:
      base:
        - /srv/salt/states
    pillar_roots:
      base:
        - /src/salt/pillar
    
  2. Make the directories: mkdir -p /srv/salt/{states,pillar}
  3. Initialise as a git repository (so we can version control the states and pillar):

    cd /srv/salt
    git init
    

Windows

Set the location of the Windows package repository in /etc/salt/master.d/windows.conf:

# The default timeout is too short for Windows minions
timeout: 10
win_repo: /srv/salt/states/win/repo
win_repo_mastercachefile: /srv/salt/states/win/repo/winrepo.p

When packages are added to the repository the cache needs updating with this command:

salt-run winrepo.genrepo

External pillars

This was for work, where I wrote a pillar interface to xcat.

  1. Start by creating /etc/salt/master.d/extension_modules.conf:

    extension_modules: /srv/salt/ext_modules
    
  2. Create the directory:

    mkdir -p /srv/salt/ext_modules/pillar
    
  3. Create the external pillar (see: http://docs.saltstack.com/topics/development/external_pillars.html), e.g. /srv/salt/ext_modules/pillar/xcat.py
  4. Enable is by creating ` /etc/salt/master.d/ext_pillar.conf`:

    ext_pillar:
      - xcat
    

Minion

Connecting minion to a master

Before anything useful can accomplished it is necessary to get a minion and a master talking.

If the DNS for salt is set correctly then the minion should automatically start talking to the master and their key will appear in the list of Unaccepted Keys reported by salt-key:

root@server:~# salt-key -l un
Unaccepted Keys:
minionid

This key can then be checked by comparing the one seen by the master:

root@server:~# salt-key -p minionid
Unaccepted Keys:
minionid:  -----BEGIN PUBLIC KEY-----
MIICI...
-----END PUBLIC KEY-----

to the one on the minon:

root@server:~# cat /etc/salt/pki/minion/minion.pub
-----BEGIN PUBLIC KEY-----
MIICI...
-----END PUBLIC KEY-----

If they match, add the key to the master:

salt-key -a minionid

Finally communication between the pair can be tested:

salt minionid test.ping