States basics

Salt offers an interface to manage the configuration or “state” of the Salt minions. This interface is a fully capable mechanism used to enforce the state of systems from a central manager.

State data structure

States are stored in text files on the master and transferred to the minions on demand via the master’s file Server. The collection of state files make up the State Tree.

Top file

In Salt, the file which contains a mapping between groups of machines on a network and the configuration roles that should be applied to them is called a top file.

Top files have three components:

Environment

A state tree directory containing a set of state files to configure systems.

Target

A grouping of machines which will have a set of states applied to them.

State files

A list of state files to apply to a target. Each state file describes one or more states to be configured and enforced on the targeted machines.

Following example shows apache state attached to web* nodes.

base:          # Apply SLS files from the directory root for the 'base' environment
  'web*':      # All minions with a minion_id that begins with 'web'
    - apache   # Apply the state file named 'apache.sls'

Environments are directory hierarchies which contain a top files and a set of state files.

Environments can be used in many ways, however there is no requirement that they be used at all. In fact, the most common way to deploy Salt is with a single environment, called base. It is recommended that users only create multiple environments if they have a use case which specifically calls for multiple versions of state trees.

State components declaration

Following Salt state structure components form up complete State definition file.

Include declaration

Defines a list of modules to include in this SLS. Can be only in the top level of the highstate structure.

Module reference

The name of a SLS module defined by a separate SLS file and residing on the Salt Master. A module named edit.vim is a reference to the SLS file salt://edit/vim.sls.

ID declaration

Defines an individual highstate component. Can be overridden by a Name declaration or a Names declaration. Must be unique across entire state tree.

State declaration

A top level section of a state file that lists the state function calls and arguments that make up a state. Each state declaration starts with a unique ID.

Function declaration

The name of the function to call within the state. Commands that you call to perform a configuration task on a system.

Function arg declaration

Single key dictionary referencing a Python type which is to be passed to the named functionsas a parameter. The type must be the data type expected by the function.

Name declaration

Overrides the name argument of a State declaration. If name is not specified the ID declaration satisfies the name argument.

Requisite declaration

A list containing requisite references. Used to build the action dependency tree.

Requisite reference

A single key dictionary. The key is the name of the referenced State declaration and the value is the ID of the referenced ID declaration.

Here is the layout in YAML using the names of the Salt state structure components.

<Include Declaration>:
  - <Module Reference>
  - <Module Reference>

<ID Declaration>:
  <State Module>.<Function>:
    - <Function Arg>
    - <Function Arg>
    - <Function Arg>
    - <Names>:
      - <name>
      - <name>
      - <name>
    - <Requisite Declaration>:
      - <Requisite Reference>
      - <Requisite Reference>

Complete state example

Following code shows example of usual file declaration.

apache:
  pkg.installed: []
  service.running:
    - watch:
      - pkg: apache
      - file: /etc/httpd/conf/httpd.conf
      - user: apache
  user.present:
    - uid: 87
    - gid: 87
    - home: /var/www/html
    - shell: /bin/nologin
    - require:
      - group: apache
  group.present:
    - gid: 87
    - require:
      - pkg: apache

/etc/httpd/conf/httpd.conf:
  file.managed:
    - source: salt://apache/httpd.conf
    - user: root
    - group: root
    - mode: 644

Test state runs

Executing a Salt state run can potentially change many aspects of a system and it may be desirable to first see what a state run is going to change before applying the run.

Salt has a test interface to report on exactly what will be changed, this interface can be invoked on any of the major state run functions:

.. code-block:: bash
salt ‘*’ state.highstate test=True salt ‘*’ state.sls test=True salt ‘*’ state.single test=True

The test run is mandated by adding the test=True option to the states. The return information will show states that will be applied in yellow and the result is reported as None.

Understanding the state system layers

The Salt state system is comprised of multiple layers. While using Salt does not require an understanding of the state layers, a deeper understanding of how Salt compiles and manages states can be very beneficial.

Function call

