States tutorial, part 3

This tutorial builds on the topic covered in part 2. It is recommended that you begin there.

This tutorial will cover more advanced templating and configuration techniques for sls files.

Templating SLS modules

SLS modules may require programming logic or inline executions. This is accomplished with module templating. The default module templating system used is Jinja2 and may be configured by changing the renderer value in the master config.

All states are passed through a templating system when they are initially read, so all that is required to make use of the templating system is to add some templating code. An example of an sls module with templating may look like this:

{% for usr in 'moe','larry','curly' %}
{{ usr }}:
  user.present
{% endfor %}

This templated sls file once generated will look like this:

moe:
  user.present
larry:
  user.present
curly:
  user.present

Using Grains in SLS modules

Often times a state will need to behave differently on different systems. Salt grains can be used from within sls modules. An object called grains is made available in the template context:

apache:
  pkg.installed:
    {% if grains['os'] == 'RedHat' %}
    - name: httpd
    {% elif grains['os'] == 'Ubuntu' %}
    - name: apache2
    {% endif %}

Calling Salt modules from templates

All of the Salt modules loaded by the minion are available within the templating system. This allows data to be gathered in real time on the target system. It also allows for shell commands to be run easily from within the sls modules.

The Salt module functions are also made available in the template context as salt:

{% for usr in 'moe','larry','curly' %}
{{ usr }}:
  group:
    - present
  user:
    - present
    - gid: {{ salt['file.group_to_gid'](usr) }}
    - require:
      - group: {{ usr }}
{% endfor %}

Below is an example that uses the network.hwaddr function to retrieve the MAC address for eth0:

salt['network.hwaddr']('eth0')

Advanced SLS module syntax

Last we will cover some incredibly useful techniques for more complex State trees.

Include declaration

You have seen an example of how to spread a Salt tree across several files but in order to be able to have requisite references span multiple files you must use an include declaration. For example:

python-libs.sls:

python-dateutil:
  pkg.installed

django.sls:

include:
  - python-libs

django:
  pkg.installed:
    - require:
      - pkg: python-dateutil

Extend declaration

You can modify previous declarations by using an extend declaration. For example the following modifies the Apache tree to also restart Apache when the vhosts file is changed:

apache.sls:

apache:
  pkg.installed

mywebsite.sls:

include:
  - apache

extend:
  apache:
    service:
      - watch:
        - file: /etc/httpd/extra/httpd-vhosts.conf

/etc/httpd/extra/httpd-vhosts.conf:
  file.managed:
    - source: salt://httpd-vhosts.conf

Name declaration

You can override the ID declaration by using a name declaration. For example, the previous example is a bit more maintainable if rewritten as follows:

mywebsite.sls:

include:
  - apache

extend:
  apache
    service:
      - watch:
        - file: mywebsite

mywebsite:
  file.managed:
    - name: /etc/httpd/extra/httpd-vhosts.conf
    - source: salt://httpd-vhosts.conf

Names declaration

Even more powerful is using a names declaration to override the ID declaration for multiple states at once. This often can remove the need for looping in a template. For example, the first example in this tutorial can be rewritten without the loop:

stooges:
  user.present:
    - names:
      - moe
      - larry
      - curly

Continue learning

The best way to continue learning about Salt States is to read through the reference documentation and to look through examples of existing state trees. You can find examples in the salt-states repository and please send a pull-request on GitHub with any state trees that you build and want to share!

If you have any questions, suggestions, or just want to chat with other people who are using Salt we have an active community.