Saltstack Official OpenSSH Formula
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
17KB

  1. .. _map.jinja:
  2. ``map.jinja``: gather formula configuration values
  3. ==================================================
  4. The `documentation`_ explains the use of a ``map.jinja`` to gather parameters values for a formula.
  5. As `pillars`_ are rendered on the Salt master for every minion, this increases the load on the master as the pillar values and the number of minions grows.
  6. As a good practice, you should:
  7. - store non-secret data in YAML files distributed by the `fileserver`_
  8. - store secret data in:
  9. - `pillars`_ (and look for the use of something like `pillar.vault`_)
  10. - `SDB`_ (and look for the use of something like `sdb.vault`_)
  11. Current best practice is to let ``map.jinja`` handle parameters from all sources, to minimise the use of pillars, grains or configuration from ``sls`` files and templates directly.
  12. .. contents:: **Table of Contents**
  13. For formula users
  14. -----------------
  15. Quick start: configure per role and per DNS domain name values
  16. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  17. We will see a quick setup to configure the ``TEMPLATE`` formula for different DNS domain name and several roles.
  18. For this example, I'll define 2 kinds of `fileserver`_ sources:
  19. 1. formulas git repositories with hard-coded version reference to avoid breaking my setup randomly at upstream update. they are the last sources where files are looked up
  20. 2. parameters of the formulas in the file backend `roots`_
  21. Configure the fileserver backends
  22. `````````````````````````````````
  23. I configure the `fileserver`_ backends to serve:
  24. 1. files from `roots`_ first
  25. 2. `gitfs`_ repositories last
  26. Create the file ``/etc/salt/master.d/fileserver.conf`` and restart the ``master``:
  27. .. code-block:: yaml
  28. ---
  29. ##
  30. ## file server
  31. ##
  32. fileserver_backend:
  33. # parameters values and override
  34. - roots
  35. # formulas
  36. - gitfs
  37. # The files in this directory will take precedence over git repositories
  38. file_roots:
  39. base:
  40. - /srv/salt
  41. # List of formulas I'm using
  42. gitfs_remotes:
  43. - https://github.com/saltstack-formulas/template-formula.git:
  44. - base: v4.1.1
  45. - https://github.com/saltstack-formulas/openssh-formula.git:
  46. - base: v2.0.1
  47. ...
  48. Create per DNS configuration for ``TEMPLATE`` formula
  49. `````````````````````````````````````````````````````
  50. Now, we can provides the per DNS domain name configuration files for the ``TEMPLATE`` formulas under ``/srv/salt/TEMPLATE/parameters/``.
  51. We create the directory for ``dns:domain`` grain and we add a symlink for the ``domain`` grain which is extracted from the minion ``id``:
  52. .. code-block:: console
  53. mkdir -p /srv/salt/TEMPLATE/parameters/dns:domain/
  54. ln -s dns:domain /srv/salt/TEMPLATE/parameters/domain
  55. We create a configuration for the DNS domain ``example.net`` in ``/srv/salt/TEMPLATE/parameters/dns:domain/example.net.yaml``:
  56. .. code-block:: yaml
  57. ---
  58. values:
  59. config: /etc/template-formula-example-net.conf
  60. ...
  61. We create another configuration for the DNS domain ``example.com`` in ``/srv/salt/TEMPLATE/parameters/dns:domain/example.com.yaml``:
  62. .. code-block:: yaml
  63. ---
  64. values:
  65. config: /etc/template-formula-{{ grains['os_family'] }}.conf
  66. ...
  67. Create per role configuration for ``TEMPLATE`` formula
  68. ``````````````````````````````````````````````````````
  69. Now, we can provides the per role configuration files for the ``TEMPLATE`` formulas under ``/srv/salt/TEMPLATE/parameters/``.
  70. We create the directory for roles:
  71. .. code-block:: console
  72. mkdir -p /srv/salt/TEMPLATE/parameters/roles
  73. We will define 2 roles:
  74. - ``TEMPLATE/server``
  75. - ``TEMPLATE/client``
  76. We create a configuration for the role ``TEMPLATE/server`` in ``/srv/salt/TEMPLATE/parameters/roles/TEMPLATE/server.yaml``:
  77. .. code-block:: yaml
  78. ---
  79. values:
  80. config: /etc/template-formula-server.conf
  81. ...
  82. We create another configuration for the role ``TEMPLATE/client`` in ``/srv/salt/TEMPLATE/parameters/roles/TEMPLATE/client.yaml``:
  83. .. code-block:: yaml
  84. ---
  85. values:
  86. config: /etc/template-formula-client.conf
  87. ...
  88. Enable roles and the ``dns:domain`` and ``domain`` grains for ``map.jinja``
  89. ```````````````````````````````````````````````````````````````````````````
  90. We need to redefine the sources for ``map.jinja`` to load values from our new configuration files, we provide a global configuration for all our minions.
  91. We create the global parameters file ``/srv/salt/parameters/map_jinja.yaml``:
  92. .. code-block:: yaml
  93. ---
  94. values:
  95. sources:
  96. # default values
  97. - "Y:G@osarch"
  98. - "Y:G@os_family"
  99. - "Y:G@os"
  100. - "Y:G@osfinger"
  101. - "C@{{ tplroot ~ ':lookup' }}"
  102. - "C@{{ tplroot }}"
  103. # Roles activate/deactivate things
  104. # then thing are configured depending on environment
  105. # So roles comes before `dns:domain`, `domain` and `id`
  106. - "Y:C@roles"
  107. # DNS domain configured (DHCP or resolv.conf)
  108. - "Y:G@dns:domain"
  109. # Based on minion ID
  110. - "Y:G@domain"
  111. # default values
  112. - "Y:G@id"
  113. ...
  114. The syntax is explained later at `Sources of configuration values`_.
  115. Bind roles to minions
  116. `````````````````````
  117. We associate roles `grains`_ to minion using `grains.append`_.
  118. For the servers:
  119. .. code-block:: console
  120. salt 'server-*' grains.append roles TEMPLATE/server
  121. For the clients:
  122. .. code-block:: console
  123. salt 'client-*' grains.append roles TEMPLATE/client
  124. .. note::
  125. Since we used ``Y:C@roles``, ``map.jinja`` will do a ``salt['config.get']('roles')`` to retrieve the roles so you could use any other method to bind roles to minions (`pillars`_ or `SDB`_) but `grains`_ seems to be the prefered method.
  126. Note for Microsoft Windows systems
  127. ``````````````````````````````````
  128. If you have a minion running under windows, you can't use colon ``:`` as a delimiter for grain path query (see `bug 58726`_) in which case you should use an alternate delimiter:
  129. Modify ``/srv/salt/parameters/map_jinja.yaml`` to change the query for ``dns:domain`` to define the `alternate delimiter`_:
  130. .. code-block:: yaml
  131. ---
  132. values:
  133. sources:
  134. # default values
  135. - "Y:G@osarch"
  136. - "Y:G@os_family"
  137. - "Y:G@os"
  138. - "Y:G@osfinger"
  139. - "C@{{ tplroot ~ ':lookup' }}"
  140. - "C@{{ tplroot }}"
  141. # Roles activate/deactivate things
  142. # then thing are configured depending on environment
  143. # So roles comes before `dns:domain`, `domain` and `id`
  144. - "Y:C@roles"
  145. # DNS domain configured (DHCP or resolv.conf)
  146. - "Y:G:!@dns!domain"
  147. # Based on minion ID
  148. - "Y:G@domain"
  149. # default values
  150. - "Y:G@id"
  151. ...
  152. And then, rename the directory:
  153. .. code-block:: console
  154. mv /srv/salt/TEMPLATE/parameters/dns:domain/ '/srv/salt/TEMPLATE/parameters/dns!domain/'
  155. Format of configuration YAML files
  156. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  157. When you write a new YAML file, note that it must conform to the following layout:
  158. - a mandatory ``values`` key to store the configuration values
  159. - two optional keys to configure the use of `salt.slsutil.merge`_
  160. - an optional ``strategy`` key to configure the merging strategy, for example ``strategy: 'recurse'``, the default is ``smart``
  161. - an optional ``merge_lists`` key to configure if lists should be merged or overridden for the ``recurse`` and ``overwrite`` strategy, for example ``merge_lists: 'true'``
  162. Here is a valid example:
  163. .. code-block:: yaml
  164. ---
  165. strategy: 'recurse'
  166. merge_lists: 'false'
  167. values:
  168. pkg:
  169. name: 'some-package'
  170. config: '/path/to/a/configuration/file'
  171. ...
  172. You can use `Jinja`_ as with any SLS files:
  173. .. code-block:: yaml
  174. ---
  175. strategy: 'overwrite'
  176. merge_lists: 'true'
  177. values:
  178. output_dir: /tmp/{{ grains['id'] }}
  179. ...
  180. Sources of configuration values
  181. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  182. Configuring ``map.jinja`` sources
  183. `````````````````````````````````
  184. The ``map.jinja`` file uses several sources where to lookup parameter values. The list of sources can be modified by two files:
  185. 1. a global ``salt://parameters/map_jinja.yaml``
  186. 2. a per formula ``salt://{{ tplroot }}/parameters/map_jinja.yaml``, it overrides the global configuration
  187. Each source definition has the form ``[<TYPE>[:<OPTION>[:<DELIMITER>]]@]<KEY>`` where ``<TYPE>`` can be one of:
  188. - ``Y`` to load values from YAML files from the `fileserver`_, this is the default when no type is defined
  189. - ``C`` to lookup values with `salt['config.get']`_
  190. - ``G`` to lookup values with `salt['grains.get']`_
  191. - ``I`` to lookup values with `salt['pillar.get']`_
  192. The YAML type option can define the query method to lookup the key value to build the file name:
  193. - ``C`` to query with `salt['config.get']`_, this is the default when no query method is defined
  194. - ``G`` to query with `salt['grains.get']`_
  195. - ``I`` to query with `salt['pillar.get']`_
  196. The ``C``, ``G`` or ``I`` types can define the ``SUB`` option to store values in the sub key ``mapdata.<KEY>`` instead of directly in ``mapdata``.
  197. All types can define the ``<DELIMITER>`` option to use an `alternate delimiter`_ of the ``<KEY>``, for example: on windows system you can't use colon ``:`` for YAML file path name and you should use something else like exclamation mark ``!``.
  198. Finally, the ``<KEY>`` describes what to lookup to either build the YAML filename or gather values using one of the query methods.
  199. .. note::
  200. For the YAML type, if the ``<KEY>`` can't be looked up, then it's used a literal string path to a YAML file, for example: ``any/path/can/be/used/here.yaml`` will result in the loading of ``salt://{{ tplroot }}/parameters/any/path/can/be/used/here.yaml`` if it exists.
  201. The built-in ``map_jinja:sources`` is:
  202. .. code-block:: yaml
  203. - "Y:G@osarch"
  204. - "Y:G@os_family"
  205. - "Y:G@os"
  206. - "Y:G@osfinger"
  207. - "C@{{ tplroot ~ ':lookup' }}"
  208. - "C@{{ tplroot }}"
  209. - "Y:G@id"
  210. This is strictly equivalent to the following ``map_jinja.yaml`` using `Jinja`_:
  211. .. code-block:: sls
  212. values:
  213. sources:
  214. - "parameters/osarch/{{ salt['grains.get']('osarch') }}.yaml"
  215. - "parameters/os_family/{{ salt['grains.get']('os_family') }}.yaml"
  216. - "parameters/os/{{ salt['grains.get']('os') }}.yaml"
  217. - "parameters/osfinger/{{ salt['grains.get']('osfinger') }}.yaml"
  218. - "C@{{ tplroot ~ ':lookup' }}"
  219. - "C@{{ tplroot }}"
  220. - "parameters/id/{{ salt['grains.get']('id') }}.yaml"
  221. Loading values from the configuration sources
  222. `````````````````````````````````````````````
  223. For each configuration source defined in ``map_jinja:sources``, ``map.jinja`` will:
  224. #. load values depending on the source type:
  225. - for YAML file sources
  226. - if the ``<KEY>`` can be looked up, load values from the YAML file named ``salt://{{ tplroot }}/paramaters/<KEY>/{{ salt['<QUERY_METHOD>']('<KEY>') }}.yaml`` if it exists
  227. - otherwise, load the YAML file named ``salt://{{ tplroot }}/parameters/<KEY>.yaml`` if it exists
  228. - for ``C``, ``G`` or ``I`` source type, lookup the value of ``salt['<QUERY_METHOD>']('<KEY>')``
  229. #. merge the loaded values with the previous ones using `salt.slsutil.merge`_
  230. There will be no error if a YAML file does not exists, they are all optional.
  231. Configuration values from ``salt['config.get']``
  232. ````````````````````````````````````````````````
  233. For sources with of type ``C`` declared in ``map_jinja:sources``, you can configure the ``merge`` option of `salt['config.get']`_ by defining per formula ``strategy`` configuration key (retrieved with ``salt['config.get'](tplroot ~ ':strategy')`` with one of the following values:
  234. - ``recurse`` merge recursively dictionaries. Non dictionary values replace already defined values
  235. - ``overwrite`` new value completely replace old ones
  236. By default, no merging is done, the first value found is returned.
  237. Global view of the order of preferences
  238. ```````````````````````````````````````
  239. To summarize, here is a complete example of the load order of formula configuration values for an ``AMD64`` ``Ubuntu 18.04`` minion named ``minion1.example.net`` for the ``libvirt`` formula:
  240. #. ``parameters/defaults.yaml``
  241. #. ``parameters/osarch/amd64.yaml``
  242. #. ``parameters/os_family/Debian.yaml``
  243. #. ``parameters/os/Ubuntu.yaml``
  244. #. ``parameters/osfinger/Ubuntu-18.04.yaml``
  245. #. ``salt['config.get']('libvirt:lookup')``
  246. #. ``salt['config.get']('libvirt')``
  247. #. ``parameters/id/minion1.example.net``
  248. Remember that the order is important, for example, the value of ``key1:subkey1`` loaded from ``parameters/os_family/Debian.yaml`` is overridden by a value loaded from ``parameters/id/minion1.example.net``.
  249. For formula authors and contributors
  250. ------------------------------------
  251. Dependencies
  252. ^^^^^^^^^^^^
  253. ``map.jinja`` requires:
  254. - salt minion 2018.3.3 minimum to use the `traverse`_ jinja filter
  255. - to be located at the root of the formula named directory (e.g. ``libvirt-formula/libvirt/map.jinja``)
  256. - the ``libsaltcli.jinja`` library, stored in the same directory, to disable the ``merge`` option of `salt['config.get']`_ over `salt-ssh`_
  257. Use formula configuration values in ``sls``
  258. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  259. The ``map.jinja`` exports a unique ``mapdata`` variable which could be renamed during import.
  260. Here is the best way to use it in an ``sls`` file:
  261. .. code-block:: sls
  262. {#- Get the `tplroot` from `tpldir` #}
  263. {%- set tplroot = tpldir.split("/")[0] %}
  264. {%- from tplroot ~ "/map.jinja" import mapdata as TEMPLATE with context %}
  265. test-does-nothing-but-display-TEMPLATE-as-json:
  266. test.nop:
  267. - name: {{ TEMPLATE | json }}
  268. Use formula configuration values in templates
  269. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  270. When you need to process salt templates, you should avoid calling `salt['config.get']`_ (or `salt['pillar.get']`_ and `salt['grains.get']`_) directly from the template. All the needed values should be available within the ``mapdata`` variable exported by ``map.jinja``.
  271. Here is an example based on `template-formula/TEMPLATE/config/file.sls`_:
  272. .. code-block:: sls
  273. # -*- coding: utf-8 -*-
  274. # vim: ft=sls
  275. {#- Get the `tplroot` from `tpldir` #}
  276. {%- set tplroot = tpldir.split('/')[0] %}
  277. {%- set sls_package_install = tplroot ~ '.package.install' %}
  278. {%- from tplroot ~ "/map.jinja" import mapdata as TEMPLATE with context %}
  279. {%- from tplroot ~ "/libtofs.jinja" import files_switch with context %}
  280. include:
  281. - {{ sls_package_install }}
  282. TEMPLATE-config-file-file-managed:
  283. file.managed:
  284. - name: {{ TEMPLATE.config }}
  285. - source: {{ files_switch(['example.tmpl'],
  286. lookup='TEMPLATE-config-file-file-managed'
  287. )
  288. }}
  289. - mode: 644
  290. - user: root
  291. - group: {{ TEMPLATE.rootgroup }}
  292. - makedirs: True
  293. - template: jinja
  294. - require:
  295. - sls: {{ sls_package_install }}
  296. - context:
  297. TEMPLATE: {{ TEMPLATE | json }}
  298. This ``sls`` file expose a ``TEMPLATE`` context variable to the jinja template which could be used like this:
  299. .. code-block:: jinja
  300. ########################################################################
  301. # File managed by Salt at <{{ source }}>.
  302. # Your changes will be overwritten.
  303. ########################################################################
  304. This is another example file from SaltStack template-formula.
  305. # This is here for testing purposes
  306. {{ TEMPLATE | json }}
  307. winner of the merge: {{ TEMPLATE['winner'] }}
  308. .. _documentation: https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html#writing-formulas
  309. .. _fileserver: https://docs.saltstack.com/en/latest/ref/file_server
  310. .. _salt['config.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.config.html#salt.modules.config.get
  311. .. _salt['grains.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.grains.html#salt.modules.grains.get
  312. .. _salt['pillar.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.pillar.html#salt.modules.pillar.get
  313. .. _alternate delimiter: https://docs.saltstack.com/en/latest/topics/targeting/compound.html#alternate-delimiters
  314. .. _pillar.vault: https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.vault.html
  315. .. _pillars: https://docs.saltstack.com/en/latest/topics/pillar/
  316. .. _grains: https://docs.saltstack.com/en/latest/topics/grains/
  317. .. _grains.append: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.grains.html#salt.modules.grains.append
  318. .. _SDB: https://docs.saltstack.com/en/latest/topics/sdb/index.html
  319. .. _sdb.vault: https://docs.saltstack.com/en/latest/ref/sdb/all/salt.sdb.vault.html
  320. .. _Jinja: https://docs.saltstack.com/en/latest/topics/jinja
  321. .. _roots: https://docs.saltstack.com/en/latest/ref/file_server/all/salt.fileserver.roots.html
  322. .. _gitfs: https://docs.saltstack.com/en/latest/topics/tutorials/gitfs.html
  323. .. _salt.slsutil.merge: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.slsutil.html
  324. .. _traverse: https://docs.saltstack.com/en/latest/topics/jinja/index.html#traverse
  325. .. _salt-ssh: https://docs.saltstack.com/en/latest/topics/ssh/
  326. .. _template-formula/TEMPLATE/config/file.sls: https://github.com/saltstack-formulas/template-formula/blob/master/TEMPLATE/config/file.sls
  327. .. _bug 58726: https://github.com/saltstack/salt/issues/58726