Add (more) explicit references to Jinja2 docs in conditionals doc (#61814)
Co-authored-by: Sandra McCann <samccann@redhat.com>
This commit is contained in:
parent
6cc326dcf1
commit
b625b430f1
1 changed files with 30 additions and 24 deletions
|
@ -10,7 +10,9 @@ Often the result of a play may depend on the value of a variable, fact (somethin
|
||||||
In some cases, the values of variables may depend on other variables.
|
In some cases, the values of variables may depend on other variables.
|
||||||
Additional groups can be created to manage hosts based on whether the hosts match other criteria. This topic covers how conditionals are used in playbooks.
|
Additional groups can be created to manage hosts based on whether the hosts match other criteria. This topic covers how conditionals are used in playbooks.
|
||||||
|
|
||||||
.. note:: There are many options to control execution flow in Ansible. More examples of supported conditionals can be located here: http://jinja.pocoo.org/docs/dev/templates/#comparisons.
|
.. note::
|
||||||
|
|
||||||
|
There are many options to control execution flow in Ansible. More examples of supported conditionals can be located here: https://jinja.palletsprojects.com/en/master/templates/#comparisons.
|
||||||
|
|
||||||
|
|
||||||
.. _the_when_statement:
|
.. _the_when_statement:
|
||||||
|
@ -22,7 +24,10 @@ Sometimes you will want to skip a particular step on a particular host.
|
||||||
This could be something as simple as not installing a certain package if the operating system is a particular version,
|
This could be something as simple as not installing a certain package if the operating system is a particular version,
|
||||||
or it could be something like performing some cleanup steps if a filesystem is getting full.
|
or it could be something like performing some cleanup steps if a filesystem is getting full.
|
||||||
|
|
||||||
This is easy to do in Ansible with the `when` clause, which contains a raw Jinja2 expression without double curly braces (see :ref:`group_by_module`).
|
This is easy to do in Ansible with the ``when`` clause, which contains a raw `Jinja2 expression <https://jinja.palletsprojects.com/en/master/templates/#expressions>`_ without double curly braces (see :ref:`group_by_module`).
|
||||||
|
|
||||||
|
.. note:: Jinja2 expressions are built up from comparisons, filters, tests, and logical combinations thereof. The below examples will give you an impression how to use them. However, for a more complete overview over all operators to use, please refer to the official `Jinja2 documentation <https://jinja.palletsprojects.com/en/master/templates/#expressions>`_ .
|
||||||
|
|
||||||
It's actually pretty simple::
|
It's actually pretty simple::
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
@ -31,7 +36,7 @@ It's actually pretty simple::
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
when: ansible_facts['os_family'] == "Debian"
|
||||||
# note that all variables can be used directly in conditionals without double curly braces
|
# note that all variables can be used directly in conditionals without double curly braces
|
||||||
|
|
||||||
You can also use parentheses to group conditions::
|
You can also use `parentheses to group and logical operators <https://jinja.palletsprojects.com/en/master/templates/#logic>`_ to combine conditions::
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: "shut down CentOS 6 and Debian 7 systems"
|
- name: "shut down CentOS 6 and Debian 7 systems"
|
||||||
|
@ -39,7 +44,7 @@ You can also use parentheses to group conditions::
|
||||||
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
|
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
|
||||||
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
|
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
|
||||||
|
|
||||||
Multiple conditions that all need to be true (a logical 'and') can also be specified as a list::
|
Multiple conditions that all need to be true (that is, a logical ``and``) can also be specified as a list::
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: "shut down CentOS 6 systems"
|
- name: "shut down CentOS 6 systems"
|
||||||
|
@ -48,9 +53,8 @@ Multiple conditions that all need to be true (a logical 'and') can also be speci
|
||||||
- ansible_facts['distribution'] == "CentOS"
|
- ansible_facts['distribution'] == "CentOS"
|
||||||
- ansible_facts['distribution_major_version'] == "6"
|
- ansible_facts['distribution_major_version'] == "6"
|
||||||
|
|
||||||
A number of Jinja2 "tests" and "filters" can also be used in when statements, some of which are unique
|
A number of Jinja2 `"tests" and "filters" <https://jinja.palletsprojects.com/en/master/templates/#other-operators>`_ can also be used in when statements, some of which are unique and provided by Ansible.
|
||||||
and provided by Ansible. Suppose we want to ignore the error of one statement and then
|
Suppose we want to ignore the error of one statement and then decide to do something conditionally based on success or failure::
|
||||||
decide to do something conditionally based on success or failure::
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- command: /bin/false
|
- command: /bin/false
|
||||||
|
@ -60,7 +64,7 @@ decide to do something conditionally based on success or failure::
|
||||||
- command: /bin/something
|
- command: /bin/something
|
||||||
when: result is failed
|
when: result is failed
|
||||||
|
|
||||||
# In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.
|
# Both `succeeded` and `success` both work. The former, however, is newer and uses the correct tense, while the latter is mainly used in older versions of Ansible.
|
||||||
- command: /bin/something_else
|
- command: /bin/something_else
|
||||||
when: result is succeeded
|
when: result is succeeded
|
||||||
|
|
||||||
|
@ -68,7 +72,7 @@ decide to do something conditionally based on success or failure::
|
||||||
when: result is skipped
|
when: result is skipped
|
||||||
|
|
||||||
|
|
||||||
.. note:: both `success` and `succeeded` work (`fail`/`failed`, etc).
|
.. note:: both `success` and `succeeded` work (`similarly for fail`/`failed`, etc).
|
||||||
.. warning:: You might expect a variable of a skipped task to be undefined and use `defined` or `default` to check that. **This is incorrect**! Even when a task is failed or skipped the variable is still registered with a failed or skipped status. See :ref:`registered_variables`.
|
.. warning:: You might expect a variable of a skipped task to be undefined and use `defined` or `default` to check that. **This is incorrect**! Even when a task is failed or skipped the variable is still registered with a failed or skipped status. See :ref:`registered_variables`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,15 +81,17 @@ To see what facts are available on a particular system, you can do the following
|
||||||
- debug: var=ansible_facts
|
- debug: var=ansible_facts
|
||||||
|
|
||||||
|
|
||||||
Tip: Sometimes you'll get back a variable that's a string and you'll want to do a math operation comparison on it. You can do this like so::
|
Tip: Sometimes you'll get back a variable that's a string and you'll want to do a math operation comparison on it.
|
||||||
|
You can do this like so::
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- shell: echo "only on Red Hat 6, derivatives, and later"
|
- shell: echo "only on Red Hat 6, derivatives, and later"
|
||||||
when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6
|
when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6
|
||||||
|
|
||||||
.. note:: the above example requires the lsb_release package on the target host in order to return the 'lsb major_release' fact.
|
.. note:: the above example requires the lsb_release package on the target host in order to return the `lsb major_release` fact.
|
||||||
|
|
||||||
Variables defined in the playbooks or inventory can also be used, just make sure to apply the `|bool` filter to non boolean variables (ex: string variables with content like 'yes', 'on', '1', 'true'). An example may be the execution of a task based on a variable's boolean value::
|
Variables defined in the playbooks or inventory can also be used, just make sure to apply the ``|bool`` filter to non-boolean variables (e.g., `string` variables with content like ``yes``, ``on``, ``1``, ``true``).
|
||||||
|
An example may be the execution of a task based on a variable's boolean value::
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
epic: true
|
epic: true
|
||||||
|
@ -103,7 +109,8 @@ or::
|
||||||
- shell: echo "This certainly isn't epic!"
|
- shell: echo "This certainly isn't epic!"
|
||||||
when: not epic
|
when: not epic
|
||||||
|
|
||||||
If a required variable has not been set, you can skip or fail using Jinja2's `defined` test. For example::
|
If a required variable has not been set, you can skip or fail using Jinja2's ``defined`` test.
|
||||||
|
For example::
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
|
- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
|
||||||
|
@ -113,20 +120,20 @@ If a required variable has not been set, you can skip or fail using Jinja2's `de
|
||||||
when: bar is undefined
|
when: bar is undefined
|
||||||
|
|
||||||
This is especially useful in combination with the conditional import of vars files (see below).
|
This is especially useful in combination with the conditional import of vars files (see below).
|
||||||
As the examples show, you don't need to use `{{ }}` to use variables inside conditionals, as these are already implied.
|
As the examples show, you don't need to use ``{{ }}`` to use variables inside conditionals, as these are already implied.
|
||||||
|
|
||||||
.. _loops_and_conditionals:
|
.. _loops_and_conditionals:
|
||||||
|
|
||||||
Loops and Conditionals
|
Loops and Conditionals
|
||||||
``````````````````````
|
``````````````````````
|
||||||
Combining `when` with loops (see :ref:`playbooks_loops`), be aware that the `when` statement is processed separately for each item. This is by design::
|
Combining ``when`` with loops (see :ref:`playbooks_loops`), be aware that the ``when`` statement is processed separately for each item. This is by design::
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- command: echo {{ item }}
|
- command: echo {{ item }}
|
||||||
loop: [ 0, 2, 4, 6, 8, 10 ]
|
loop: [ 0, 2, 4, 6, 8, 10 ]
|
||||||
when: item > 5
|
when: item > 5
|
||||||
|
|
||||||
If you need to skip the whole task depending on the loop variable being defined, used the `|default` filter to provide an empty iterator::
|
If you need to skip the whole task depending on the loop variable being defined, used the ``|default`` filter to provide an empty iterator::
|
||||||
|
|
||||||
- command: echo {{ item }}
|
- command: echo {{ item }}
|
||||||
loop: "{{ mylist|default([]) }}"
|
loop: "{{ mylist|default([]) }}"
|
||||||
|
@ -165,7 +172,7 @@ to a task include statement as below. All the tasks get evaluated, but the cond
|
||||||
- import_tasks: tasks/sometasks.yml
|
- import_tasks: tasks/sometasks.yml
|
||||||
when: "'reticulating splines' in output"
|
when: "'reticulating splines' in output"
|
||||||
|
|
||||||
.. note:: In versions prior to 2.0 this worked with task includes but not playbook includes. 2.0 allows it to work with both.
|
.. note:: In versions prior to 2.0 this worked with task includes but not playbook includes. 2.0 allows it to work with both.
|
||||||
|
|
||||||
Or with a role::
|
Or with a role::
|
||||||
|
|
||||||
|
@ -174,7 +181,7 @@ Or with a role::
|
||||||
- role: debian_stock_config
|
- role: debian_stock_config
|
||||||
when: ansible_facts['os_family'] == 'Debian'
|
when: ansible_facts['os_family'] == 'Debian'
|
||||||
|
|
||||||
You will note a lot of 'skipped' output by default in Ansible when using this approach on systems that don't match the criteria.
|
You will note a lot of ``skipped`` output by default in Ansible when using this approach on systems that don't match the criteria.
|
||||||
In many cases the :ref:`group_by module <group_by_module>` can be a more streamlined way to accomplish the same thing; see
|
In many cases the :ref:`group_by module <group_by_module>` can be a more streamlined way to accomplish the same thing; see
|
||||||
:ref:`os_variance`.
|
:ref:`os_variance`.
|
||||||
|
|
||||||
|
@ -282,23 +289,22 @@ instance, you could test for the existence of a particular program.
|
||||||
|
|
||||||
.. note:: Registration happens even when a task is skipped due to the conditional. This way you can query the variable for `` is skipped`` to know if task was attempted or not.
|
.. note:: Registration happens even when a task is skipped due to the conditional. This way you can query the variable for `` is skipped`` to know if task was attempted or not.
|
||||||
|
|
||||||
The 'register' keyword decides what variable to save a result in. The resulting variables can be used in templates, action lines, or *when* statements. It looks like this (in an obviously trivial example)::
|
The ``register`` keyword decides what variable to save a result in. The resulting variables can be used in templates, action lines, or *when* statements. It looks like this (in an obviously trivial example)::
|
||||||
|
|
||||||
- name: test play
|
- name: test play
|
||||||
hosts: all
|
hosts: all
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
|
||||||
- shell: cat /etc/motd
|
- shell: cat /etc/motd
|
||||||
register: motd_contents
|
register: motd_contents
|
||||||
|
|
||||||
- shell: echo "motd contains the word hi"
|
- shell: echo "motd contains the word hi"
|
||||||
when: motd_contents.stdout.find('hi') != -1
|
when: motd_contents.stdout.find('hi') != -1
|
||||||
|
|
||||||
As shown previously, the registered variable's string contents are accessible with the 'stdout' value.
|
As shown previously, the registered variable's string contents are accessible with the ``stdout`` value.
|
||||||
The registered result can be used in the loop of a task if it is converted into
|
The registered result can be used in the loop of a task if it is converted into
|
||||||
a list (or already is a list) as shown below. "stdout_lines" is already available on the object as
|
a list (or already is a list) as shown below. ``stdout_lines`` is already available on the object as
|
||||||
well though you could also call "home_dirs.stdout.split()" if you wanted, and could split by other
|
well though you could also call ``home_dirs.stdout.split()`` if you wanted, and could split by other
|
||||||
fields::
|
fields::
|
||||||
|
|
||||||
- name: registered variable usage as a loop list
|
- name: registered variable usage as a loop list
|
||||||
|
@ -318,7 +324,7 @@ fields::
|
||||||
# same as loop: "{{ home_dirs.stdout.split() }}"
|
# same as loop: "{{ home_dirs.stdout.split() }}"
|
||||||
|
|
||||||
|
|
||||||
As shown previously, the registered variable's string contents are accessible with the 'stdout' value.
|
As shown previously, the registered variable's string contents are accessible with the ``stdout`` value.
|
||||||
You may check the registered variable's string contents for emptiness::
|
You may check the registered variable's string contents for emptiness::
|
||||||
|
|
||||||
- name: check registered variable for emptiness
|
- name: check registered variable for emptiness
|
||||||
|
|
Loading…
Reference in a new issue