Ansible: check `When` before check for undefined variables

Viewed 144

ansible 2.9.6

I have a list of hashes within with_items. And I put when as one of the items params. So, the some items will be executed, some not. I don't want to declare or set defaults for the variables in skipped items. But i have "VAR_2 is undefined" error even for items that will not be executed.

Example:

---
- hosts: localhost
  gather_facts: no
  tasks:
    - name: localtest
      template:
        src: test.txt.j2
        dest: "{{ item.BASE_NAME }}-test.txt"
      when: "item.when"
      with_items:
        - { BASE_NAME: "{{VAR_1}}", when: "{{ variable_true }}" }
        - { BASE_NAME: "{{VAR_2}}", when: "{{ variable_false }}" }
        - { BASE_NAME: "{{VAR_3}}", when: "{{ variable_true }}" }

I don't want to use defaults, because I'm using this Play for the different hosts with different variables sets. And I need errors, when necessary variable (with when true condition) is undeclared.

1 Answers

What you are describing here is the reason of the omit special variable, that you can use in Ansible with the default filter.

By default Ansible requires values for all variables in a templated expression. However, you can make specific variables optional. For example, you might want to use a system default for some items and control the value for others. To make a variable optional, set the default value to the special variable omit

Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#making-variables-optional

So you could do with a playbook like this:

- hosts: localhost
  gather_facts: no

  tasks:
    - template:
        src: test.txt.j2
        dest: "{{ item.BASE_NAME }}-test.txt"
      when: "item.when"
      with_items:
        - BASE_NAME: "{{ VAR_1 | default(omit) }}"
          when: "{{ variable_true }}"
        - BASE_NAME: "{{ VAR_2 | default(omit) }}"
          when: "{{ variable_false }}"
        - BASE_NAME: "{{ VAR_3 | default(omit) }}"
          when: "{{ variable_true }}"
      vars: 
        variable_true: true
        variable_false: false

Another thing you could do, but, that, I, personally find less appealing, is to define only the name of your variables in your loop, then refer to the content of this variable using the vars lookup.

So ending whit this playbook:

- hosts: localhost
  gather_facts: no

  tasks:
    - template:
        src: test.txt.j2
        dest: "{{ lookup('vars', item.BASE_NAME) }}-test.txt"
      when: "item.when"
      with_items:
        - BASE_NAME: "VAR_1"
          when: "{{ variable_true }}"
        - BASE_NAME: "VAR_2"
          when: "{{ variable_false }}"
        - BASE_NAME: "VAR_3"
          when: "{{ variable_true }}"
      vars: 
        variable_true: true
        variable_false: false
Related