# States tutorial, part 3

Note

This tutorial builds on topics covered in part 1 and part 2. It is recommended that you begin there.

This part of the tutorial will cover more advanced templating and configuration techniques for `sls` files.

## Templating SLS modules

SLS modules may require programming logic or inline execution. 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. To make use of the templating system, simply add some templating markup. An example of an sls module with templating markup 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

Here's a more complex example:

    {% for usr in 'moe','larry','curly' %}
    {{ usr }}:
      group:
        - present
      user:
        - present
        - gid_from_name: True
        - require:
          - group: {{ usr }}
    {% endfor %}

## Using Grains in SLS modules

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

    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:`

    moe:
      user:
        - present
        - gid: {{ salt['file.group_to_gid']('some_group_that_exists') }}

Note that for the above example to work, `some_group_that_exists` must exist before the state file is processed by the templating engine.

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

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

## Advanced SLS module syntax

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

### Include declaration

A previous example showed how to spread a Salt tree across several files. Similarly, requisites span multiple files by using an include declaration. For example:

`python/python-libs.sls:`

    python-dateutil:
      pkg.installed

`python/django.sls:`

    include:
      - python.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/apache.sls:`

    apache:
      pkg.installed

`apache/mywebsite.sls:`

    include:
      - apache.apache

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

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

Using extend with require or watch

The `extend` statement works differently for `require` or `watch`. It appends to, rather than replacing the requisite component.

### 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:

`apache/mywebsite.sls:`

    include:
      - apache.apache

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

    mywebsite:
      file.managed:
        - name: /etc/httpd/extra/httpd-vhosts.conf
        - source: salt://apache/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

## Next steps

In part 4 we will discuss how to use salt's `file_roots` to set up a workflow in which states can be "promoted" from dev, to QA, to production.

Current Salt release: 0.17.1

### Table Of Contents

- States tutorial, part 3
  - Templating SLS modules
  - Using Grains in SLS modules
  - Calling Salt modules from templates
  - Advanced SLS module syntax
    - `Include declaration`
    - `Extend declaration`
    - `Name declaration`
    - `Names declaration`
  - Next steps

#### Previous topic

States tutorial, part 2

#### Next topic

States tutorial, part 4

### Quick search

Enter search terms or a module, class or function name.

### Upcoming SaltStack Events

My conferences on Lanyrd