Document that dict key syntax should be preferred

While `{{ salt.foo.bar() }}` often works, it can introduce some edge
cases which are avoided by `{{ salt['foo.bar']() }}`.
This commit is contained in:
jeanluc 2024-05-31 10:44:15 +02:00 committed by Daniel Wozniak
parent 096dca61ba
commit c2e0b57ba9
13 changed files with 57 additions and 49 deletions

View file

@ -563,7 +563,7 @@ The ``onfail`` requisite is applied in the same way as ``require`` and ``watch``
notify-build_failure:
hipchat.send_message:
- room_id: 123456
- message: "Building website fail on {{ salt.grains.get('id') }}"
- message: "Building website fail on {{ salt['grains.get']('id') }}"
The default behavior of the ``onfail`` when multiple requisites are listed is
@ -723,7 +723,7 @@ be installed. Thus allowing for a requisite to be defined "after the fact".
.. code-block:: sls
{% for cfile in salt.pillar.get('nginx:config_files') %}
{% for cfile in salt['pillar.get']('nginx:config_files') %}
/etc/nginx/conf.d/{{ cfile }}:
file.managed:
- source: salt://nginx/configs/{{ cfile }}

View file

@ -21,6 +21,13 @@ General rules
4. Store sensitive data in pillar.
5. Don't use grains for matching in your pillar top file for any sensitive
pillars.
6. When accessing modules from within a template, use the mapping
key syntax instead of the attribute one to avoid edge cases. Example:
.. code-block:: jinja
{%- set do_this = salt['pillar.get']('foo:bar') %}
{%- set avoid_this = salt.pillar.get('foo:bar') %}
.. include:: ../_incl/grains_passwords.rst

View file

