Red Hat Ansible: Yes and No, True and False

During the code review, my colleague and I have fixed a few ageless Boolean variable issues. If you have ever done even a humble sized JavaScript project, you know what I mean. What is in common between Red Hat Ansible and JavaScript? Well, they do not have types. Of course, they have, but the variable type is fluent and always depends on the context. Ansible scripts do not have type declarations, because it's built on top of YAML, combined with Jinja2 templates, and Python is a core language for everything.

On practice, it means you should be quite mindful and consistent in your coding style, because 1, True, yes, and "false" look quite different, but have the same logical meaning and my mean not what you have expected.

The table below summarizes how Ansible interprets variable values. It may be surprising for developers with Java or C/C++ background.

Test Outcome Variable Value
True Any positeve number >0: 1,2 ..
Non-empty string: "1", "True","False",'Nonsence'
Boolean value (unquoted): True,true
Ansible-specific (case-agnostic): Yes,yes
False Any number <=0: 0,-1 ..
Empty string: "", ''
Boolean value (unquoted): False,false
Ansible-specific (case-agnostic): No,no

Even after the significant unification in Oracle Fusion Middleware 12c, the WLST scripting language still adds more fun with the mix of Boolean and String parameters. The only way to keep it under control is to develop and (it's even more important!!) to follow coding guidelines. There are few that I've found as useful:

  • Always quote String values. It applies for everything: variable values, task or play names, static strings, everything. I use double quotes for String and single quotes for the in-line quotes and templates.
  • For Ansible scenarios, use only yes or no as a Boolean value. It brings some overhead in templates but pays off in the long run.
  • If you prefer classic True/False, use them capitalized and do not put any quotes.

This small playbook illustrates how Ansible converts variable values to a Boolean value.

---
- hosts: localhost
  vars:
    upper_bool: True
    lower_bool: false
    quote_false: "false"
    empty_str: ''
    yes_var: yes
    yes_str: "yes"
    cap_yes: Yes
    num_yes: 1
    num_no: 0
  tasks:
    - debug: msg="upper_bool [True] {{ ':' }} Logical value is {{ 'True' if upper_bool else 'False' }}"
    - debug: msg="lower_bool [false] {{ ':' }} Logical value is {{ 'True' if lower_bool else 'False' }}"
    - debug: msg="quote_false [\"false\"] {{ ':' }} Logical value is {{ 'True' if quote_false else 'False' }}"
    - debug: msg="emty_str [ \'\' ] {{ ':' }} Logical value is {{ 'True' if empty_str else 'False' }}"
    - debug: msg="yes_var [yes]  {{ ':' }} Logical value is {{ 'True' if yes_var else 'False' }}"
    - debug: msg="yes_str [\"yes\"] {{ ':' }} Logical value is {{ 'True' if yes_str else 'False' }}"
    - debug: msg="cap_yes [Yes] {{ ':' }} Logical value is {{ 'True' if cap_yes else 'False' }}"
    - debug: msg="num_yes [1] {{ ':' }} Logical value is {{ 'True' if num_yes else 'False' }}"
    - debug: msg="num_no [0] {{ ':' }} Logical value is {{ 'True' if num_no else 'False' }}"
...

ansible-playbook 2.6.3

  config file = /home/user/ansible.cfg

  configured module search path = [u'/opt/ansible/modules']

  ansible python module location = /usr/lib/python2.7/site-packages/ansible

  executable location = /usr/bin/ansible-playbook

  python version = 2.7.5 (default, Sep 26 2019, 13:23:47) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

Using /home/user/ansible.cfg as config file

PLAYBOOK: true-false-yes-no.yml ************************************************************

1 plays in true-false-yes-no.yml

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

TASK [Gathering Facts] *********************************************************************

task path: /home/user/true-false-yes-no.yml:2

ok: [localhost]

META: ran handlers

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:14

ok: [localhost] => {

    "msg": "upper_bool [True] : Logical value is True"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:15

ok: [localhost] => {

    "msg": "lower_bool [false] : Logical value is False"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:16

ok: [localhost] => {

    "msg": "quote_false [\"false\"] : Logical value is True"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:17

ok: [localhost] => {

    "msg": "emty_str [ '' ] : Logical value is False"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:18

ok: [localhost] => {

    "msg": "yes_var [yes]  : Logical value is True"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:19

ok: [localhost] => {

    "msg": "yes_str [\"yes\"] : Logical value is True"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:20

ok: [localhost] => {

    "msg": "cap_yes [Yes] : Logical value is True"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:21

ok: [localhost] => {

    "msg": "num_yes [1] : Logical value is True"

}

TASK [debug] *******************************************************************************

task path: /home/user/true-false-yes-no.yml:22

ok: [localhost] => {

    "msg": "num_no [0] : Logical value is False"

}

META: ran handlers

META: ran handlers

PLAY RECAP *********************************************************************************

localhost                  : ok=10   changed=0    unreachable=0    failed=0


Image author: @geralt (pixabay.com)