Ansible: a host appears in more than one group, and both groups have the same tasks in them; any way to run tasks once

ansible

I have a playbook that looks something like this:

---
- hosts: group1
  roles:
    - role1
    - role2

- hosts: group2
  roles:
    - role2
    - role3

Now say I have a hosts file that has an entry like this:

[group1]
host1.example.com

[group2]
host1.example.com

Ansible will run the tasks in role2 TWICE for host1.example.com because it appears in 2 groups, and each have role2 assigned to them.

How can I make Ansible realise it has the same role included twice, and thus it should only run it once?

Best Answer

As mentioned, this is by design. Ansible executes just one play at a time. Your playbook consists of two plays (the two items in the root-level YAML list defined by the playbook file). The first play applies role1 and role2 to group1. That play executes first, and only once it's finished does the second play begin. But Ansible doesn't attempt to merge the plays together logically. After all, you might actually want the tasks in role2 to run twice.

As for addressing the problem, there are a few ways you could work around this, and which you choose will depend on the details of the groups and roles.

If all of the tasks in role2 are idempotent, ie if they can be run multiple times and end up with the same result every time, then all you are really losing is time, and it's okay to let the roles repeat. If the roles take a really long time to apply or if you can't make it idempotent, then consider the following ideas:


You could split the playbook into three plays, and apply the roles individually:

---
- hosts: group1
  roles:
    - role1

- hosts: group1:group2
  roles:
    - role2

- hosts: group2
  roles:
    - role3

Or if your roles need to be grouped together, you could create a third group for the servers that need all three roles. You don't need to take them out of the other two groups. You could create the group in your inventory file like this:

[group1and2:children]
group1
group2

Then in your playbook you could again split into three plays, but use the third group to avoid re-running roles:

---
- hosts: group1:!group1and2
  roles:
    - role1
    - role2

 - hosts: group1and2
   roles:
     - role1
     - role2
     - role3

 - hosts: group2:!group1and2
   roles:
     - role2
     - role3

That's pretty ugly but it might be useful in some cases.