# Renderers

The Salt state system operates by gathering information from common data types such as lists, dictionaries, and strings that would be familiar to any developer.

Salt Renderers translate input from the format in which it is written into Python data structures.

The default renderer is set in the master/minion configuration file using the `renderer` config option, which defaults to `jinja|yaml`.

## Two Kinds of Renderers

Renderers fall into one of two categories, based on what they output: text or data. Some exceptions to this would be the `pure python` and `gpg` renderers which could be used in either capacity.

### Text Renderers

Important

Jinja supports a secure, sandboxed template execution environment that Salt takes advantage of. Other text Renderers do not support this functionality, so Salt highly recommends usage of `jinja` / `jinja|yaml`.

A text renderer returns text. These include templating engines such as `jinja`, `mako`, and `genshi`, as well as the `gpg` renderer. The following are all text renderers:

- `aws_kms`

- `cheetah`

- `genshi`

- `gpg`

- `jinja`

- `mako`

- `nacl`

- `pass`

- `py`

- `wempy`

### Data Renderers

A data renderer returns a Python data structure (typically a dictionary). The following are all data renderers:

- `dson`

- `hjson`

- `json5`

- `json`

- `pydsl`

- `pyobjects`

- `py`

- `stateconf`

- `yamlex`

- `yaml`

- `gpg`

## Overriding the Default Renderer

It can sometimes be beneficial to write an SLS file using a renderer other than the default one. This can be done by using a "shebang"-like syntax on the first line of the SLS file:

Here is an example of using the `pure python` renderer to install a package:

    #!py

    def run():
        """
        Install version 1.5-1.el7 of package "python-foo"
        """
        return {
            "include": ["python"],
            "python-foo": {"pkg.installed": [{"version": "1.5-1.el7"}]},
        }

This would be equivalent to the following:

    include:
      - python

    python-foo:
      pkg.installed:
        - version: '1.5-1.el7'

## Composing Renderers (a.k.a. The "Render Pipeline")

A render pipeline can be composed from other renderers by connecting them in a series of "pipes" (i.e. `|`). The renderers will be evaluated from left to right, with each renderer receiving the result of the previous renderer's execution.

Take for example the default renderer (`jinja|yaml`). The file is evaluated first a jinja template, and the result of that template is evaluated as a YAML document.

Other render pipeline combinations include:

> `yaml`

>   Just YAML, no templating.

> `mako|yaml`

>   This passes the input to the `mako` renderer, with its output fed into the `yaml` renderer.

> `jinja|mako|yaml`

>   This one allows you to use both jinja and mako templating syntax in the input and then parse the final rendered output as YAML.

