1"""
2Pure python state renderer
3==========================
4
5To use this renderer, the SLS file should contain a function called ``run``
6which returns highstate data.
7
8The highstate data is a dictionary containing identifiers as keys, and execution
9dictionaries as values. For example the following state declaration in YAML:
10
11.. code-block:: yaml
12
13    common_packages:
14      pkg.installed:
15       - pkgs:
16          - curl
17          - vim
18
19translates to:
20
21.. code-block:: python
22
23     {'common_packages': {'pkg.installed': [{'pkgs': ['curl', 'vim']}]}}
24
25In this module, a few objects are defined for you, giving access to Salt's
26execution functions, grains, pillar, etc. They are:
27
28- ``__salt__`` - :ref:`Execution functions <all-salt.modules>` (i.e.
29  ``__salt__['test.echo']('foo')``)
30- ``__grains__`` - :ref:`Grains <targeting-grains>` (i.e. ``__grains__['os']``)
31- ``__pillar__`` - :ref:`Pillar data <pillar>` (i.e. ``__pillar__['foo']``)
32- ``__opts__`` - Minion configuration options
33- ``__env__`` - The effective salt fileserver environment (i.e. ``base``). Also
34  referred to as a "saltenv". ``__env__`` should not be modified in a pure
35  python SLS file. To use a different environment, the environment should be
36  set when executing the state. This can be done in a couple different ways:
37
38  - Using the ``saltenv`` argument on the salt CLI (i.e. ``salt '*' state.sls
39    foo.bar.baz saltenv=env_name``).
40  - By adding a ``saltenv`` argument to an individual state within the SLS
41    file. In other words, adding a line like this to the state's data
42    structure: ``{'saltenv': 'env_name'}``
43
44- ``__sls__`` - The SLS path of the file. For example, if the root of the base
45  environment is ``/srv/salt``, and the SLS file is
46  ``/srv/salt/foo/bar/baz.sls``, then ``__sls__`` in that file will be
47  ``foo.bar.baz``.
48
49When writing a reactor SLS file the global context ``data`` (same as context ``{{ data }}``
50for states written with Jinja + YAML) is available. The following YAML + Jinja state declaration:
51
52.. code-block:: jinja
53
54    {% if data['id'] == 'mysql1' %}
55    highstate_run:
56      local.state.apply:
57        - tgt: mysql1
58    {% endif %}
59
60translates to:
61
62.. code-block:: python
63
64    if data['id'] == 'mysql1':
65        return {'highstate_run': {'local.state.apply': [{'tgt': 'mysql1'}]}}
66
67Full Example
68------------
69
70.. code-block:: python
71   :linenos:
72
73    #!py
74
75    def run():
76        config = {}
77
78        if __grains__['os'] == 'Ubuntu':
79            user = 'ubuntu'
80            group = 'ubuntu'
81            home = '/home/{0}'.format(user)
82        else:
83            user = 'root'
84            group = 'root'
85            home = '/root/'
86
87        config['s3cmd'] = {
88            'pkg': [
89                'installed',
90                {'name': 's3cmd'},
91            ],
92        }
93
94        config[home + '/.s3cfg'] = {
95            'file.managed': [
96                {'source': 'salt://s3cfg/templates/s3cfg'},
97                {'template': 'jinja'},
98                {'user': user},
99                {'group': group},
100                {'mode': 600},
101                {'context': {
102                    'aws_key': __pillar__['AWS_ACCESS_KEY_ID'],
103                    'aws_secret_key': __pillar__['AWS_SECRET_ACCESS_KEY'],
104                    },
105                },
106            ],
107        }
108
109        return config
110
111"""
112
113import os
114
115import salt.utils.templates
116from salt.exceptions import SaltRenderError
117
118
119def render(template, saltenv="base", sls="", tmplpath=None, **kws):
120    """
121    Render the python module's components
122
123    :rtype: string
124    """
125    template = tmplpath
126    if not os.path.isfile(template):
127        raise SaltRenderError("Template {} is not a file!".format(template))
128
129    tmp_data = salt.utils.templates.py(
130        template,
131        True,
132        __salt__=__salt__,
133        salt=__salt__,
134        __grains__=__grains__,
135        grains=__grains__,
136        __opts__=__opts__,
137        opts=__opts__,
138        __pillar__=__pillar__,
139        pillar=__pillar__,
140        __env__=saltenv,
141        saltenv=saltenv,
142        __sls__=sls,
143        sls=sls,
144        **kws
145    )
146    if not tmp_data.get("result", False):
147        raise SaltRenderError(
148            tmp_data.get("data", "Unknown render error in py renderer")
149        )
150
151    return tmp_data["data"]
152