Search code examples
ansiblejinja2

Ansible : strange jinja2 behaviour with lowercase


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.


Solution

  • 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'))