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. | 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. | ||||
Note for Microsoft Windows systems | |||||
`````````````````````````````````` | |||||
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: | |||||
Modify ``/srv/salt/parameters/map_jinja.yaml`` to change the query for ``dns:domain`` to define the `alternate delimiter`_: | |||||
.. code-block:: yaml | |||||
--- | |||||
values: | |||||
sources: | |||||
# default values | |||||
- "Y:G@osarch" | |||||
- "Y:G@os_family" | |||||
- "Y:G@os" | |||||
- "Y:G@osfinger" | |||||
- "C@{{ tplroot ~ ':lookup' }}" | |||||
- "C@{{ tplroot }}" | |||||
# Roles activate/deactivate things | |||||
# then thing are configured depending on environment | |||||
# So roles comes before `dns:domain`, `domain` and `id` | |||||
- "Y:C@roles" | |||||
# DNS domain configured (DHCP or resolv.conf) | |||||
- "Y:G:!@dns!domain" | |||||
# Based on minion ID | |||||
- "Y:G@domain" | |||||
# default values | |||||
- "Y:G@id" | |||||
... | |||||
And then, rename the directory: | |||||
.. code-block:: console | |||||
mv /srv/salt/TEMPLATE/parameters/dns:domain/ '/srv/salt/TEMPLATE/parameters/dns!domain/' | |||||
Format of configuration YAML files | Format of configuration YAML files | ||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||
1. a global ``salt://parameters/map_jinja.yaml`` | 1. a global ``salt://parameters/map_jinja.yaml`` | ||||
2. a per formula ``salt://{{ tplroot }}/parameters/map_jinja.yaml``, it overrides the global configuration | 2. a per formula ``salt://{{ tplroot }}/parameters/map_jinja.yaml``, it overrides the global configuration | ||||
Each source definition has the form ``<TYPE>:<OPTION>@<KEY>`` where ``<TYPE>`` can be one of: | |||||
Each source definition has the form ``[<TYPE>[:<OPTION>[:<DELIMITER>]]@]<KEY>`` where ``<TYPE>`` can be one of: | |||||
- ``Y`` to load values from YAML files from the `fileserver`_, this is the default when no type is defined | - ``Y`` to load values from YAML files from the `fileserver`_, this is the default when no type is defined | ||||
- ``C`` to lookup values with `salt['config.get']`_ | - ``C`` to lookup values with `salt['config.get']`_ | ||||
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``. | 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``. | ||||
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 ``!``. | |||||
Finally, the ``<KEY>`` describes what to lookup to either build the YAML filename or gather values using one of the query methods. | Finally, the ``<KEY>`` describes what to lookup to either build the YAML filename or gather values using one of the query methods. | ||||
.. note:: | .. note:: | ||||
.. _salt['config.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.config.html#salt.modules.config.get | .. _salt['config.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.config.html#salt.modules.config.get | ||||
.. _salt['grains.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.grains.html#salt.modules.grains.get | .. _salt['grains.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.grains.html#salt.modules.grains.get | ||||
.. _salt['pillar.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.pillar.html#salt.modules.pillar.get | .. _salt['pillar.get']: https://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.pillar.html#salt.modules.pillar.get | ||||
.. _alternate delimiter: https://docs.saltstack.com/en/latest/topics/targeting/compound.html#alternate-delimiters | |||||
.. _pillar.vault: https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.vault.html | .. _pillar.vault: https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.vault.html | ||||
.. _pillars: https://docs.saltstack.com/en/latest/topics/pillar/ | .. _pillars: https://docs.saltstack.com/en/latest/topics/pillar/ | ||||
.. _grains: https://docs.saltstack.com/en/latest/topics/grains/ | .. _grains: https://docs.saltstack.com/en/latest/topics/grains/ | ||||
.. _traverse: https://docs.saltstack.com/en/latest/topics/jinja/index.html#traverse | .. _traverse: https://docs.saltstack.com/en/latest/topics/jinja/index.html#traverse | ||||
.. _salt-ssh: https://docs.saltstack.com/en/latest/topics/ssh/ | .. _salt-ssh: https://docs.saltstack.com/en/latest/topics/ssh/ | ||||
.. _template-formula/TEMPLATE/config/file.sls: https://github.com/saltstack-formulas/template-formula/blob/master/TEMPLATE/config/file.sls | .. _template-formula/TEMPLATE/config/file.sls: https://github.com/saltstack-formulas/template-formula/blob/master/TEMPLATE/config/file.sls | ||||
.. _bug 58726: https://github.com/saltstack/salt/issues/58726 |
{#- When no part before `@` is provided: #} | {#- When no part before `@` is provided: #} | ||||
{#- - define a filename path, noted `F` #} | {#- - define a filename path, noted `F` #} | ||||
{#- - use `salt["config.get"]`, noted `C` #} | {#- - use `salt["config.get"]`, noted `C` #} | ||||
{#- - use colon `:` delimiter for querying #} | |||||
{%- set _defaults = { | {%- set _defaults = { | ||||
"type": "F", | "type": "F", | ||||
"query_type": "C", | "query_type": "C", | ||||
"query_delimiter": ":" | |||||
} %} | } %} | ||||
{%- macro parse_matchers( | {%- macro parse_matchers( | ||||
config_get_strategy=None, | config_get_strategy=None, | ||||
log_prefix="libmatchers: " | log_prefix="libmatchers: " | ||||
) %} | ) %} | ||||
{#- matcher format is `[<TYPE>[:<OPTION>]@]<KEY>` #} | |||||
{#- matcher format is `[<TYPE>[:<OPTION>[:DELIMITER]]@]<KEY>` #} | |||||
{#- each matcher has a type: #} | {#- each matcher has a type: #} | ||||
{#- - `F` to build a file name (the default when no type is set) #} | {#- - `F` to build a file name (the default when no type is set) #} | ||||
{#- - `C` to lookup values with `config.get` #} | {#- - `C` to lookup values with `config.get` #} | ||||
{#- - `C` for query with `config.get` (the default when to query type is set) #} | {#- - `C` for query with `config.get` (the default when to query type is set) #} | ||||
{#- - `G` for query with `grains.get` #} | {#- - `G` for query with `grains.get` #} | ||||
{#- - `I` for query with `pillar.get` #} | {#- - `I` for query with `pillar.get` #} | ||||
{#- With `DELIMITER`, you can choose a different delimiter when doing queries #} | |||||
{%- set parsed_matchers = [] %} | {%- set parsed_matchers = [] %} | ||||
{%- for matcher in matchers %} | {%- for matcher in matchers %} | ||||
{%- do salt["log.debug"]( | {%- do salt["log.debug"]( | ||||
"type": _defaults["type"], | "type": _defaults["type"], | ||||
"option": None, | "option": None, | ||||
"query_method": query_map[_defaults["query_type"]], | "query_method": query_map[_defaults["query_type"]], | ||||
"query_delimiter": _defaults["query_delimiter"], | |||||
"query": matcher | "query": matcher | ||||
} | } | ||||
) %} | ) %} | ||||
{ | { | ||||
"type": metadatas[0], | "type": metadatas[0], | ||||
"option": "C", | "option": "C", | ||||
"query_delimiter": ":" | |||||
} | } | ||||
) %} | ) %} | ||||
{%- do salt["log.debug"]( | {%- do salt["log.debug"]( | ||||
{ | { | ||||
"type": metadatas[0], | "type": metadatas[0], | ||||
"option": metadatas[1], | "option": metadatas[1], | ||||
"query_delimiter": ":" | |||||
} | } | ||||
) %} | ) %} | ||||
{%- do salt["log.debug"]( | {%- do salt["log.debug"]( | ||||
{ | { | ||||
"type": metadatas[0], | "type": metadatas[0], | ||||
"option": metadatas[1], | "option": metadatas[1], | ||||
"query_delimiter": metadatas[2] | default(":", boolean=True) | |||||
} | } | ||||
) %} | ) %} | ||||
{%- do salt["log.debug"]( | {%- do salt["log.debug"]( | ||||
| indent(4, True) | | indent(4, True) | ||||
) %} | ) %} | ||||
{%- elif metadatas | length == 4 %} | {%- elif metadatas | length == 4 %} | ||||
{#- The delimiter is `:` #} | |||||
{%- do parsed.update( | {%- do parsed.update( | ||||
{ | { | ||||
"type": metadatas[0], | "type": metadatas[0], | ||||
"option": metadatas[1], | "option": metadatas[1], | ||||
"query_delimiter": ":" | |||||
} | } | ||||
) %} | ) %} | ||||
{%- do salt["log.debug"]( | {%- do salt["log.debug"]( | ||||
{#- Add `merge:` option to `salt["config.get"]` if configured #} | {#- Add `merge:` option to `salt["config.get"]` if configured #} | ||||
{%- if cli in ["minion", "local"] and parsed.query_method == "config.get" and config_get_strategy %} | {%- if cli in ["minion", "local"] and parsed.query_method == "config.get" and config_get_strategy %} | ||||
{%- set merge_opt = {"merge": config_get_strategy} %} | |||||
{%- set merge_msg = ( | |||||
", merge: strategy='" | |||||
{%- set query_opts = { | |||||
"merge": config_get_strategy, | |||||
"delimiter": parsed.query_delimiter, | |||||
} %} | |||||
{%- set query_opts_msg = ( | |||||
", delimiter='" | |||||
~ parsed.query_delimiter | |||||
~ "', merge: strategy='" | |||||
~ config_get_strategy | ~ config_get_strategy | ||||
~ "'" | ~ "'" | ||||
) %} | ) %} | ||||
{%- if cli not in ["minion", "local"] %} | {%- if cli not in ["minion", "local"] %} | ||||
{%- do salt["log.error"]( | {%- do salt["log.error"]( | ||||
log_prefix | log_prefix | ||||
~ "the 'merge' option of 'config.get' is skipped when the salt command type is '" | |||||
~ "the 'delimiter' and 'merge' options of 'config.get' are skipped when the salt command type is '" | |||||
~ cli | ~ cli | ||||
~ "'" | ~ "'" | ||||
) %} | ) %} | ||||
{%- endif %} | {%- endif %} | ||||
{%- set merge_opt = {} %} | |||||
{%- set merge_msg = "" %} | |||||
{%- set query_opts = {} %} | |||||
{%- set query_opts_msg = "" %} | |||||
{%- endif %} | {%- endif %} | ||||
{%- do salt["log.debug"]( | {%- do salt["log.debug"]( | ||||
~ "' with '" | ~ "' with '" | ||||
~ parsed.query_method | ~ parsed.query_method | ||||
~ "'" | ~ "'" | ||||
~ merge_msg | |||||
~ query_opts_msg | |||||
) %} | ) %} | ||||
{%- set values = salt[parsed.query_method]( | {%- set values = salt[parsed.query_method]( | ||||
parsed.query, | parsed.query, | ||||
default=[], | default=[], | ||||
**merge_opt | |||||
**query_opts | |||||
) %} | ) %} | ||||
{%- do parsed.update( | {%- do parsed.update( | ||||
{ | { |
{#- - type: `F` to load file, `C`, `G`, `I` for lookup #} | {#- - type: `F` to load file, `C`, `G`, `I` for lookup #} | ||||
{#- - option: specific to the type #} | {#- - option: specific to the type #} | ||||
{#- - query: which key is requested #} | {#- - query: which key is requested #} | ||||
{#- - query_delimiter: the separator between query component #} | |||||
{#- - query_method: the salt method doing the query `config.get`, `pillar.get` and `grains.get` #} | {#- - query_method: the salt method doing the query `config.get`, `pillar.get` and `grains.get` #} | ||||
{#- - value: the result of the `salt[<query_method>](<query>)` #} | {#- - value: the result of the `salt[<query_method>](<query>)` #} | ||||
{%- set map_matchers = parse_matchers( | {%- set map_matchers = parse_matchers( |