Running a command in a State
If you remember from the previous article SaltStack's states are permanent configurations. Adding a command in a Salt state is used when you want to have a command that is run after provisioning a server, run every time Salt manages the state of the system or run when certain conditions are true.For today's article we will be using the same nginx state file as our last article.
For this example let's pretend that we want to execute the script /root/scripts/test.sh on systems with the nginx software loaded. To do this we can simply add the command into the nginx state file.
On the Salt Master edit the nginx/init.sls file:
# vi /salt/states/base/nginx/init.sls
Append the following:test.sh:
cmd:
- run
- name: /root/scripts/test.sh
The above entry will tell Salt to run the command named /root/scripts/test.sh
every time the systems state is managed.Using onlyif and unless
What if we only want to run the command when certain conditions are true? Well salt can handle that too. We can us theonlyif
and unless
options to tell Salt to only run the command if certain conditions are met.Onlyif
Onlyif
will execute the command only if the supplied
command is true. In the below example we will only execute test.sh if
the file exists.Example:
test.sh:
cmd:
- run
- name: /root/scripts/test.sh
- onlyif: test -f /root/scripts/test.sh
Unless
Whileonlyif
executes the named command if the supplied command returns true, unless
will only execute the named command if the supplied command returns
false. In this example we will execute the command test.sh only when the
nginx configtest fails.Example:
test.sh:
cmd:
- run
- name: /root/scripts/test.sh
- unless: /usr/sbin/service nginx configtest
Stateful commands
If you want Salt to understand whether your script passed or failed you can do this by making the commandstateful
.Adding stateful to the state file
In the state file we will tell Salt that the command is stateful by appending- stateful: True
.Example:
test.sh:
cmd:
- run
- name: /root/scripts/test.sh
- unless: /usr/sbin/service nginx configtest
- stateful: True
Adding state status to the script
Now that salt knows the command is "stateful" the script must also tell Salt what has changed and if it was successful or not. To do this you can append two lines at the end of the scripts output.Example of a good run:
echo "" ## This echos an empty line and is required
echo "changed=yes comment='I executed something and it changed'"
Example of a failed run:echo "" ## This echos an empty line and is required
echo "changed=no comment='I executed something and it did not change'"
It's ok if your script also has other output. Salt will only be
looking at the last two lines of output; so you must make sure that
these lines are at the end. For more information about running commands
in states check out the Saltstack cmd state docs.Running adhoc commands with Salt
Unlike many configuration management tools, Saltstack can be used to run one time only commands as well. This functionality along with the ability to filter which minions to execute the command on, is one of the key things that I feel sets Saltstack apart from other automation tools.Running an adhoc command on all hosts
To run a command on all of the minions the syntax is pretty basic. We will call salt with the cmd.run module and then supply it with a command to run followed by single or double quotes.# salt '*' cmd.run "<command to execute>"
The below example shows running the hostname -s
command via Saltstack on all of the attached minions.Example:
# salt '*' cmd.run "hostname -s"
dbsalt01:
dbsalt01
websalt02:
websalt02
websalt:
websalt
saltminion:
saltminion
Running an adhoc command on specific hosts
While running commands on every host is great for many tasks, it is rare that we actually want to run a command on every single host. Usually we want to run a command on a subset of hosts. Below I am going to show a few examples of how this could be done.Hostname globs
When calling salt you can use globs to specify a hostname pattern. For example if all of your mail servers had a naming convention of mailserver01, than you could simply usemail*
. If you
wanted to run a command on all of your development servers and they had a
hostname of someserver.dev.example.com you could use *dev.example.com
.The below example will run service nginx restart on all of my servers that have a hostname that starts with
web
.Example:
# salt 'web*' cmd.run 'service nginx restart'
websalt02:
Restarting nginx: nginx.
websalt:
Restarting nginx: nginx.
Using Grains
In addition to globs you can also ask Salt to run commands based on the grains available on those hosts. To do this you can use the-G
flag followed by the grain:value
that you are looking for.The below example will run
uname -r
on all of my Ubuntu hosts.Example:
# salt -G 'os:Ubuntu' cmd.run "uname -r"
saltminion:
3.2.0-53-generic
websalt02:
3.2.0-53-generic
dbsalt01:
3.2.0-53-generic
websalt:
3.2.0-53-generic
Using a list of hosts
If neither of the options above works for your situation, you could always simply specify the hostnames with the-L
flag.The below will only execute the "service nginx status" command on the hosts named websalt and saltminion.
Example:
# salt -L 'websalt,saltminion' cmd.run "service nginx status" websalt: * nginx is running saltminion: * nginx is running
Some things to keep in mind
You can't run interactive scripts
While the remote execution abilities of Saltstack are great, there is one catch to them. Due to the method that Saltstack sends commands to systems; Saltstack is not expecting them to ask for user input. These types of commands will fail, as Saltstack cannot supply the expected input.# salt 'saltminion*' cmd.run "/root/scripts/test.sh"
saltminion:
Can I ask you something? [y/n]:
Error! Failed to get user input
You can run commands without SSH running
Saltstack communicates to the minions via ZeroMQ. This communication layer is outside of SSH, because of this you can use Saltstack to restart SSH on any servers where it may have died unexpectedly. This allows you to have a second path into a system without having to launch a KVM or go to the systems console.# salt 'saltminion*' cmd.run "service ssh status"
saltminion:
ssh stop/waiting
0 comments:
Post a Comment