Score:0

ansible AND operation with WHEN is failing when using ansible_facts

gr flag

Team: I am trying to fail a task when two conditions are not met on a node. ansible_facts['distribution_version'] and ansible_facts['distribution'].

I am passing in two nodes. one node is 20.x ubuntu and other is 18.x.

vars/main.yml

os_distribution: "Ubuntu"
os_version: "20.04"

task is below

- name: "Check Base OS Version maps to expected distribution version {{ os_version }}"
  fail:
    msg: "Task failed as unexpected OS version found: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }} on {{ inventory_hostname }}"
  when:
    - ansible_facts['distribution_version'] is version(os_version, '<')
    - os_distribution != ansible_facts['distribution']

result

TASK [node-validation : Check Base OS Version maps to expected distribution version 20.04] ***
Tuesday 23 November 2021  20:11:32 +0000 (0:00:17.570)       0:00:17.690 ****** 
skipping: [node1]
skipping: [node2]
    

expected output: observe 18.x below not sure what am i missing to get that.

fatal: [node2]: FAILED! => {"changed": false, "msg": "Task failed as unexpected OS version found: Ubuntu 18.04 on node2"}

When I remove - os_distribution != ansible_facts['distribution'] then I get expected result as below but I want to satisfy two conditions not just one.

[fatal: [node2]: FAILED! => {"changed": false, "msg": "Task failed as unexpected OS version found: Ubuntu 18.04 on node2 }}"}

reference to ansible_facts

FACTS for 20.x

10:17:59  [0;32m        "distribution": "Ubuntu",[0m
10:17:59  [0;32m        "distribution_file_parsed": true,[0m
10:17:59  [0;32m        "distribution_file_path": "/etc/os-release",[0m
10:17:59  [0;32m        "distribution_file_variety": "Debian",[0m
10:17:59  [0;32m        "distribution_major_version": "18",[0m
10:17:59  [0;32m        "distribution_release": "bionic",[0m
10:17:59  [0;32m        "distribution_version": "18.04",[0m

FACTS for 20.x

10:23:43  [0;32m        "distribution": "Ubuntu",[0m
10:23:43  [0;32m        "distribution_file_parsed": true,[0m
10:23:43  [0;32m        "distribution_file_path": "/etc/os-release",[0m
10:23:43  [0;32m        "distribution_file_variety": "Debian",[0m
10:23:43  [0;32m        "distribution_major_version": "20",[0m
10:23:43  [0;32m        "distribution_release": "focal",[0m
10:23:43  [0;32m        "distribution_version": "20.04",[0m
Score:0
in flag

When you provide a when a list it performs an AND of the two expressions. And here is the standard AND truth table.

Cond1 Cont2 | Result
False False | False
False True  | False
True  False | False
True  True  | True

Consider your have

os_distribution: "Ubuntu"             # variable
ansible_facts.distribution: "Ubuntu"  # fact

The Expression "Ubuntu" != "Ubuntu" is False, and since per the truth table if either of the conditions are false, the final result is false. Ansible will only execute the task when the result is true.

Anyway, I suepct to get the result you want should change your when to an OR instead of having a list that are joined by an AND.

when:
  ansible_facts['distribution_version'] is version(os_version, '<') or
  os_distribution != ansible_facts['distribution']

Demonstration playbook + output

---
- hosts: localhost
  vars:
    os_distribution: "Ubuntu"
    os_version: "20.04"
    ansible_facts:
      distribution: "Ubuntu"
      distribution_file_parsed: True
      distribution_file_path: "/etc/os-release"
      distribution_file_variety: "Debian"
      distribution_major_version: "18"
      distribution_release: "bionic"
      distribution_version: "18.04"

  tasks:
  - debug:
      msg: >-
        {{ os_distribution }} {{ansible_facts['distribution'] }}
        {{ os_distribution != ansible_facts['distribution'] }}
  - debug:
      msg: >-
        {{ ansible_facts['distribution_version'] }} {{ os_version }}
        {{ ansible_facts['distribution_version'] is version(os_version, '<') }}

  - name: "Check Base OS Version maps to expected distribution version {{ os_version }}"
    debug:
      msg: "Task failed as unexpected OS version found: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }} on {{ inventory_hostname }}"
    when:
      ansible_facts['distribution_version'] is version(os_version, '<') or
      os_distribution != ansible_facts['distribution']

- hosts: localhost
  vars:
    os_distribution: "Ubuntu"
    os_version: "20.04"
    ansible_facts:
      distribution: "Ubuntu"
      distribution_file_parsed: true
      distribution_file_path: "/etc/os-release"
      distribution_file_variety: "Debian"
      distribution_major_version: "20"
      distribution_release: "focal"
      distribution_version: "20.04"

  tasks:
  - debug:
      msg: >-
        {{ os_distribution }} {{ansible_facts['distribution'] }}
        {{ os_distribution != ansible_facts['distribution'] }}
  - debug:
      msg: >-
        {{ ansible_facts['distribution_version'] }} {{ os_version }}
        {{ ansible_facts['distribution_version'] is version(os_version, '<') }}

  - name: "Check Base OS Version maps to expected distribution version {{ os_version }}"
    debug:
      msg: "Task failed as unexpected OS version found: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }} on {{ inventory_hostname }}"
    when:
      ansible_facts['distribution_version'] is version(os_version, '<') or
      os_distribution != ansible_facts['distribution']

# Output

# TASK [debug] ***************************************************************************************************************************
# ok: [localhost] => {
#     "msg": "Ubuntu Ubuntu False"
# }
#
# TASK [debug] ***************************************************************************************************************************
# ok: [localhost] => {
#     "msg": "18.04 20.04 True"
# }
#
# TASK [Check Base OS Version maps to expected distribution version 20.04] ***************************************************************
# ok: [localhost] => {
#     "msg": "Task failed as unexpected OS version found: Ubuntu 18.04 on localhost"
# }
#
# PLAY [localhost] ***********************************************************************************************************************
#
# TASK [debug] ***************************************************************************************************************************
# ok: [localhost] => {
#     "msg": "Ubuntu Ubuntu False"
# }
#
# TASK [debug] ***************************************************************************************************************************
# ok: [localhost] => {
#     "msg": "20.04 20.04 False"
# }
#
# TASK [Check Base OS Version maps to expected distribution version 20.04] ***************************************************************
# skipping: [localhost]
#

PS, if you want the math on why you switch from an AND to an OR on negation see De_Morgan's_laws

AhmFM avatar
gr flag
agree and I believe that is what i thought am doing? I have one node1 that is TT and other is TF. so I should have got failure for node2 that prints message and skip on node1 that has TT with no message. but am getting skip and no message in both situations
in flag
If you need more added an example playbook and output that may help, and you can use to test more.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.