Skip to content

Commit 4db7d6f

Browse files
committed
feat(map): the YAML files must not use any Jinja
For each `.yaml` file that `map.jinja` try to load, a `.yaml.jinja` Jinja template is tried right after to permit jinja manipulation of values and circumvent yamllint errors when using Jinja in YAML files. At the end of the load of YAML files and Jinja YAML templates, `map.jinja` include an optional `post-map.jinja` for post-processing the `mapdata` variable.
1 parent c28acb9 commit 4db7d6f

File tree

5 files changed

+85
-20
lines changed

5 files changed

+85
-20
lines changed

docs/map.jinja.rst

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ We create a configuration for the DNS domain ``example.net`` in ``/srv/salt/TEMP
9393
config: /etc/template-formula-example-net.conf
9494
...
9595
96-
We create another configuration for the DNS domain ``example.com`` in ``/srv/salt/TEMPLATE/parameters/dns:domain/example.com.yaml``:
96+
We create another configuration for the DNS domain ``example.com`` in the Jinja YAML template ``/srv/salt/TEMPLATE/parameters/dns:domain/example.com.yaml.jinja``:
9797

9898
.. code-block:: yaml
9999
@@ -263,15 +263,21 @@ Here is a valid example:
263263
config: '/path/to/a/configuration/file'
264264
...
265265
266-
You can use `Jinja`_ as with any SLS files:
267266
268-
.. code-block:: yaml
267+
Using Jinja2 YAML template
268+
``````````````````````````
269+
270+
You can provide a Jinja2 YAML template file with a name suffixed with ``.yaml.jinja``, it must produce a YAML file conform to the `Format of configuration YAML files`_, for example:
271+
272+
.. code-block:: jinja2
269273
270274
---
271275
strategy: 'overwrite'
272276
merge_lists: 'true'
273277
values:
274-
output_dir: /tmp/{{ grains['id'] }}
278+
{%- if grains["os"] == "Debian" %}
279+
output_dir: /tmp/{{ grains["id"] }}
280+
{%- endif %}
275281
...
276282
277283
@@ -285,13 +291,24 @@ The ``map.jinja`` file aggregates configuration values from several sources:
285291
- `grains`_
286292
- configuration gathered with `salt['config.get']`_
287293