The following is a contrived example SLS file using the `jinja|mako|yaml` render pipeline:

    #!jinja|mako|yaml

    An_Example:
      cmd.run:
        - name: |
            echo "Using Salt ${grains['saltversion']}" \
                 "from path {{grains['saltpath']}}."
        - cwd: /

    <%doc> ${...} is Mako's notation, and so is this comment. </%doc>
    {#     Similarly, {{...}} is Jinja's notation, and so is this comment. #}

Important

Keep in mind that not all renderers can be used alone or with any other renderers. For example, text renderers shouldn't be used alone as their outputs are just strings, which still need to be parsed by another renderer to turn them into Python data structures.

For example, it would not make sense to use `yaml|jinja` because the output of the `yaml` renderer is a Python data structure, and the `jinja` renderer only accepts text as input.

Therefore, when combining renderers, you should know what each renderer accepts as input and what it returns as output. One way of thinking about it is that you can chain together multiple text renderers, but the pipeline must end in a data renderer. Similarly, since the text renderers in Salt don't accept data structures as input, a text renderer should usually not come after a data renderer. It's technically possible to write a renderer that takes a data structure as input and returns a string, but no such renderer is distributed with Salt.

## Writing Renderers

A custom renderer must be a Python module which implements a `render` function. This function must implement three positional arguments:

1. `data` - Can be called whatever you like. This is the input to be rendered.

2. `saltenv`

3. `sls`

The first is the important one, and the 2nd and 3rd must be included since Salt needs to pass this info to each render, even though it is only used by template renderers.

Renderers should be written so that the `data` argument can accept either strings or file-like objects as input. For example:

    import mycoolmodule
    from salt.ext import six

    def render(data, saltenv="base", sls="", **kwargs):
        if not isinstance(data, six.string_types):
            # Read from file-like object
            data = data.read()

        return mycoolmodule.do_something(data)

Custom renderers should be placed within `salt://_renderers/`, so that they can be synced to minions. They are synced when any of the following are run:

- `state.apply`

- `saltutil.sync_renderers`

- `saltutil.sync_all`

Any custom renderers which have been synced to a minion, that are named the same as one of Salt's default set of renderers, will take the place of the default renderer with the same name.

Note

Renderers can also be synced from `salt://_renderers/` to the Master using either the `saltutil.sync_renderers` or `saltutil.sync_all` runner function.

## Examples

The best place to find examples of renderers is in the Salt source code.

Documentation for renderers included with Salt can be found here:

salt/renderers

Here is a simple YAML renderer example:

    import salt.utils.yaml
    from salt.utils.yamlloader import SaltYamlSafeLoader
    from salt.ext import six

    def render(yaml_data, saltenv="", sls="", **kws):
        if not isinstance(yaml_data, six.string_types):
            yaml_data = yaml_data.read()
        data = salt.utils.yaml.safe_load(yaml_data)
        return data if data else {}

## Full List of Renderers

- renderer modules
  - salt.renderers.aws_kms
    - Setup
    - `render()`
  - salt.renderers.cheetah
    - `render()`
  - salt.renderers.dson
    - `render()`
  - salt.renderers.genshi
    - `render()`
  - salt.renderers.gpg
    - GPG Homedir
    - GPG Keys
      - New Key Pair
      - Export Public Key
      - Import Public Key
      - Export (Save) Private Key
      - Import (Restore) Private Key
      - Adjust trust level of imported keys
    - Encrypting Data
    - Encrypted CLI Pillar Data
      - Replacing Newlines
      - Encrypting the Entire CLI Pillar Dictionary
      - Configuration
    - `render()`
  - salt.renderers.hjson
    - `render()`
  - salt.renderers.jinja
    - `render()`
    - `SerializerExtension`
  - salt.renderers.json
    - `render()`
  - salt.renderers.json5
    - `render()`
  - salt.renderers.mako
    - `render()`
  - salt.renderers.msgpack
    - `render()`
  - salt.renderers.nacl
    - Setup
    - Using encrypted pillar
    - `render()`
  - salt.renderers.pass
    - Pass Renderer for Salt
      - Setup
    - `render()`
  - salt.renderers.py
    - Pure python state renderer
      - Full Example
    - `render()`
  - salt.renderers.pydsl
    - Special integration with the cmd state
    - Implicit ordering of states
    - Render time state execution
    - Integration with the stateconf renderer
    - Importing custom Python modules
    - `PyDslError`
    - `SaltRenderError`
    - `render()`
  - salt.renderers.pyobjects
    - Creating state data
    - Context Managers and requisites
    - Including and Extending
    - Importing from other state files
    - Salt object
    - Pillar, grain, mine & config data
    - Opts dictionary and SLS name
    - Map Data
    - `PyobjectsModule`
    - `load_states()`
    - `render()`
  - salt.renderers.stateconf
  - salt.renderers.toml
    - `render()`
  - salt.renderers.wempy
    - `render()`
  - salt.renderers.yaml
  - Understanding YAML
    - Rule One: Indentation
    - Rule Two: Colons
    - Rule Three: Dashes
    - Reference
      - `get_yaml_loader()`
      - `render()`
  - salt.renderers.yamlex
    - Reference
      - `render()`