You'll learn how to:
Estimated time: 15 minutes
Difficulty:
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
Apply 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.git
:
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
The 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 salt.module.*
.
(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 execution.*
instead.)
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 None
.
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.