UNDEF Keyword in Ansible

Solution 1:

You are kind of mixing two things here:

  • The possibility to have a custom hint in the error Ansible would raise when a variable is undefined, with the undef keyword.
  • The possibility to define a default when a variable is not defined.

Those two concepts are mutually exclusive, basically, because a variable having a default should never be undefined and should never cause Ansible to raise an error.
Although, depending on where you place your default, the way Ansible process variable could make the undef take precedence, and, so if you call a role containing an undef, then the error will always be raised.

As an example, a role variable file containing:

demo_variable: "{{ undef(hint='Please provide a demo variable') | default('Defeat `undef` purpose') }}"

makes nearly no sense, as the default will always take precedence.


Here is a simple role using the undef keyword.

roles/demo/vars/main.yml:

demo_variable: "{{ undef(hint='Please provide a demo variable') }}"

roles/demo/tasks/main.yml:

- debug:
    msg: "{{ demo_variable }}"

Playbook:

- hosts: localhost
  gather_facts: no

  roles:
    - role: demo      

If used as is, this will raise:

The task includes an option with an undefined variable. 
The error was: {{ undef(hint='Please provide a demo variable') }}: Please provide a demo variable
  
The error appears to be in '/usr/local/ansible/roles/demo/tasks/main.yml': line 1, column 3, 
but may be elsewhere in the file depending on the exact syntax problem.

As opposed to an undefined variable not using the undef keyword that would have raised:

The task includes an option with an undefined variable. 
The error was: 'demo_variable' is undefined
 
The error appears to be in '/usr/local/ansible/roles/demo/tasks/main.yml': line 1, column 3, 
but may be elsewhere in the file depending on the exact syntax problem.

If you want a default, on the other hand, you'll have to drop the definition of the variable, including the undef keyword out of the variable/main.yml file of the role and have a tasks/main.yml that would read:

- debug:
    msg: "{{ demo_variable | default('Defeat `undef` purpose') }}"

And this would then give the expected:

TASK [demo : debug] *********************************************************
ok: [localhost] => 
  msg: Defeat `undef` purpose

when the variable is not defined at the level of the playbook calling this role.