salt.states.cmd

Execution of arbitrary commands

The cmd state module manages the enforcement of executed commands, this state can tell a command to run under certain circumstances.

A simple example to execute a command:

# Store the current date in a file
date > /tmp/salt-run:
  cmd.run

Only run if another execution failed, in this case truncate syslog if there is no disk space:

> /var/log/messages:
  cmd.run:
    - unless: echo 'foo' > /tmp/.test && rm -f /tmp/.test

Only run if the file specified by creates does not exist, in this case touch /tmp/foo if it does not exist.

touch /tmp/foo:
  cmd.run:
    - creates: /tmp/foo

Note

The creates option was added to version 2014.7.0

Salt determines whether the cmd state is successfully enforced based on the exit code returned by the command. If the command returns a zero exit code, then salt determines that the state was successfully enforced. If the script returns a non-zero exit code, then salt determines that it failed to successfully enforce the state. If a command returns a non-zero exit code but you wish to treat this as a success, then you must place the command in a script and explicitly set the exit code of the script to zero.

Please note that the success or failure of the state is not affected by whether a state change occurred nor the stateful argument.

When executing a command or script, the state (i.e., changed or not) of the command is unknown to Salt's state system. Therefore, by default, the cmd state assumes that any command execution results in a changed state.

This means that if a cmd state is watched by another state then the state that's watching will always be executed due to the changed state in the cmd state.

Using the "Stateful" Argument

