can anyone explain the following Jinja behaviour in Ansible?
The following code works: The task is skipped because the job_function is not in the exclusion_functions array
- name: Lowercase test
hosts: localhost
gather_facts: false
vars:
job_function: 'VRIJwillig'
exclusion_functions:
- vrijwilliger
- maatje
tasks:
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in exclusion_functions
The following code works as well, the second task is skipped.
- name: Lowercase test
hosts: localhost
gather_facts: false
vars:
job_function: 'VRIJwillig'
exclusion_functions:
- Vrijwilliger
- Maatje
tasks:
- name: Initialiseer variabelen
set_fact:
exclusions: "{{ exclusion_functions | lower }}"
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in exclusions
But this doesn’t work, the task isn’t skipped:
---
- name: Lowercase test
hosts: localhost
gather_facts: false
vars:
job_function: 'VRIJwillig'
exclusion_functions:
- Vrijwilliger
- Maatje
tasks:
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in (exclusion_functions | lower)
Why is the task not skipped in the last code snippet? job_function | lower
is vrijwillig
, and exclusion_functions | lower
is ['vrijwilliger','maatje']
, and the first one isn’t in the second one.
The value of the variable exclusion_functions is a list
- debug:
msg: |
{{ exclusion_functions }}
{{ exclusion_functions | type_debug }}
gives
msg: |-
['Vrijwilliger', 'Maatje']
list
The filter lower converts the argument to a string
- debug:
msg: |
{{ exclusion_functions | lower }}
{{ exclusion_functions | lower | type_debug }}
The output looks like a list but it isn’t. It’s a string
msg: |-
['vrijwilliger', 'maatje']
str
This explains why the below task isn’t skipped
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in (exclusion_functions | lower)
The value VRIJwillig
of the variable job_function is converted to lowercase vrijwillig
which is in the string ['vrijwilliger', 'maatje']
The solution is to map the filter lower to each list’s item
- debug:
msg: |
{{ exclusion_functions | map('lower') }}
{{ exclusion_functions | map('lower') | type_debug }}
shows the result is a list with items converted to lowercase
msg: |-
['vrijwilliger', 'maatje']
list
Then, as expected, the below task is skipped
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in (exclusion_functions | map('lower'))
Example of a complete playbook for testing
- name: Lowercase test
hosts: localhost
vars:
job_function: VRIJwillig
exclusion_functions:
- Vrijwilliger
- Maatje
tasks:
- debug:
msg: |
{{ exclusion_functions }}
{{ exclusion_functions | type_debug }}
- debug:
msg: |
{{ exclusion_functions | lower }}
{{ exclusion_functions | lower | type_debug }}
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in (exclusion_functions | lower)
- debug:
msg: |
{{ exclusion_functions | map('lower') }}
{{ exclusion_functions | map('lower') | type_debug }}
- name: Test for function in exclusions
debug:
msg: In exclusions
when: (job_function | lower) in (exclusion_functions | map('lower'))
1
Whereby I can’t answer
Q: “Can anyone explain the following Jinja behaviour in Ansible?“
in order to search for a (sub-)string in a list I like to recommend to use the approach from the following minimal example playbook
---
- name: Lowercase test
hosts: localhost
become: false
gather_facts: false
vars:
job_function: 'VRIJwillig'
exclusion_functions:
- Vrijwilliger
- Maatje
tasks:
- name: Initialiseer variabelen
debug:
var: exclusion_functions | lower
- name: Test for function in exclusions
debug:
msg: In exclusions
when: exclusions is search(job_function | lower)
# Initialiseer variabelen
vars:
exclusions: "{{ exclusion_functions | lower }}"
resulting into an output of
TASK [Initialiseer variabelen] *******************************************************
ok: [localhost] =>
exclusion_functions | lower:
- vrijwilliger
- maatje
TASK [Test for function in exclusions] *******************************************************
ok: [localhost] =>
msg: In exclusions
because the search
test – Does string match a regular expression has already a Parameter: ignorecase
. See in example the result of
- name: Test for function in exclusions
debug:
msg: In exclusions
when: exclusions is search(job_function, ignorecase=True)
# Initialiseer variabelen
vars:
exclusions: "{{ exclusion_functions }}"
If looking for an exact match of list elements use contains
test – does the list contain this element
Checks the supplied element against the input list to see if it exists within it.
- name: Test for function in exclusions
debug:
msg: In exclusions
when: exclusions is contains(job_function | lower)
# Initialiseer variabelen
vars:
exclusions: "{{ exclusion_functions | lower }}"
resulting into a SKIPPED task.
PLAY RECAP *****************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=1
Or use the already given answer.
2