The lowest layer of functionality in the state system is the direct state function call. State executions are executions of single state functions at the core. These individual functions are defined in state modules and can be called directly via the state.single command.

salt '*' state.single pkg.installed name='vim'

Low chunk

The low chunk is the bottom of the Salt state compiler. This is a data representation of a single function call. The low chunk is sent to the state caller and used to execute a single state function.

A single low chunk can be executed manually via the state.low command.

salt '*' state.low '{name: vim, state: pkg, fun: installed}'

The passed data reflects what the state execution system gets after compiling the data down from sls formulas.

Low state

The Low State layer is the list of low chunks “evaluated” in order. To see what the low state looks like for a highstate, run:

salt '*' state.show_lowstate

This will display the raw lowstate in the order which each low chunk will be evaluated. The order of evaluation is not necessarily the order of execution, since requisites are evaluated at runtime. Requisite execution and evaluation is finite; this means that the order of execution can be ascertained with 100% certainty based on the order of the low state.

High data

High data is the data structure represented in YAML via SLS files. The High data structure is created by merging the data components rendered inside sls files (or other render systems). The High data can be easily viewed by executing the state.show_highstate or state.show_sls functions. Since this data is a somewhat complex data structure, it may be easier to read using the json, pprint or yaml outputters:

salt '*' state.show_highstate --out yaml
salt '*' state.show_sls edit.vim --out pprint

SLS

Above “High Data”, the logical layers are no longer technically required to be executed, or to be executed in a hierarchy. This means that how the High data is generated is optional and very flexible. The SLS layer allows for many mechanisms to be used to render sls data from files or to use the fileserver backend to generate sls and file data from external systems.

The SLS layer can be called directly to execute individual sls formulas.

Note

SLS Formulas have historically been called “SLS files”. This is because a single SLS was only constituted in a single file. Now the term “SLS Formula” better expresses how a compartmentalized SLS can be expressed in a much more dynamic way by combining pillar and other sources, and the SLS can be dynamically generated.

To call a single SLS formula named edit.vim, execute state.sls:

salt '*' state.sls edit.vim

HighState

Calling SLS directly logically assigns what states should be executed from the context of the calling minion. The Highstate layer is used to allow for full contextual assignment of what is executed where to be tied to groups of, or individual, minions entirely from the master. This means that the environment of a minion, and all associated execution data pertinent to said minion, can be assigned from the master without needing to execute or configure anything on the target minion. This also means that the minion can independently retrieve information about its complete configuration from the master.

To execute the High State call state.highstate:

salt '*' state.highstate

Orchestrate

The orchestrate layer expresses the highest functional layer of Salt’s automated logic systems. The Overstate allows for stateful and functional orchestration of routines from the master. The orchestrate defines in data execution stages which minions should execute states, or functions, and in what order using requisite logic.

Lab: Initial SLS file evaluation

Configure file_roots for example in /etc/salt/master.d/files.conf

file_roots:
  base:
    - /srv/salt/files

Create directory /srv/salt/files on cfg01 node:

cfg01# mkdir -p /srv/salt/files

Create a file named /srv/salt/files/example.sls with content below.

utils_install:
  pkg.installed:
    - names:
      - htop
      - curl
      - mc
salt 'svc0[1-2]*' state.apply example

Lab: Create simple SLS file

On the master, in the directory /srv/salt/files created in the previous step, create a new file called top.sls and add the following:

base:
  'svc01*':
    - webserver

Write your first state file in /srv/salt/files/webserver.sls

apache2:
  pkg.installed: []
  service.running:
    - watch:
      - pkg: apache2

Now test the state by running several commands.

cfg01:# salt-call state.show_highstate