294+
For the values loaded from YAML files, ``map.jinja`` will automatically try to load a Jinja2 template with the same name as the YAML file with the addition of the ``.jinja`` extension, for example ``foo/bar/quux.yaml.jinja``.
295+
296+
After loading values from all sources, it will try to include the ``salt://parameters/post-map.jinja`` Jinja file if it exists which can post-process the ``mapdata`` variable.
297+
288298
Configuring ``map.jinja`` sources
289299
`````````````````````````````````
290300

291301
The ``map.jinja`` file uses several sources where to lookup parameter values. The list of sources can be configured in two places:
292302

293-
1. a global ``salt://parameters/map_jinja.yaml``
294-
2. a per formula ``salt://{{ tplroot }}/parameters/map_jinja.yaml``, it overrides the global configuration
303+
1. globally
304+
305+
1. with a plain YAML file ``salt://parameters/map_jinja.yaml``
306+
2. with a Jinja2 YAML template file ``salt://parameters/map_jinja.yaml.jinja``
307+
308+
2. per formula
309+
310+
1. with a plain YAML file ``salt://{{ tplroot }}/parameters/map_jinja.yaml``
311+
2. with a Jinja2 YAML template file ``salt://{{ tplroot }}/parameters/map_jinja.yaml.jinja``
295312

296313
.. note::
297314

@@ -318,7 +335,10 @@ Finally, the ``<KEY>`` describes what to lookup to either build the YAML filenam
318335

319336
.. note::
320337

321-
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.
338+
For the YAML type:
339+
340+
- 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
341+
- ``map.jinja`` will automatically try to load a Jinja2 template, after the corresponding YAML file, with the same name as the YAML file extended with the ``.jinja`` extension, for example ``any/path/can/be/used/here.yaml.jinja``
322342

323343
The built-in ``map.jinja`` sources are:
324344

@@ -332,19 +352,24 @@ The built-in ``map.jinja`` sources are:
332352
- "C@{{ tplroot }}"
333353
- "Y:G@id"
334354
335-
This is strictly equivalent to the following ``map_jinja.yaml`` using `Jinja`_:
355+
This is strictly equivalent to the following ``map_jinja.yaml.jinja``:
336356

337357
.. code-block:: sls
338358
339359
values:
340360
sources:
341361
- "parameters/osarch/{{ salt['grains.get']('osarch') }}.yaml"
362+
- "parameters/osarch/{{ salt['grains.get']('osarch') }}.yaml.jinja"
342363
- "parameters/os_family/{{ salt['grains.get']('os_family') }}.yaml"
364+
- "parameters/os_family/{{ salt['grains.get']('os_family') }}.yaml.jinja"
343365
- "parameters/os/{{ salt['grains.get']('os') }}.yaml"
366+
- "parameters/os/{{ salt['grains.get']('os') }}.yaml.jinja"
344367
- "parameters/osfinger/{{ salt['grains.get']('osfinger') }}.yaml"
368+
- "parameters/osfinger/{{ salt['grains.get']('osfinger') }}.yaml.jinja"
345369
- "C@{{ tplroot ~ ':lookup' }}"
346370
- "C@{{ tplroot }}"
347371
- "parameters/id/{{ salt['grains.get']('id') }}.yaml"
372+
- "parameters/id/{{ salt['grains.get']('id') }}.yaml.jinja"
348373
349374
350375
Loading values from the configuration sources
@@ -356,14 +381,21 @@ For each configuration source defined, ``map.jinja`` will:
356381

357382
- for YAML file sources
358383

359-
- 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
360-
- otherwise, load the YAML file named ``salt://{{ tplroot }}/parameters/<KEY>.yaml`` if it exists
384+
- if the ``<KEY>`` can be looked up:
385+
386+
- load values from the YAML file named ``salt://{{ tplroot }}/paramaters/<KEY>/{{ salt['<QUERY_METHOD>']('<KEY>') }}.yaml`` if it exists
387+
- load values from the Jinja2 YAML template file named ``salt://{{ tplroot }}/paramaters/<KEY>/{{ salt['<QUERY_METHOD>']('<KEY>') }}.yaml.jinja`` if it exists
388+
389+
- otherwise:
390+
391+
- load the YAML file named ``salt://{{ tplroot }}/parameters/<KEY>.yaml`` if it exists
392+
- load the Jinja2 YAML template file named ``salt://{{ tplroot }}/parameters/<KEY>.yaml.jinja`` if it exists
361393

362394
- for ``C``, ``G`` or ``I`` source type, lookup the value of ``salt['<QUERY_METHOD>']('<KEY>')``
363395

364396
#. merge the loaded values with the previous ones using `salt.slsutil.merge`_
365397

366-
There will be no error if a YAML file does not exists, they are all optional.
398+
There will be no error if a YAML or Jinja2 file does not exists, they are all optional.
367399

368400

369401
Configuration values from ``salt['config.get']``
@@ -383,13 +415,19 @@ Global view of the order of preferences
383415
To summarise, 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:
384416

385417
#. ``parameters/defaults.yaml``
418+
#. ``parameters/defaults.yaml.jinja``
386419
#. ``parameters/osarch/amd64.yaml``
420+
#. ``parameters/osarch/amd64.yaml.jinja``
387421
#. ``parameters/os_family/Debian.yaml``
422+
#. ``parameters/os_family/Debian.yaml.jinja``
388423
#. ``parameters/os/Ubuntu.yaml``
424+
#. ``parameters/os/Ubuntu.yaml.jinja``
389425
#. ``parameters/osfinger/Ubuntu-18.04.yaml``
426+
#. ``parameters/osfinger/Ubuntu-18.04.yaml.jinja``
390427
#. ``salt['config.get']('libvirt:lookup')``
391428
#. ``salt['config.get']('libvirt')``
392429
#. ``parameters/id/minion1.example.net.yaml``
430+
#. ``parameters/id/minion1.example.net.yaml.jinja``
393431

394432
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.yaml``.
395433

openvpn/libmapstack.jinja

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,19 @@
196196
{%- set yaml_names = [yaml_names] %}
197197
{%- endif %}
198198

199+
{#- Try to load a `.yaml.jinja` file for each `.yaml` file #}
200+
{%- set all_yaml_names = [] %}
201+
{%- for name in yaml_names %}
202+
{%- set extension = name.rpartition(".")[2] %}
203+
{%- if extension not in ["yaml", "jinja"] %}
204+
{%- do all_yaml_names.extend([name ~ ".yaml", name ~ ".yaml.jinja"]) %}
205+
{%- elif extension == "yaml" %}
206+
{%- do all_yaml_names.extend([name, name ~ ".jinja"]) %}
207+
{%- else %}
208+
{%- do all_yaml_names.append(name) %}
209+
{%- endif %}
210+
{%- endfor %}
211+
199212
{#- `yaml_dirname` can be an empty string with literal path like `myconf.yaml` #}
200213
{%- set yaml_dir = [
201214
param_dir,
@@ -204,15 +217,10 @@
204217
| select
205218
| join("/") %}
206219

207-
{%- for yaml_name in yaml_names %}
208-
{#- Make sure to have a `.yaml` extension #}
209-
{#- Use `.rpartition` to strip last `.yaml` in `dir.yaml/file.yaml` #}
220+
{%- for yaml_name in all_yaml_names %}
210221
{%- set yaml_filename = [
211222
yaml_dir.rstrip("/"),
212-
yaml_name.rpartition(".yaml")
213-
| reject("equalto", ".yaml")
214-
| join
215-
~ ".yaml"
223+
yaml_name
216224
]
217225
| select
218226
| join("/") %}

openvpn/map.jinja

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
{#- Load formula parameters values #}
4040
{%- set _formula_matchers = ["defaults.yaml"] + map_sources %}
41+
4142
{%- set _formula_settings = mapstack(
4243
matchers=_formula_matchers,
4344
dirs=[formula_param_dir],
@@ -59,3 +60,7 @@
5960

6061
{%- do salt["log.debug"]("map.jinja: save parameters in variable 'mapdata'") %}
6162
{%- set mapdata = _formula_settings["values"] %}
63+
64+
{#- Per formula post-processing of `mapdata` if it exists #}
65+
{%- do salt["log.debug"]("map.jinja: post-processing of 'mapdata'") %}
66+
{%- include tplroot ~ "/post-map.jinja" ignore missing %}

openvpn/parameters/defaults.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# yamllint disable-file
21
# -*- coding: utf-8 -*-
32
# vim: ft=yaml
43
---
@@ -14,7 +13,7 @@ values:
1413
group: nobody
1514
# None, will default to 'user'
1615
log_user: ~
17-
multi_services: {{ salt['grains.has_value']('systemd') }}
16+
multi_services: false
1817
pkgs: ['openvpn']
1918
service: openvpn
2019
service_function: running
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{#- -*- coding: utf-8 -*- #}
2+
{#- vim: ft=jinja #}
3+
{#-
4+
Setup variables after loading `defaults.yaml`.
5+
6+
This jinja2 file must return a valid `map.jinja` YAML which will
7+
be merged into `defaults.yaml`.
8+
9+
If you do not need to provide calculated defaults, you can remove
10+
this file or provide at least an empty dict, e.g. values: {}
11+
#}
12+
---
13+
values:
14+
multi_services: {{ salt['grains.has_value']('systemd') }}
15+
...

0 commit comments

Comments
 (0)