9

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?

  • It would be better to give us real examples instead of "role1", "role2" etc., because maybe you should be doing it differently. But it depends on what you are actually trying to achieve. – Antonis Christofides Feb 10 '15 at 14:59
9

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.

  • Thanks, I think I'll go with a variation of option (2) - I'll make my groups and roles more granular to group my servers together. – Asfand Qazi Feb 10 '15 at 16:38
  • If I call hosts via variable as {{ host1 }} and {{ host2 }} , how can i put them together? – BMW Nov 13 '15 at 3:11
3

This is by design. The only way to go would be to apply role2 only in one playbook to one specific group, and not use role2 in any other playbook on a group that might have common members, like here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.