[INFO    ] Loading fresh modules for state activity
[INFO    ] Fetching file from saltenv 'base', ** done ** u'top.sls'
[INFO    ] Fetching file from saltenv 'base', ** done ** u'webserver.sls'
local:
    ----------
    /etc/httpd/conf/httpd.conf:
        ----------
        __env__:
            base
        __sls__:
            webserver
        file:
            |_
              ----------
              source:
                  salt://apache/httpd.conf
            |_
              ----------
              user:
                  root
            |_
              ----------
              group:
                  root
            |_
              ----------
              mode:
                  644
            - managed
            |_
              ----------
              order:
                  10004
    apache:
        ----------
        __env__:
            base
            __sls__:
            webserver
        group:
            |_
              ----------
              gid:
                  87
            |_
              ----------
              require:
                  |_
                    ----------
                    pkg:
                        apache
            - present
    ...

Now propagate single SLS definition.

[email protected]:-# salt-call state.sls webserver
[INFO    ] Loading fresh modules for state activity
[INFO    ] Fetching file from saltenv 'base', ** skipped ** latest already in cache u'salt://webserver.sls'
[INFO    ] Running state [apache] at time 14:54:41.753275
[INFO    ] Executing state pkg.installed for apache
[INFO    ] Executing command ['dpkg-query', '--showformat', '${Status} ${Package} ${Version} ${Architecture}\n', '-W'] in directory '/root'
[INFO    ] Executing command 'apt-get -q update' in directory '/root'

...

Lab: Apply a Highstate

It is quite simple, just run the state.highstate function.

[email protected]:-# salt-call state.highstate
[INFO    ] Loading fresh modules for state activity
[INFO    ] Fetching file from saltenv 'base', ** skipped ** latest already in cache u'salt://top.sls'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/beacons'
[INFO    ] Syncing beacons for environment 'base'
[INFO    ] Loading cache from salt://_beacons, for base)
[INFO    ] Caching directory u'_beacons/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/modules'
[INFO    ] Syncing modules for environment 'base'
[INFO    ] Loading cache from salt://_modules, for base)
[INFO    ] Caching directory u'_modules/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/states'
[INFO    ] Syncing states for environment 'base'
[INFO    ] Loading cache from salt://_states, for base)
[INFO    ] Caching directory u'_states/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/sdb'
[INFO    ] Syncing sdb for environment 'base'
[INFO    ] Loading cache from salt://_sdb, for base)
[INFO    ] Caching directory u'_sdb/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/grains'
[INFO    ] Syncing grains for environment 'base'
[INFO    ] Loading cache from salt://_grains, for base)
[INFO    ] Caching directory u'_grains/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/renderers'
[INFO    ] Syncing renderers for environment 'base'
[INFO    ] Loading cache from salt://_renderers, for base)
[INFO    ] Caching directory u'_renderers/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/returners'
[INFO    ] Syncing returners for environment 'base'
[INFO    ] Loading cache from salt://_returners, for base)
[INFO    ] Caching directory u'_returners/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/output'
[INFO    ] Syncing output for environment 'base'
[INFO    ] Loading cache from salt://_output, for base)
[INFO    ] Caching directory u'_output/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/utils'
[INFO    ] Syncing utils for environment 'base'
[INFO    ] Loading cache from salt://_utils, for base)
[INFO    ] Caching directory u'_utils/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/log_handlers'
[INFO    ] Syncing log_handlers for environment 'base'
[INFO    ] Loading cache from salt://_log_handlers, for base)
[INFO    ] Caching directory u'_log_handlers/' for environment 'base'
[INFO    ] Creating module dir '/var/cache/salt/minion/extmods/proxy'
[INFO    ] Syncing proxy for environment 'base'
[INFO    ] Loading cache from salt://_proxy, for base)
[INFO    ] Caching directory u'_proxy/' for environment 'base'
[INFO    ] Loading fresh modules for state activity
[INFO    ] Fetching file from saltenv 'base', ** skipped ** latest already in cache u'salt://webserver.sls'
[INFO    ] Running state [apache] at time 14:55:28.152005
[INFO    ] Executing state pkg.installed for apache
[INFO    ] Executing command ['dpkg-query', '--showformat', '${Status} ${Package} ${Version} ${Architecture}\n', '-W'] in directory '/root'