The Complete Magazine on Open Source

Use Salt for Basic Configuration Management

SHARE

configure tools

Salt, the Python-based open source configuration management and remote execution application, can be used to actually do basic configuration management. Let’s find out how

This article assumes that you are familiar with what is in the following list (or have read Part 1 of this series on Salt in the December 2014 edition of Open Source For You).

  • Installing SaltStack
  • Setting up master and minion
  • Establishing a relationship between master and minion

In this column, we will look at how to actually use Salt to do some basic configuration management.

Basic Salt commands for documentation/help
Salt provides a wide range of system level documentation on how to use any of its modules.

salt ‘*’ sys.doc (list all modules’ documentation for all minions)
salt ‘*’ sys.doc apache.fullversion (list module specific documentation for all minions)

It offers a minion availability test, as follows:

salt ‘*’ test.ping (for all nodes)
salt ‘machine-name’ test.ping (for specific node)

‘*’ is the target, which specifies all minions. You must specify the minion id/hostname if you want to target a specific minion.
To install a package, type:

salt ‘*’ pkg.install dialog

For user addition, type:

salt ‘*’ user.add osfy

To query disk usage, type:

salt ‘myminion’ disk.percent

myminion:
----------
/:
31%
/boot:
25%
/dev/shm:
0%
/tmp:
29%
/var/log:
8%

Salt State
Salt State is a component in SaltStack that holds the configuration data on the master, and which gets transferred to all minions, on demand.
The collection of state files makes up the ‘State Tree’. The Salt file server must be set up first. So, edit the master configuration file ‘/etc/salt/master’ and uncomment the following lines:

file_roots:
base:
- /srv/salt

The data will be stored in a simple serialisation format (YAML) in a master file server. YAML stands for ‘YAML Ain’t Markup Language’.
We can set a different folder for the base in the master and also define separate folders under the base, depending on the environments that we support. For instance, if you have the dev, test and prod environments, then the directory structure might look like what is shown below:

file_roots:
base:
- /srv/salt
dev:
- /srv/salt/dev
test:
- /srv/salt/test
prod:
- /srv/salt/prod

We could keep common Salt States like user, group and sudo in the base structure, and other configurations, which might be specific to the environments, in their respective folders.
A Salt State consists of identifiers, as well as state module and function declarations. It might also include function parameters.

nginx: #Identifier
pkg: #State Module
- installed #State Function

nginx: #Identifier
pkg.installed #State Module and Function combined.

/etc/nginx:
file.directory: # State module and function
- user:nginx #State function parameter

The top file
The top file contains the list of all the Salt States to be used. It maps the name with the SLS module that gets loaded on a certain minion via the state system. By default, it understands ‘*’ as all minions. We can specify a set of minions or even a number of minions, using regular expressions or a grouping criterion, e.g., environment.
The file will be within the folder that we mark as base. We could also keep a top file within each environment and refer these top files within the base top file.
Let’s prepare the SLS file to install the Nginx Web server. With the pkg module we can install packages using Salt. Create the nginx.sls file in the base folder as shown below.

/srv/salt/nginx.sls:

nginx:
pkg:
- installed

If the top file were to use the above Nginx Salt State, then it would look like what follows:

/srv/base/top.sls:

base:
‘*’:
- nginx

Running the Salt State
A Salt State can be run in two ways.

  • Salt Master could instruct the targeted minion to only run the selected module. The module is then downloaded, compiled and executed on the minion. Once completed, the minion will revert with a summary of all actions taken and all changes made.
    salt ‘myminion’ state.sls nginx (Flow: nginx)
  • The master could instruct the targeted minion to run as state.highstate. When a minion executes a highstate call, it will download the top file and attempt to match the expressions within the top file. When it does match an expression, the modules listed for it will be downloaded, compiled and executed. Once completed, the minion will give a summary of all actions taken and all changes made.
salt ‘myminion’ state.highstate (Flow: top -> nginx -> top)

The summary output looks like what’s shown below:

Summary
--------------
Succeeded: 1
Failed: 0
--------------
Total: 1

Note: Instead of nginx.sls, we can also use nginx/init.sls, if we have other modules common to the Nginx module and if we want to call all or some of those modules within init.

SLS namespace rules
Salt has defined a few simple rules for .sls files.
1. The .sls is discarded (i.e., nginx.sls becomes nginx).
2. A file called init.sls in a sub-directory is referred to by the path of the directory. So, nginx/init.sls is referred to as nginx.
3. Sub-directories can be used for better organisation.
a. Each sub-directory is represented by a dot.
b. nginx/dev.sls is referred to as nginx.dev.
4. If both nginx.sls and nginx/init.sls happen to exist, nginx/init.sls will be ignored, and nginx.sls will be preferred over nginx/init.sls and read as nginx.
To start a service, type:

/srv/salt/nginx/init.sls:

nginx:
pkg:
- installed
service:
- running
- require:
- pkg: nginx

Now we have added a little more information about our preferences.

  • A check is done whether a package named Nginx is installed or not. If not, it will be installed.
  • If the package is installed, then a check is done to find out whether the Nginx service is running. If not, the service is started. For the service check to be done, the package installation is marked as a dependency. The word ‘require’, being a Requisite Statement, does just that—ensuring that the pre-requisites are there.
    To add users and groups, type:
nginx:
pkg:
- installed
service:
- running
- enable: True
- watch:
- pkg: nginx
- file: /etc/nginx/nginx.conf
- user: nginx
user.present:
- uid: 151
- gid: 151
- home: /var/lib/nginx
- shell: /bin/nologin
- require:
- group: nginx
group.present:
- gid: 151
- require:
- pkg: nginx

‘Watch’ and ‘require’
We hope you noticed that we have used the ‘watch’ word this time. The ‘require’ word will make sure the user gets created after the group creation, which must happen only after the Nginx package is installed. The ‘watch’ word checks for any changes to the watched states. The service state watcher will be activated in the following cases:

  • When the package is updated
  • When the configuration file is changed
  • If the user ID gets modified

The service state watcher just restarts the service; so in this case, a change in the config file will also trigger a restart of the respective service.

Users and groups
User Nginx is created with:

  • userid and groupid 151
  • Home folder /var/lib/nginx
  • No login shell
  • Requires a group called nginx

Group Nginx is dependent on the package nginx being installed.

Repository
The Salt master could act as the repository for the Nginx configuration file. The ‘file.managed’ module sends files to the minion and replaces the configuration file on the target system.

/etc/nginx/nginx.conf:
file.managed:
- source: salt://nginx/files/nginx.conf
- user: root
- group: root
- mode: 644

Source file
The source file can be hosted either on the Salt master server or on a network accessible server. The file hosted on a network server (e.g., HTTP or FTP) requires the source_hash argument. We could also keep the data files along with init.sls but it is easier to maintain and manage these files if they are separated from the SLS configuration. If we do keep the data and configuration files within the same directory, the source statement and files could look like what’s shown below:

nginx/init.sls
nginx/nginx.conf

- source: salt://nginx/nginx.conf

Debugging

Once the rules in an SLS are ready, they should be tested to ensure they work properly. To invoke these rules, execute salt ‘*’ state.highstate on the command line. If you get back only hostnames followed by a ‘:’, but no return, chances are that there is a problem with one or more of the SLS files. On the minion, use the command salt-call state.highstate -l debug to examine the output for errors. This should help to troubleshoot the issue. The minions can also be started in the foreground in debug mode: salt-minion -l debug.