Is there a logical reasoning that explains why the two debug
tasks in the Ansible playbook below respectively output "NONE"
and "FALSE"
and not both "NONE"
?
- hosts: 'all'
tasks:
- debug:
msg: '{{ foo | default( None ) | ternary( "TRUE", "FALSE", "NONE" ) }}'
- debug:
msg: '{{ bar | ternary( "TRUE", "FALSE", "NONE" ) }}'
vars:
bar: '{{ foo | default( None ) }}'
I observed this with ansible@2.8.5
btw
[edit@2019-10-16]
As inferred from @VladimirBotka's answer, one could say the real "problem" is that None
isn't transitive with respect to substitution. My use of default(...)
was needlessly complicating matters and the example can be simplified to:
- hosts: 'all'
tasks:
- debug:
msg: '{{ None | ternary( "TRUE", "FALSE", "NONE" ) }}'
- debug:
msg: '{{ bar | ternary( "TRUE", "FALSE", "NONE" ) }}'
vars:
bar: '{{ None }}'
... and still produce the exact same output.
foo | default(None)
evaluates to null
{{ foo | default(None) }}
evaluates to an empty string ""
Given
bar: "{{ foo | default(None) }}"
the task
- debug:
msg: bar is empty string
when: bar | length == 0
gives
msg: bar is empty string
But the task
- debug:
msg: foo is empty string
when: foo | default(None) | length == 0
fails with the error:
"... object of type 'NoneType' has no len() ... "
As a result in ternary
, an empty string selects FALSE
and null
selects NONE
.
Notes:
See the Note in Omitting Parameters
Both null
and empty string ""
select FALSE
in ternary if the third parameter is omitted. The tasks
- debug:
msg: "{{ bar | ternary('TRUE', 'FALSE') }}"
- debug:
msg: "{{ foo | default(None) | ternary('TRUE', 'FALSE') }}"
give
msg: FALSE
msg: FALSE