You'll learn how to:
Estimated time: 15 minutes
You learned the basics of the configuration management system in SaltStack Fundamentals, so let’s take a deep-dive and learn more about Salt state functions.
Salt State functions are what do the work in your Salt states, and are the most important thing to master when using SaltStack’s configuration management system.
Functions are available to install and configure applications, create users, distribute files, and about anything else you might need to do when setting up your systems.
Before we call any functions, let’s go over how Salt states are represented and the syntax for Salt state function calls.
Salt states are described using YAML, which is a simple language for describing structured data (similar to JSON, but more human friendly).
The following diagram shows the format of a Salt state declaration:
The first line in a Salt state declaration is the ID. Underneath the ID is where you call one or more Salt state functions.
The best way to learn how to use Salt state functions is by examples. To see these examples in action, let’s start the vagrant demo environment you set up in SaltStack Fundamentals.
Open a terminal to the
salt-vagrant-demo-master directory and run
vagrant up. Refer back to Demo Environment section of SaltStack Fundamentals if you need a refresher or if you no longer have the Vagrant environment.
While your environment is coming up, create a file named
salt-vagrant-demo-master/saltstack/salt/examples.sls that you can use to run these examples.
Copy the following snippet to the
examples.sls file you created:
install vim: pkg.installed: - name: vim
When your Vagrant environment is up (you are back at the command prompt), ssh to your Salt master:
vagrant ssh master
examples.sls by running the following command:
sudo salt 'minion1' state.apply examples
For extra credit, take a look at the state.pkg docs and see if you can figure out which function to call to ensure that this package is not on the system (hint: the function starts with ‘rem’ and ends in ‘oved’).
remove vim: pkg.removed: - name: vim
You can follow a similar process to test the other examples in this section. You can replace the contents of
examples.sls each time, or you can create new SLS files for each example. If you use new files, make sure you update the
state.apply call to reference the new name.
sudo salt '*' state.apply name-of-your-sls-file-with-no-extension
A basic example that creates a directory.
create my_new_directory: file.directory: - name: /opt/my_new_directory - user: root - group: root - mode: 755
This example uses only a few of the available
file.directory options. Take a look at the docs and try adding a few more.
This state ensures that a service is running on the Salt minion:
Make sure the mysql service is running: service.running: - name: mysql
Each state declaration is identified by a state ID. state IDs must be unique, and they can contain spaces and numbers. In the previous example,
Make sure the mysql service is running is a valid ID.
You can add multiple Salt state function calls under a single state ID:
Install mysql and make sure the mysql service is running: pkg.installed: - name: mysql service.running: - name: mysql
Make sure you look over the complete parameter list when you call a function, since there is often a lot of functionality available by simply passing additional arguments. By passing the
enable: True to
service.running, SaltStack will make sure the service starts each time the system boots.
Make sure the mysql service is running and enable it to start at boot: service.running: - name: mysql - enable: True
Every function takes a
name parameter. If you do not define a value for name, Salt uses the state ID for the value of name. In this example, the
name parameter is
https://github.com/saltstack/salt-bootstrap: git.latest: - rev: develop - target: /tmp/salt
Using the ID as the name is popular with experienced users because keystrokes. You could also write this state like this:
Clone the SaltStack bootstrap script repo: pkg.installed: - name: git # make sure git is installed first! git.latest: - name: https://github.com/saltstack/salt-bootstrap - rev: develop - target: /tmp/salt
We recommend using the second format and always defining the
name argument. The ID should describe what the state is doing, even though it might require more typing. Following this format tends to make your states more consistent and easier to reuse, maintain, and debug.
user account for pete: user.present: - name: pete - shell: /bin/bash - home: /home/pete - groups: - sudo
groups argument is a list, so it is on the next line, indented two spaces, and preceded by a dash.
myserver in hosts file: host.present: - name: myserver - ip: 192.168.0.42
A nice example of platform normalization. This state can be applied to multiple platforms even though hosts are configured in different ways (Salt works out the details so you don’t have to worry about it).
The service.restart and other execution functions can be called in Salt states.
restart vsftpd: module.run: - name: service.restart - m_name: vsftpd # m_name gets passed to the execution module as "name"
Execution functions (short for “remote execution functions”) are the commands that you call from the
salt command line, and they start with
(Bit of trivia: Execution functions start with
module.* since they were the first and only modules available in the initial versions of Salt. If Salt is ever rewritten we should probably start these with
You might be wondering why you would use the service execution functions instead of the service state functions, and why there seems to be so much overlap between Salt state and Salt execution functions.
If you compare the names of the salt execution functions, such as
service.restart, to similar salt state functions, such as
service.running, you might notice a small but important difference. Salt state functions are designed to make only the changes necessary to apply a configuration, and to not make changes otherwise. Salt execution functions run each time they are called, which may or may not result in system changes.
When you call the
service.running state function, the function checks first to see if the service is already running and only starts it if needed. When you call the
service.restart execution function, the service is always restarted.
In many cases the Salt state function wraps the Salt execution function, and adds additional code to determine if the execution function needs to be called.
Applying a Salt state can result in many changes on the target system. Salt state functions provide a mechanism to display the changes that will be made during a live run. The return information will show states that will be applied in yellow and the result is reported as
sudo salt 'minion1' state.apply examples test=True
If you target a directory during a
state.apply or in the state Top file, salt looks for an
init.sls file in that directory and applies it.
You could go forward from this point and create a wide variety of very useful Salt states with only Salt state function calls. Salt ships with hundreds of functions that can manage all sorts of applications and services.
The rest of the features in SaltStack’s configuration management system let you make your states more re-usable with variables and loops, branch on failure, and make your states declarative using statements such as ‘include’ and ‘require’. Mastering these advanced concepts will help you get the most value out of SaltStack’s configuration management system.
We’ll discuss these features in the remaining sections.