'Ansible not evaluating correctly mutiple ansible_facts.packages

I have strange issue, I'm sure its just something trivial but I'm stuck.

ansible 2.9.21

I have tasks that should not run if any of 3 or 4 packages are not present on the target.

So at the play beginning I do run:

- name: Gather the package facts
  package_facts:
    manager: auto

Which givers me ansible_facts.packages with all the packages on the server

Next there is some example task:

- name: "Copying temporary files"
  copy:
    src: files.zip
    dest: /tmp/files.zip
    owner: root
    group: root
    mode: 0644
  when:
    - inventory_hostname in groups['cluster_nodes']
    - "'pcs' not in ansible_facts.packages"
    - "'fence-agents-mpath' not in ansible_facts.packages"
    - "'pacemaker' not in ansible_facts.packages"

Now on purpose I remove fence-agents-mpath from server and expected behaviours would be that the task runs because one of the conditions is not met. Thinking about it now, AND operator would not be the right choice probably, but using OR also is not evaluated correctly:

when:
  - inventory_hostname in groups['cluster_nodes']
  - ( "'pcs' not in ansible_facts.packages" ) or ( "'pacemaker' not in ansible_facts.packages" ) or ( "'fence-agents-mpath' not in ansible_facts.packages" )

With that it rest executed on servers where all 3 packages are present... I'm confused.



Solution 1:[1]

This is because:

You can use logical operators to combine conditions. When you have multiple conditions that all need to be true (that is, a logical and), you can specify them as a list

Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#conditionals-based-on-ansible-facts

So by doing

when:
  - inventory_hostname in groups['cluster_nodes']
  - "'pcs' not in ansible_facts.packages"
  - "'fence-agents-mpath' not in ansible_facts.packages"
  - "'pacemaker' not in ansible_facts.packages"

You are basically saying:

When pcs AND fence-agents-mpath AND pacemaker are not installed

What you need here is an or:

when:
  - inventory_hostname in groups['cluster_nodes']
  - "'pcs' not in ansible_facts.packages" or "'fence-agents-mpath' not in ansible_facts.packages" or "'pacemaker' not in ansible_facts.packages"

Also in your current or statement you left out some negations

( "'pcs' not in ansible_facts.packages" ) or 
( "'pacemaker' in ansible_facts.packages" ) or 
##             ^--- missing negation here
( "'fence-agents-mpath' in ansible_facts.packages" )
##                      ^--- another missing negation here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1