Many state functions in this module now also accept a stateful argument. If stateful is specified to be true then it is assumed that the command or script will determine its own state and communicate it back by following a simple protocol described below:

  1. If there's nothing in the stdout of the command, then assume no changes. Otherwise, the stdout must be either in JSON or its last non-empty line must be a string of key=value pairs delimited by spaces (no spaces on either side of =).

  2. If it's JSON then it must be a JSON object (e.g., {}). If it's key=value pairs then quoting may be used to include spaces. (Python's shlex module is used to parse the key=value string)

    Two special keys or attributes are recognized in the output:

    changed: bool (i.e., 'yes', 'no', 'true', 'false', case-insensitive)
    comment: str  (i.e., any string)
    

    So, only if changed is True then assume the command execution has changed the state, and any other key values or attributes in the output will be set as part of the changes.

  3. If there's a comment then it will be used as the comment of the state.

    Here's an example of how one might write a shell script for use with a stateful command:

    #!/bin/bash
    #
    echo "Working hard..."
    
    # writing the state line
    echo  # an empty line here so the next line will be the last.
    echo "changed=yes comment='something has changed' whatever=123"
    

    And an example SLS file using this module:

    Run myscript:
      cmd.run:
        - name: /path/to/myscript
        - cwd: /
        - stateful: True
    
    Run only if myscript changed something:
      cmd.run:
        - name: echo hello
        - cwd: /
        - onchanges:
            - cmd: Run myscript
    

    Note that if the second cmd.run state also specifies stateful: True it can then be watched by some other states as well.

  4. The stateful argument can optionally include a test_name parameter.

    This is used to specify a command to run in test mode. This command should return stateful data for changes that would be made by the command in the name parameter.

    New in version 2015.2.0.

    Run myscript:
      cmd.run:
        - name: /path/to/myscript
        - cwd: /
        - stateful:
          - test_name: /path/to/myscript test
    
    Run masterscript:
      cmd.script:
        - name: masterscript
        - source: salt://path/to/masterscript
        - cwd: /
        - stateful:
          - test_name: masterscript test
    

Should I use cmd.run or cmd.wait?

Note

Use cmd.run together with onchanges instead of cmd.wait.

These two states are often confused. The important thing to remember about them is that cmd.run states are run each time the SLS file that contains them is applied. If it is more desirable to have a command that only runs after some other state changes, then cmd.wait does just that. cmd.wait is designed to watch other states, and is executed when the state it is watching changes. Example:

/usr/local/bin/postinstall.sh:
  cmd.wait:
    - watch:
      - pkg: mycustompkg
  file.managed:
    - source: salt://utils/scripts/postinstall.sh

mycustompkg:
  pkg.installed:
    - require:
      - file: /usr/local/bin/postinstall.sh

cmd.wait itself does not do anything; all functionality is inside its mod_watch function, which is called by watch on changes.

cmd.wait will be deprecated in future due to the confusion it causes. The preferred format is using the onchanges Requisite, which works on cmd.run as well as on any other state. The example would then look as follows:

/usr/local/bin/postinstall.sh:
  cmd.run:
    - onchanges:
      - pkg: mycustompkg
  file.managed:
    - source: salt://utils/scripts/postinstall.sh

mycustompkg:
  pkg.installed:
    - require:
      - file: /usr/local/bin/postinstall.sh

How do I create an environment from a pillar map?

The map that comes from a pillar cannot be directly consumed by the env option. To use it one must convert it to a list. Example:

printenv:
  cmd.run:
    - env:
      {% for key, value in pillar['keys'].iteritems() %}
      - '{{ key }}': '{{ value }}'
      {% endfor %}
salt.states.cmd.call(name, func, args=(), kws=None, onlyif=None, unless=None, creates=None, output_loglevel='debug', use_vt=False, **kwargs)

Invoke a pre-defined Python function with arguments specified in the state declaration. This function is mainly used by the salt.renderers.pydsl renderer.

The interpretation of onlyif and unless arguments are identical to those of cmd.run, and all other arguments(cwd, runas, ...) allowed by cmd.run are allowed here, except that their effects apply only to the commands specified in onlyif and unless rather than to the function to be invoked.

In addition, the stateful argument has no effects here.

The return value of the invoked function will be interpreted as follows.

If it's a dictionary then it will be passed through to the state system, which expects it to have the usual structure returned by any salt state function.

Otherwise, the return value (denoted as result in the code below) is expected to be a JSON serializable object, and this dictionary is returned:

{
    'name': name
    'changes': {'retval': result},
    'result': True if result is None else bool(result),
    'comment': result if isinstance(result, string_types) else ''
}
salt.states.cmd.mod_run_check(cmd_kwargs, onlyif, unless, creates)

Execute the onlyif and unless logic. Return a result dict if: * onlyif failed (onlyif != 0) * unless succeeded (unless == 0) else return True

salt.states.cmd.mod_watch(name, **kwargs)

Execute a cmd function based on a watch call

salt.states.cmd.run(name, onlyif=None, unless=None, creates=None, cwd=None, runas=None, shell=None, env=None, stateful=False, umask=None, output_loglevel='debug', quiet=False, timeout=None, ignore_timeout=False, use_vt=False, **kwargs)

Run a command if certain circumstances are met. Use cmd.wait if you want to use the watch requisite.

name
The command to execute, remember that the command will execute with the path and permissions of the salt-minion.
onlyif
A command to run as a check, run the named command only if the command passed to the onlyif option returns true
unless
A command to run as a check, only run the named command if the command passed to the unless option returns false
cwd
The current working directory to execute the command in, defaults to /root
runas
The user name to run the command as
shell
The shell to use for execution, defaults to the shell grain
env

A list of environment variables to be set prior to execution. Example:

script-foo:
  cmd.run:
    - env:
      - BATCH: 'yes'

Warning

The above illustrates a common PyYAML pitfall, that yes, no, on, off, true, and false are all loaded as boolean True and False values, and must be enclosed in quotes to be used as strings. More info on this (and other) PyYAML idiosyncrasies can be found here.

Variables as values are not evaluated. So $PATH in the following example is a literal '$PATH':

script-bar:
  cmd.run:
    - env: "PATH=/some/path:$PATH"

One can still use the existing $PATH by using a bit of Jinja:

{% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}

mycommand:
  cmd.run:
    - name: ls -l /
    - env:
      - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
stateful
The command being executed is expected to return data about executing a state. For more information, see the Using the "Stateful" Argument section.
umask
The umask (in octal) to use when running the command.
output_loglevel
Control the loglevel at which the output from the command is logged. Note that the command being run will still be logged (loglevel: DEBUG) regardless, unless quiet is used for this value.
quiet
The command will be executed quietly, meaning no log entries of the actual command or its return data. This is deprecated as of the 2014.1.0 release, and is being replaced with output_loglevel: quiet.
timeout
If the command has not terminated after timeout seconds, send the subprocess sigterm, and if sigterm is ignored, follow up with sigkill
ignore_timeout

Ignore the timeout of commands, which is useful for running nohup processes.

New in version 2015.8.0.

creates

Only run if the file specified by creates does not exist.

New in version 2014.7.0.

use_vt
Use VT utils (saltstack) to stream the command output more interactively to the console and the logs. This is experimental.
bg

If True, run command in background and do not await or deliver it's results.

New in version 2016.3.6.

Note

cmd.run supports the usage of reload_modules. This functionality allows you to force Salt to reload all modules. You should only use reload_modules if your cmd.run does some sort of installation (such as pip), if you do not reload the modules future items in your state which rely on the software being installed will fail.

getpip:
  cmd.run:
    - name: /usr/bin/python /usr/local/sbin/get-pip.py
    - unless: which pip
    - require:
      - pkg: python
      - file: /usr/local/sbin/get-pip.py
    - reload_modules: True
salt.states.cmd.script(name, source=None, template=None, onlyif=None, unless=None, creates=None, cwd=None, runas=None, shell=None, env=None, stateful=False, umask=None, timeout=None, use_vt=False, output_loglevel='debug', defaults=None, context=None, **kwargs)

Download a script and execute it with specified arguments.

source
The location of the script to download. If the file is located on the master in the directory named spam, and is called eggs, the source string is salt://spam/eggs
template
If this setting is applied then the named templating engine will be used to render the downloaded file. Currently jinja, mako, and wempy are supported
name
Either "cmd arg1 arg2 arg3..." (cmd is not used) or a source "salt://...".
onlyif
Run the named command only if the command passed to the onlyif option returns true
unless
Run the named command only if the command passed to the unless option returns false
cwd
The current working directory to execute the command in, defaults to /root
runas
The name of the user to run the command as
shell
The shell to use for execution. The default is set in grains['shell']
env

A list of environment variables to be set prior to execution. Example:

salt://scripts/foo.sh:
  cmd.script:
    - env:
      - BATCH: 'yes'

Warning

The above illustrates a common PyYAML pitfall, that yes, no, on, off, true, and false are all loaded as boolean True and False values, and must be enclosed in quotes to be used as strings. More info on this (and other) PyYAML idiosyncrasies can be found here.

Variables as values are not evaluated. So $PATH in the following example is a literal '$PATH':

salt://scripts/bar.sh:
  cmd.script:
    - env: "PATH=/some/path:$PATH"

One can still use the existing $PATH by using a bit of Jinja:

{% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}

mycommand:
  cmd.run:
    - name: ls -l /
    - env:
      - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
saltenv
: base
The Salt environment to use
umask
The umask (in octal) to use when running the command.
stateful
The command being executed is expected to return data about executing a state. For more information, see the Using the "Stateful" Argument section.
timeout
If the command has not terminated after timeout seconds, send the subprocess sigterm, and if sigterm is ignored, follow up with sigkill
args
String of command line args to pass to the script. Only used if no args are specified as part of the name argument. To pass a string containing spaces in YAML, you will need to doubly-quote it: "arg1 'arg two' arg3"
creates

Only run if the file specified by creates does not exist.

New in version 2014.7.0.

use_vt
Use VT utils (saltstack) to stream the command output more interactively to the console and the logs. This is experimental.
context

New in version 2016.3.0.

Overrides default context variables passed to the template.

defaults

New in version 2016.3.0.

Default context passed to the template.

output_loglevel
Control the loglevel at which the output from the command is logged. Note that the command being run will still be logged (loglevel: DEBUG) regardless, unless quiet is used for this value.
salt.states.cmd.wait(name, onlyif=None, unless=None, creates=None, cwd=None, runas=None, shell=None, env=(), stateful=False, umask=None, output_loglevel='debug', use_vt=False, **kwargs)

Run the given command only if the watch statement calls it.

Note

Use cmd.run with onchange instead.

name
The command to execute, remember that the command will execute with the path and permissions of the salt-minion.
onlyif
A command to run as a check, run the named command only if the command passed to the onlyif option returns true
unless
A command to run as a check, only run the named command if the command passed to the unless option returns false
cwd
The current working directory to execute the command in, defaults to /root
runas
The user name to run the command as
shell
The shell to use for execution, defaults to /bin/sh
env

A list of environment variables to be set prior to execution. Example:

script-foo:
  cmd.wait:
    - env:
      - BATCH: 'yes'

Warning

The above illustrates a common PyYAML pitfall, that yes, no, on, off, true, and false are all loaded as boolean True and False values, and must be enclosed in quotes to be used as strings. More info on this (and other) PyYAML idiosyncrasies can be found here.

Variables as values are not evaluated. So $PATH in the following example is a literal '$PATH':

script-bar:
  cmd.wait:
    - env: "PATH=/some/path:$PATH"

One can still use the existing $PATH by using a bit of Jinja:

{% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}

mycommand:
  cmd.run:
    - name: ls -l /
    - env:
      - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
umask
The umask (in octal) to use when running the command.
stateful
The command being executed is expected to return data about executing a state. For more information, see the Using the "Stateful" Argument section.
creates

Only run if the file specified by creates does not exist.

New in version 2014.7.0.

output_loglevel
Control the loglevel at which the output from the command is logged. Note that the command being run will still be logged (loglevel: DEBUG) regardless, unless quiet is used for this value.
use_vt
Use VT utils (saltstack) to stream the command output more interactively to the console and the logs. This is experimental.
salt.states.cmd.wait_call(name, func, args=(), kws=None, onlyif=None, unless=None, creates=None, stateful=False, use_vt=False, output_loglevel='debug', **kwargs)
salt.states.cmd.wait_script(name, source=None, template=None, onlyif=None, unless=None, cwd=None, runas=None, shell=None, env=None, stateful=False, umask=None, use_vt=False, output_loglevel='debug', **kwargs)

Download a script from a remote source and execute it only if a watch statement calls it.

source
The source script being downloaded to the minion, this source script is hosted on the salt master server. If the file is located on the master in the directory named spam, and is called eggs, the source string is salt://spam/eggs
template
If this setting is applied then the named templating engine will be used to render the downloaded file, currently jinja, mako, and wempy are supported
name
The command to execute, remember that the command will execute with the path and permissions of the salt-minion.
onlyif
A command to run as a check, run the named command only if the command passed to the onlyif option returns true
unless
A command to run as a check, only run the named command if the command passed to the unless option returns false
cwd
The current working directory to execute the command in, defaults to /root
runas
The user name to run the command as
shell
The shell to use for execution, defaults to the shell grain
env

A list of environment variables to be set prior to execution. Example:

salt://scripts/foo.sh:
  cmd.wait_script:
    - env:
      - BATCH: 'yes'

Warning

The above illustrates a common PyYAML pitfall, that yes, no, on, off, true, and false are all loaded as boolean True and False values, and must be enclosed in quotes to be used as strings. More info on this (and other) PyYAML idiosyncrasies can be found here.

Variables as values are not evaluated. So $PATH in the following example is a literal '$PATH':

salt://scripts/bar.sh:
  cmd.wait_script:
    - env: "PATH=/some/path:$PATH"

One can still use the existing $PATH by using a bit of Jinja:

{% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}

mycommand:
  cmd.run:
    - name: ls -l /
    - env:
      - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
umask
The umask (in octal) to use when running the command.
stateful
The command being executed is expected to return data about executing a state. For more information, see the Using the "Stateful" Argument section.
use_vt
Use VT utils (saltstack) to stream the command output more interactively to the console and the logs. This is experimental.
output_loglevel
Control the loglevel at which the output from the command is logged. Note that the command being run will still be logged (loglevel: DEBUG) regardless, unless quiet is used for this value.