using if condition to assign True or False to gather_facts in Ansible doesnt work

Viewed 3550
---
- hosts: "{{ run_on_node|default('mysql_cluster_sql[0]')}}"
  connection: "{% if migrated is defined and migrated == 'yes' %}local{% else %}ssh{% endif %}" # This works as we are assigning non boolean value
  gather_facts: "{% if migrated is defined and migrated == 'yes' %}false{% else %}true{% endif %}" #This doesnt work well
  tasks:
    - debug: var=ansible_all_ipv4_addresses
    - debug: var=ansible_default_ipv4.address

Inventory File:

[mysql_cluster_sql]
10.200.1.191 migrated=yes

The variable has the value as true and false based on condition but even when gather_facts is false, it gathers the facts.

2 Answers

gather_facts will be evaluted before the play loop has started so ansible cannot know which group/host var it should load in this case. The problem is exactly the same for the connection attribute.

I only see one way to fulfill your requirement by gathering facts explicitly and setting the connection for each host. Ini format does not play well with this for the inventory so I transformed to yaml. I also modified your default hosts expression in playbook so that it directly get the host name from inventory. You can keep yours if it suits your needs if you wish.

Inventory:

---
all:
  children:
    mysql_cluster_sql:
      hosts:
        10.200.1.191:
          migrated: yes
      vars:
        ansible_connection: "{{ migrated | default(false) | bool | ternary('local', 'ssh') }}"

Playbook:

---
- hosts: "{{ run_on_node | default(groups['mysql_cluster_sql'][0]) }}"
  gather_facts: false

  tasks:

    - name: gather_facts if not migrated
      setup:
      when: not (migrated | default(false) | bool)

    - debug:
        var: ansible_all_ipv4_addresses

    - debug:
        var: ansible_default_ipv4.address

Simplify and fix the condition. Use the default value. This will cover both tests, e.g.

shell> cat pb.yml
- hosts: localhost
  gather_facts: "{{ (migrated|default('no') == 'yes')|ternary(false, true) }}"
  tasks:
    - meta: noop

will gather facts without the variable migrated defined

shell> ansible-playbook pb.yml

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

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

, or when the variable is set to other value than 'yes'

shell> ansible-playbook pb.yml -e migrated=no

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

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

When the variable is set to 'yes' no facts will be gathered

shell> ansible-playbook pb.yml -e migrated=yes

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

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

Jinja

If you insist on Jinja the playbook below gives the same results

shell> cat pb.yml
- hosts: localhost
  gather_facts: "{% if migrated|default('no') == 'yes' %}
                 false
                 {% else %}
                 true
                 {% endif %}"
  tasks:
    - meta: noop

Boolean

You can further simplify the test by explicit conversion to Boolean, e.g.

- hosts: localhost
  gather_facts: "{{ (migrated|default('no')|bool)|ternary(false, true) }}"
  tasks:
    - meta: noop

Truthy/Falsy

Make sure you understand how Boolean conversion and testing work. See results of the tasks

    - debug:
        msg: "True"
      loop: [yes, Yes, true, True, xxx]
      when: item|bool

    - debug:
        msg: "False"
      loop: [no, No, false, False, xxx]
      when: not item|bool

    - debug:
        msg: "{{ item|bool|ternary(True, False) }}"
      loop: [yes, Yes, true, True, xxx,
             no, No, false, False, xxx]

    - debug:
        msg: "{{ item|ternary(True, False) }}"
      loop: [yes, Yes, true, True, xxx,
             no, No, false, False, xxx]

Q: "Passing the variable 'migrated' from within the inventory does not work."

A: You're right. It seems that the inventory variables are not available at the time gather_facts is running. Use setup as a workaround. For example

- hosts: localhost
  gather_facts: false
  tasks:
    - setup:
      when: (migrated|default('no')|bool)|ternary(false, true)
Related