2

From what I understood reading about the topic, null and "{{ None }}" are basically the same thing in Ansible. The difference is that the former is language agnostic YAML syntax and the latter is Python specific (I do not speak that language so I do not know how correct that is). However, as the following Ansible playbook shows, they are different.

- hosts: localhost
  vars:
    a: null
    b: "{{ None }}"
  tasks:
  - name: a always
    debug:
      var: a
  - name: a if none
    debug:
      var: a
    when: a==None
  - name: a if not none
    debug:
      var: a
    when: a!=None
  - name: b always
    debug:
      var: b
  - name: b if none
    debug:
      var: b
    when: b==None
  - name: b if not none
    debug:
      var: b
    when: b!=None

The output from the above is this:

PLAY [localhost] *******************************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************************************
ok: [localhost]

TASK [a always] ********************************************************************************************************************************************************************************
ok: [localhost] => {
    "a": null
}

TASK [a if none] *******************************************************************************************************************************************************************************
ok: [localhost] => {
    "a": null
}

TASK [a if not none] ***************************************************************************************************************************************************************************
skipping: [localhost]

TASK [b always] ********************************************************************************************************************************************************************************
ok: [localhost] => {
    "b": ""
}

TASK [b if none] *******************************************************************************************************************************************************************************
skipping: [localhost]

TASK [b if not none] ***************************************************************************************************************************************************************************
ok: [localhost] => {
    "b": ""
}

PLAY RECAP *************************************************************************************************************************************************************************************
localhost                  : ok=5    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   

I am not so much concerned about the output null vs. "", but what really bothers me is the different test results a==None compared to b==None.

Can somebody please help me understand what I am missing here?

U880D
  • 8,601
  • 6
  • 24
  • 40
Marko
  • 33
  • 4

1 Answers1

2

Regarding

From what I understood reading about the topic, null and "{{ None }}" are basically the same thing in Ansible.

there was a longer conversation under Ansible Issue #7984 "Ansible substitutes YAML null value with "None" in templates".

The difference is that the former is language agnostic YAML syntax and the latter is Python specific

Right, such is discussed under the above mentioned issue.

From the discussion there I understand also that such test is meant for testing defined. And since

To check if it is defined and truthy ... The string "None" evaluates as truthy and defined, the actual python None evaluates as "falsey" and defined.

a test might look like

---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    a: null
    b: "{{ None }}"

  tasks:

  - name: a if none
    debug:
      var: a
    when: a == None

  - name: b if none
    debug:
      var: b
    when: b is defined and not b

Further Discussions and Documentation


If you are interested more in they types of the variables you may have a look into

---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    a: null
    b: "{{ None }}"
    c: !!null

  tasks:

  - name: a if none
    debug:
      msg: 'a: "{{ a }}" is of {{ a | type_debug }}'
    when: a == None

  - name: b if none
    debug:
      msg: 'b: "{{ b }}" is of {{ b | type_debug }}'
    when: b is defined and not b

  - name: c if none
    debug:
      msg: "{{ c }}"
    when: c ==  None

resulting into an output of

TASK [a if none] ************
ok: [localhost] =>
  msg: 'a: "" is of NoneType'

TASK [b if none] ************
ok: [localhost] =>
  msg: 'b: "" is of unicode'

TASK [c if none] ************
ok: [localhost] =>
  msg: null
U880D
  • 8,601
  • 6
  • 24
  • 40
  • Yes, I had read that issue 7984, that is where I read that "null is equivalent to python None". I think my question may be rephrased as follows: Is it possible code Python None value in Ansible other than using YAML's null? I thought that "{{ None }}" would do it, but based on the output it seems to be evaluated to an empty string. I think your output showing b as of Unicode type confirms it. You quoted a statement from the issue that I think does not apply here: The string "None" evaluates as truthy and defined, I do not have string "None" in my example. – Marko Sep 01 '22 at 05:41
  • "_based on the output it seems to be evaluated to an empty string_", right, that is the case. "_I think your output showing b as of Unicode type confirms it_", right, both definitions lead into different internal data types and therefore slightly different behavior. – U880D Sep 01 '22 at 05:52