states_pt3.rst 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. .. _tutorial-states-part-3:
  2. =======================================================
  3. States tutorial, part 3 - Templating, Includes, Extends
  4. =======================================================
  5. .. note::
  6. This tutorial builds on topics covered in :ref:`part 1 <states-tutorial>` and
  7. :ref:`part 2 <tutorial-states-part-2>`. It is recommended that you begin there.
  8. This part of the tutorial will cover more advanced templating and
  9. configuration techniques for ``sls`` files.
  10. Templating SLS modules
  11. ======================
  12. SLS modules may require programming logic or inline execution. This is
  13. accomplished with module templating. The default module templating system used
  14. is `Jinja2`_ and may be configured by changing the :conf_master:`renderer`
  15. value in the master config.
  16. .. _`Jinja2`: https://jinja.palletsprojects.com/en/2.11.x/
  17. All states are passed through a templating system when they are initially read.
  18. To make use of the templating system, simply add some templating markup.
  19. An example of an sls module with templating markup may look like this:
  20. .. code-block:: jinja
  21. {% for usr in ['moe','larry','curly'] %}
  22. {{ usr }}:
  23. user.present
  24. {% endfor %}
  25. This templated sls file once generated will look like this:
  26. .. code-block:: yaml
  27. moe:
  28. user.present
  29. larry:
  30. user.present
  31. curly:
  32. user.present
  33. Here's a more complex example:
  34. .. code-blocK:: jinja
  35. # Comments in yaml start with a hash symbol.
  36. # Since jinja rendering occurs before yaml parsing, if you want to include jinja
  37. # in the comments you may need to escape them using 'jinja' comments to prevent
  38. # jinja from trying to render something which is not well-defined jinja.
  39. # e.g.
  40. # {# iterate over the Three Stooges using a {% for %}..{% endfor %} loop
  41. # with the iterator variable {{ usr }} becoming the state ID. #}
  42. {% for usr in 'moe','larry','curly' %}
  43. {{ usr }}:
  44. group:
  45. - present
  46. user:
  47. - present
  48. - gid_from_name: True
  49. - require:
  50. - group: {{ usr }}
  51. {% endfor %}
  52. Using Grains in SLS modules
  53. ===========================
  54. Often times a state will need to behave differently on different systems.
  55. :ref:`Salt grains <targeting-grains>` objects are made available in the template
  56. context. The `grains` can be used from within sls modules:
  57. .. code-block:: jinja
  58. apache:
  59. pkg.installed:
  60. {% if grains['os'] == 'RedHat' %}
  61. - name: httpd
  62. {% elif grains['os'] == 'Ubuntu' %}
  63. - name: apache2
  64. {% endif %}
  65. Using Environment Variables in SLS modules
  66. ==========================================
  67. You can use ``salt['environ.get']('VARNAME')`` to use an environment
  68. variable in a Salt state.
  69. .. code-block:: bash
  70. MYENVVAR="world" salt-call state.template test.sls
  71. .. code-block:: jinja
  72. Create a file with contents from an environment variable:
  73. file.managed:
  74. - name: /tmp/hello
  75. - contents: {{ salt['environ.get']('MYENVVAR') }}
  76. Error checking:
  77. .. code-block:: jinja
  78. {% set myenvvar = salt['environ.get']('MYENVVAR') %}
  79. {% if myenvvar %}
  80. Create a file with contents from an environment variable:
  81. file.managed:
  82. - name: /tmp/hello
  83. - contents: {{ salt['environ.get']('MYENVVAR') }}
  84. {% else %}
  85. Fail - no environment passed in:
  86. test.fail_without_changes
  87. {% endif %}
  88. Calling Salt modules from templates
  89. ===================================
  90. All of the Salt modules loaded by the minion are available within the
  91. templating system. This allows data to be gathered in real time on the target
  92. system. It also allows for shell commands to be run easily from within the sls
  93. modules.
  94. The Salt module functions are also made available in the template context as
  95. ``salt:``
  96. The following example illustrates calling the ``group_to_gid`` function in the
  97. ``file`` execution module with a single positional argument called
  98. ``some_group_that_exists``.
  99. .. code-block:: jinja
  100. moe:
  101. user.present:
  102. - gid: {{ salt['file.group_to_gid']('some_group_that_exists') }}
  103. One way to think about this might be that the ``gid`` key is being assigned
  104. a value equivalent to the following python pseudo-code:
  105. .. code-block:: python
  106. import salt.modules.file
  107. file.group_to_gid("some_group_that_exists")
  108. Note that for the above example to work, ``some_group_that_exists`` must exist
  109. before the state file is processed by the templating engine.
  110. Below is an example that uses the ``network.hw_addr`` function to retrieve the
  111. MAC address for eth0:
  112. .. code-block:: python
  113. salt["network.hw_addr"]("eth0")
  114. To examine the possible arguments to each execution module function,
  115. one can examine the `module reference documentation </ref/modules/all>`_:
  116. Advanced SLS module syntax
  117. ==========================
  118. Lastly, we will cover some incredibly useful techniques for more complex State
  119. trees.
  120. Include declaration
  121. -------------------
  122. A previous example showed how to spread a Salt tree across several files.
  123. Similarly, :ref:`requisites` span multiple files by
  124. using an :ref:`include-declaration`. For example:
  125. ``python/python-libs.sls:``
  126. .. code-block:: yaml
  127. python-dateutil:
  128. pkg.installed
  129. ``python/django.sls:``
  130. .. code-block:: yaml
  131. include:
  132. - python.python-libs
  133. django:
  134. pkg.installed:
  135. - require:
  136. - pkg: python-dateutil
  137. Extend declaration
  138. ------------------
  139. You can modify previous declarations by using an :ref:`extend-declaration`. For
  140. example the following modifies the Apache tree to also restart Apache when the
  141. vhosts file is changed:
  142. ``apache/apache.sls:``
  143. .. code-block:: yaml
  144. apache:
  145. pkg.installed
  146. ``apache/mywebsite.sls:``
  147. .. code-block:: yaml
  148. include:
  149. - apache.apache
  150. extend:
  151. apache:
  152. service:
  153. - running
  154. - watch:
  155. - file: /etc/httpd/extra/httpd-vhosts.conf
  156. /etc/httpd/extra/httpd-vhosts.conf:
  157. file.managed:
  158. - source: salt://apache/httpd-vhosts.conf
  159. .. include:: /_incl/extend_with_require_watch.rst
  160. Name declaration
  161. ----------------
  162. You can override the :ref:`id-declaration` by using a :ref:`name-declaration`.
  163. For example, the previous example is a bit more maintainable if rewritten as
  164. follows:
  165. ``apache/mywebsite.sls:``
  166. .. code-block:: yaml
  167. :emphasize-lines: 8,10,12
  168. include:
  169. - apache.apache
  170. extend:
  171. apache:
  172. service:
  173. - running
  174. - watch:
  175. - file: mywebsite
  176. mywebsite:
  177. file.managed:
  178. - name: /etc/httpd/extra/httpd-vhosts.conf
  179. - source: salt://apache/httpd-vhosts.conf
  180. Names declaration
  181. -----------------
  182. Even more powerful is using a :ref:`names-declaration` to override the
  183. :ref:`id-declaration` for multiple states at once. This often can remove the
  184. need for looping in a template. For example, the first example in this tutorial
  185. can be rewritten without the loop:
  186. .. code-block:: yaml
  187. stooges:
  188. user.present:
  189. - names:
  190. - moe
  191. - larry
  192. - curly
  193. Next steps
  194. ==========
  195. In :ref:`part 4 <tutorial-states-part-4>` we will discuss how to use salt's
  196. :conf_master:`file_roots` to set up a workflow in which states can be
  197. "promoted" from dev, to QA, to production.