In Ansible, is there a difference between a variable that is 'undefined' and one that is 'not defined'?
I've seen both terms used interchangeably, but I want to make sure that there isn't some subtle difference that I'm missing. From what I understand, both terms refer to a variable that has not been defined or has no value assigned to it.
Is this correct, or are there some cases where they should be used differently? Can someone provide a clear explanation or point to relevant documentation?
I have tried running the following play-book because I thought the difference will be in the declaration of the variable but it didn't work as expected.
---
- name: Example play-book
hosts: localhost
gather_facts: no
vars:
# This variable is defined with a value assigned to it
defined_var: "Hello, world!"
# This variable is defined but has no value assigned to it
undefined_var:
# This variable is not defined at all
# not_defined_var:
tasks:
- name: Task 1
debug:
var: defined_var
- name: Task 2
debug:
msg: "VARIABLE IS UNDEFINED"
when: undefined_var is undefined
- name: Task 3
debug:
var: not_defined_var
when: not_defined_var is undefined
Output:
PLAY [Example playbook] *******************************************
TASK [Task 1] *****************************************************
ok: [localhost] => {
"defined_var": "Hello, world!"
}
TASK [Task 2] *****************************************************
skipping: [localhost]
TASK [Task 3] *****************************************************
ok: [localhost] => {
"not_defined_var": "VARIABLE IS NOT DEFINED!"
}
Ansible templating system is Jinja, and in the Jinja documentation we can read:
jinja-tests.undefined(value: Any) → bool
Likedefined()
but the other way round.
Source: https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-tests.undefined
So, yes, one is simply the not
variant of the other.
{{ var is not defined == var is undefined }} {# => will always be true #}
{{ var is not undefined == var is defined }} {# => will always be true #}
The difference can be done when using the filter default()
, that is referenced in the defined()
test documentation to handled undefined variables:
{{ '' | default('this is a placeholder') }}
will render a blank string, while
{{ '' | default('this is a placeholder', true) }}
will render the placeholder, this is a placeholder
, as the second parameter will help you to also control variables that evaluate to false (empty values — ''
string, ()
tuple, {}
dictionary, []
list —, the boolean false
, None
, 0
).
If you want to go further and peak at Jinja's code you can see that the defined
test is defined as such:
def test_defined(value: t.Any) -> bool:
return not isinstance(value, Undefined)
Source: https://github.com/pallets/jinja/blob/main/src/jinja2/tests.py
And the undefined
one as such:
def test_undefined(value: t.Any) -> bool:
return isinstance(value, Undefined)
Source: https://github.com/pallets/jinja/blob/main/src/jinja2/tests.py