@ -262,7 +262,7 @@ file. This section contains several suggestions and examples.
deploy_myapp:
git.latest:
- name: git@github.com/myco/myapp.git
- version: {{ salt.pillar.get('myapp:version', 'master') }}
- version: {{ salt['pillar.get']('myapp:version', 'master') }}
Use a descriptive State ID
``````````````````````````
@ -363,11 +363,11 @@ for commenting YAML code.
# BAD EXAMPLE
# The Jinja in this YAML comment is still executed!
# {% set apache_is_installed = 'apache' in salt.pkg.list_pkgs() %}
# {% set apache_is_installed = 'apache' in salt['pkg.list_pkgs']() %}
# GOOD EXAMPLE
# The Jinja in this Jinja comment will not be executed.
{# {% set apache_is_installed = 'apache' in salt.pkg.list_pkgs() %} #}
{# {% set apache_is_installed = 'apache' in salt['pkg.list_pkgs']() %} #}
Easy on the Jinja!
------------------
@ -427,7 +427,7 @@ Less common values are often found by running commands. For example:
.. code-block:: jinja
{% set is_selinux_enabled = salt.cmd.run('sestatus') == '1' %}
{% set is_selinux_enabled = salt['cmd.run']('sestatus') == '1' %}
This is usually best done with a variable assignment in order to separate the
data from the state that will make use of the data.
@ -442,7 +442,7 @@ from the Salt Master. For example:
.. code-block:: jinja
{% set some_data = salt.pillar.get('some_data', {'sane default': True}) %}
{% set some_data = salt['pillar.get']('some_data', {'sane default': True}) %}
{# or #}
@ -478,7 +478,7 @@ Below is a simple example of a readable loop:
.. code-block:: jinja
{% for user in salt.pillar.get('list_of_users', []) %}
{% for user in salt['pillar.get']('list_of_users', []) %}
{# Ensure unique state IDs when looping. #}
{{ user.name }}-{{ loop.index }}:
@ -690,7 +690,7 @@ Macros are useful for creating reusable, parameterized states. For example:
- groups: {{ groups | json() }}
{% endmacro %}
{% for user_info in salt.pillar.get('my_users', []) %}
{% for user_info in salt['pillar.get']('my_users', []) %}
{{ user_state('user_number_' ~ loop.index, **user_info) }}
{% endfor %}
@ -708,7 +708,7 @@ example, the following macro could be used to write a php.ini config file:
- source: salt://php.ini.tmpl
- template: jinja
- context:
php_ini_settings: {{ salt.pillar.get('php_ini', {}) | json() }}
php_ini_settings: {{ salt['pillar.get']('php_ini', {}) | json() }}
``/srv/pillar/php.sls``:
@ -920,7 +920,7 @@ Pillar can also be used.
.. code-block:: jinja
{% set lookup_table = {...} %}
{% do lookup_table.update(salt.pillar.get('my:custom:data')) %}
{% do lookup_table.update(salt['pillar.get']('my:custom:data')) %}
When to use lookup tables
`````````````````````````
@ -994,7 +994,7 @@ XML.)
.. code-block:: jinja
{% import_yaml 'tomcat/defaults.yaml' as server_xml_defaults %}
{% set server_xml_final_values = salt.pillar.get(
{% set server_xml_final_values = salt['pillar.get'](
'appX:server_xml_overrides',
default=server_xml_defaults,
merge=True)
@ -1033,11 +1033,11 @@ example:
{# Extract the relevant subset for the app configured on the current
machine (configured via a grain in this example). #}
{% app = app_defaults.get(salt.grains.get('role')) %}
{% app = app_defaults.get(salt['grains.get']('role')) %}
{# Allow values from Pillar to (optionally) update values from the lookup
table. #}
{% do app_defaults.update(salt.pillar.get('myapp', {})) %}
{% do app_defaults.update(salt['pillar.get']('myapp', {})) %}
deploy_application:
git.latest:

View file

@ -161,7 +161,7 @@ starts at the root of the state tree or pillar.
Errors
======
Saltstack allows raising custom errors using the ``raise`` jinja function.
Saltstack allows raising custom errors using the ``raise`` Jinja function.
.. code-block:: jinja
@ -2506,7 +2506,8 @@ dictionary of :term:`execution function <Execution Function>`.
.. code-block:: jinja
# The following two function calls are equivalent.
# The following two function calls are mostly equivalent,
# but the first style should be preferred to avoid edge cases.
{{ salt['cmd.run']('whoami') }}
{{ salt.cmd.run('whoami') }}
@ -2536,7 +2537,7 @@ For example, making the call:
.. code-block:: jinja
{%- do salt.log.error('testing jinja logging') -%}
{%- do salt['log.error']('testing jinja logging') -%}
Will insert the following message in the minion logs:
@ -2552,14 +2553,14 @@ Profiling
.. versionadded:: 3002
When working with a very large codebase, it becomes increasingly imperative to
trace inefficiencies with state and pillar render times. The `profile` jinja
trace inefficiencies with state and pillar render times. The `profile` Jinja
block enables the user to get finely detailed information on the most expensive
areas in the codebase.
Profiling blocks
----------------
Any block of jinja code can be wrapped in a ``profile`` block. The syntax for
Any block of Jinja code can be wrapped in a ``profile`` block. The syntax for
a profile block is ``{% profile as '<name>' %}<jinja code>{% endprofile %}``,
where ``<name>`` can be any string. The ``<name>`` token will appear in the
log at the ``profile`` level along with the render time of the block.
@ -2626,15 +2627,15 @@ For ``import_*`` blocks, the ``profile`` log statement has the following form:
[...]
Python Methods
====================
==============
A powerful feature of jinja that is only hinted at in the official jinja
documentation is that you can use the native python methods of the
variable type. Here is the python documentation for `string methods`_.
A powerful feature of Jinja that is only hinted at in the official Jinja
documentation is that you can use the native Python methods of the
variable type. Here is the Python documentation for `string methods`_.
.. code-block:: jinja
{% set hostname,domain = grains.id.partition('.')[::2] %}{{ hostname }}
{% set hostname, domain = grains.id.partition('.')[::2] %}{{ hostname }}
.. code-block:: jinja
@ -2681,7 +2682,7 @@ module, say ``my_filters`` and use as:
.. code-block:: jinja
{{ salt.my_filters.my_jinja_filter(my_variable) }}
{{ salt['my_filters.my_jinja_filter'](my_variable) }}
The greatest benefit is that you are able to access thousands of existing functions, e.g.:
@ -2689,16 +2690,16 @@ The greatest benefit is that you are able to access thousands of existing functi
.. code-block:: jinja
{{ salt.dnsutil.AAAA('www.google.com') }}
{{ salt['dnsutil.AAAA']('www.google.com') }}
- retrieve a specific field value from a :mod:`Redis <salt.modules.modredis>` hash:
.. code-block:: jinja
{{ salt.redis.hget('foo_hash', 'bar_field') }}
{{ salt['redis.hget']('foo_hash', 'bar_field') }}
- get the routes to ``0.0.0.0/0`` using the :mod:`NAPALM route <salt.modules.napalm_route>`:
.. code-block:: jinja
{{ salt.route.show('0.0.0.0/0') }}
{{ salt['route.show']('0.0.0.0/0') }}

View file

@ -394,8 +394,8 @@ For example:
.. code-block:: jinja
# /srv/salt/orchestrate/do_complex_thing.sls
{% set tag = salt.pillar.get('event_tag') %}
{% set data = salt.pillar.get('event_data') %}
{% set tag = salt['pillar.get']('event_tag') %}
{% set data = salt['pillar.get']('event_data') %}
# Pass data from the event to a custom runner function.
# The function expects a 'foo' argument.

View file

@ -52,7 +52,7 @@ Unfortunately, it can lead to code that looks like the following.
{% do storage.update({'server_ip': servers_list[server_index]}) %}
{% endif %}
{% for network, _ in salt.pillar.get('inventory:networks', {}) | dictsort %}
{% for network, _ in salt['pillar.get']('inventory:networks', {}) | dictsort %}
{% do storage.ipsets.hash_net.foo_networks.append(network) %}
{% endfor %}
@ -88,7 +88,7 @@ Let's move that to an execution module.
{% do storage.update({'server_ip': salt['storage.ip']()}) %}
{% for network, _ in salt.pillar.get('inventory:networks', {}) | dictsort %}
{% for network, _ in salt['pillar.get']('inventory:networks', {}) | dictsort %}
{% do storage.ipsets.hash_net.af_networks.append(network) %}
{% endfor %}

View file

@ -121,7 +121,7 @@ def renderer(path=None, string=None, default_renderer="jinja|yaml", **kwargs):
.. code-block:: jinja
#!jinja|yaml
{% set apache = salt.grains.filter_by({
{% set apache = salt['grains.filter_by']({
...normal jinja map file here...
}, merge=salt.pillar.get('apache:lookup')) %}
{{ apache | yaml() }}
@ -141,7 +141,7 @@ def renderer(path=None, string=None, default_renderer="jinja|yaml", **kwargs):
.. code-block:: jinja
{% set apache = salt.slsutil.renderer('map.sls') %}
{% set apache = salt['slsutil.renderer']('map.sls') %}
CLI Example:
@ -211,7 +211,7 @@ def serialize(serializer, obj, **mod_kwargs):
.. code-block:: jinja
{% set json_string = salt.slsutil.serialize('json',
{% set json_string = salt['slsutil.serialize']('json',
{'foo': 'Foo!'}) %}
"""
kwargs = salt.utils.args.clean_kwargs(**mod_kwargs)
@ -235,7 +235,7 @@ def deserialize(serializer, stream_or_string, **mod_kwargs):
.. code-block:: jinja
{% set python_object = salt.slsutil.deserialize('json',
{% set python_object = salt['slsutil.deserialize']('json',
'{"foo": "Foo!"}') %}
"""
kwargs = salt.utils.args.clean_kwargs(**mod_kwargs)

View file

@ -135,7 +135,7 @@ def base64_encodefile(fname):
path:
to:
data: |
{{ salt.hashutil.base64_encodefile('/path/to/binary_file') | indent(6) }}
{{ salt['hashutil.base64_encodefile']('/path/to/binary_file') | indent(6) }}
The :py:func:`file.decode <salt.states.file.decode>` state function can be
used to decode this data and write it to disk.

View file

@ -405,7 +405,7 @@ def search_by(lookup, tgt_type="compound", minion_id=None):
.. code-block:: jinja
{% set roles = salt.match.search_by({
{% set roles = salt['match.search_by']({
'web': ['G@os_family:Debian not nodeX'],
'db': ['L@node2,node3 and G@datacenter:west'],
'caching': ['node3', 'node4'],

View file

@ -301,7 +301,7 @@ def get(tgt, fun, tgt_type="glob", exclude_minion=False):
.. code-block:: jinja
{% set minion_ips = salt.saltutil.runner('mine.get',
{% set minion_ips = salt['saltutil.runner']('mine.get',
tgt='*',
fun='network.ip_addrs',
tgt_type='glob') %}

View file

@ -321,8 +321,8 @@ def version_compare(ver1, oper, ver2, ignore_epoch=False):
.. code-block:: jinja
{%- set postfix_version = salt.pkg.version('postfix') %}
{%- if postfix_version and salt.pkg_resource.version_compare(postfix_version, '>=', '3.3', ignore_epoch=True) %}
{%- set postfix_version = salt['pkg.version']('postfix') %}
{%- if postfix_version and salt['pkg_resource.version_compare'](postfix_version, '>=', '3.3', ignore_epoch=True) %}
{#- do stuff #}
{%- endif %}

View file

@ -126,18 +126,18 @@ def renderer(path=None, string=None, default_renderer="jinja|yaml", **kwargs):
.. code-block:: jinja
#!jinja|yaml
{% set apache = salt.grains.filter_by({
{% set apache = salt['grains.filter_by']({
...normal jinja map file here...
}, merge=salt.pillar.get('apache:lookup')) %}
}, merge=salt['pillar.get']('apache:lookup')) %}
{{ apache | yaml() }}
.. code-block:: python
#!py
def run():
apache = __salt__.grains.filter_by({
apache = __salt__['grains.filter_by']({
...normal map here but as a python dict...
}, merge=__salt__.pillar.get('apache:lookup'))
}, merge=__salt__['pillar.get']('apache:lookup'))
return apache
Regardless of which of the above map files is used, it can be accessed from
@ -146,7 +146,7 @@ def renderer(path=None, string=None, default_renderer="jinja|yaml", **kwargs):
.. code-block:: jinja
{% set apache = salt.slsutil.renderer('map.sls') %}
{% set apache = salt['slsutil.renderer']('map.sls') %}
CLI Example:
@ -219,7 +219,7 @@ def serialize(serializer, obj, **mod_kwargs):
.. code-block:: jinja
{% set json_string = salt.slsutil.serialize('json',
{% set json_string = salt['slsutil.serialize']('json',
{'foo': 'Foo!'}) %}
"""
kwargs = salt.utils.args.clean_kwargs(**mod_kwargs)
@ -243,7 +243,7 @@ def deserialize(serializer, stream_or_string, **mod_kwargs):
.. code-block:: jinja
{% set python_object = salt.slsutil.deserialize('json',
{% set python_object = salt['slsutil.deserialize']('json',
'{"foo": "Foo!"}') %}
"""
kwargs = salt.utils.args.clean_kwargs(**mod_kwargs)

View file

@ -8814,7 +8814,7 @@ def decode(
- name: /tmp/new_file
- encoding_type: base64
- encoded_data: |
{{ salt.pillar.get('path:to:data') | indent(8) }}
{{ salt['pillar.get']('path:to:data') | indent(8) }}
"""
ret = {"name": name, "changes": {}, "result": False, "comment": ""}