Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

include_role+with_items executes tasks num_hosts*num_items times on *each* host #18748

Closed
amenonsen opened this issue Dec 5, 2016 · 7 comments · Fixed by #30372
Closed

include_role+with_items executes tasks num_hosts*num_items times on *each* host #18748

amenonsen opened this issue Dec 5, 2016 · 7 comments · Fixed by #30372
Assignees
Labels
affects_2.3 This issue/PR affects Ansible v2.3 affects_2.4 This issue/PR affects Ansible v2.4 bug This issue/PR relates to a bug. support:core This issue/PR relates to code supported by the Ansible Engineering Team.

Comments

@amenonsen
Copy link
Contributor

ISSUE TYPE
  • Bug Report
COMPONENT NAME

core

ANSIBLE VERSION
devel
CONFIGURATION

N/A

OS / ENVIRONMENT

N/A

SUMMARY

include_role+with_items executes once per item per host on each host.

STEPS TO REPRODUCE

x.yml::

---
- hosts: all
  gather_facts: no
  tasks:
    - include_role: name=p
      with_items: [1,2]

roles/p/tasks/main.yml::

- command: cat /proc/uptime
EXPECTED RESULTS

I expected cat /proc/uptime to be executed twice on a and twice on b.

ACTUAL RESULTS

It actually executes cat /proc/uptime four times on both hosts.

TASK [p : command] ****************************************************************************************************************************************************************************
changed: [b] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002532", "end": "2016-12-05 20:00:08.080587", "rc": 0, "start": "2016-12-05 20:00:08.078055", "stderr": "", "stdout": "987830.64 3614256.86", "stdout_lines": ["987830.64 3614256.86"], "warnings": []}
changed: [a] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002532", "end": "2016-12-05 20:00:08.080587", "rc": 0, "start": "2016-12-05 20:00:08.078055", "stderr": "", "stdout": "987830.64 3614256.86", "stdout_lines": ["987830.64 3614256.86"], "warnings": []}

TASK [p : command] ****************************************************************************************************************************************************************************
changed: [b] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002069", "end": "2016-12-05 20:00:08.214287", "rc": 0, "start": "2016-12-05 20:00:08.212218", "stderr": "", "stdout": "987830.77 3614257.08", "stdout_lines": ["987830.77 3614257.08"], "warnings": []}
changed: [a] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002710", "end": "2016-12-05 20:00:08.214238", "rc": 0, "start": "2016-12-05 20:00:08.211528", "stderr": "", "stdout": "987830.77 3614257.08", "stdout_lines": ["987830.77 3614257.08"], "warnings": []}

TASK [p : command] ****************************************************************************************************************************************************************************
changed: [a] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002648", "end": "2016-12-05 20:00:08.340613", "rc": 0, "start": "2016-12-05 20:00:08.337965", "stderr": "", "stdout": "987830.90 3614257.30", "stdout_lines": ["987830.90 3614257.30"], "warnings": []}
changed: [b] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002124", "end": "2016-12-05 20:00:08.345231", "rc": 0, "start": "2016-12-05 20:00:08.343107", "stderr": "", "stdout": "987830.91 3614257.30", "stdout_lines": ["987830.91 3614257.30"], "warnings": []}

TASK [p : command] ****************************************************************************************************************************************************************************
changed: [b] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002734", "end": "2016-12-05 20:00:08.475102", "rc": 0, "start": "2016-12-05 20:00:08.472368", "stderr": "", "stdout": "987831.04 3614257.51", "stdout_lines": ["987831.04 3614257.51"], "warnings": []}
changed: [a] => {"changed": true, "cmd": ["cat", "/proc/uptime"], "delta": "0:00:00.002468", "end": "2016-12-05 20:00:08.478968", "rc": 0, "start": "2016-12-05 20:00:08.476500", "stderr": "", "stdout": "987831.04 3614257.52", "stdout_lines": ["987831.04 3614257.52"], "warnings": []}

PLAY RECAP ************************************************************************************************************************************************************************************
a                          : ok=4    changed=4    unreachable=0    failed=0   
b                          : ok=4    changed=4    unreachable=0    failed=0   
@ansibot ansibot added bug_report affects_2.3 This issue/PR affects Ansible v2.3 labels Dec 5, 2016
@sirkubax
Copy link
Contributor

sirkubax commented Dec 6, 2016

Sorry to say, but it seems to work properly.
I can not see the place, where you would limit or delegate the execution.
You may misunderstood the concept.

Please play with the following:


---
- hosts: all
  gather_facts: no
  tasks:
    - debug: msg="{{ item }}"
      with_items: [1,2]

    - include_role: name=p
     with_items: "{{ play_hosts }}"
     #with_items: [1,2]


roles/p/tasks/main.yml::
- debug: msg="{{ item }} {{ inventory_hostname }}"

- command: cat /proc/uptime
  when: item == inventory_hostname

The 'when: item == inventory_hostname' would work for you in this example, but please note that this would expect the 'item' variable every time you use this role.
You may rethink your concept, and use a delegate but please remember about KISS (https://en.wikipedia.org/wiki/KISS_principle)

@callipeo
Copy link
Contributor

Hi,

I was about to report the same behavior yesterday before noticing this issue. It seems surprising to me, and it certainly behaves very differently than a task include:

# roles/example/tasks/example.yml
---
    -   name: "describe {{ included_variable }} with included task"
        debug: msg="{{ included_variable }} {{ ansible_play_batch }}"


# roles/example/tasks/main.yml
---
    -   include_role:
            name: included
            allow_duplicates: no
        with_items:
            -   example role 1
        loop_control:
            loop_var: included_variable

    -   include: example.yml
        vars:
            included_variable: "{{ item }}"
        with_items:
            -   example task 1


# roles/included/tasks/main.yml
---
    -   name: "describe {{ included_variable }} with included role"
        debug: msg="{{ included_variable }} {{ ansible_play_batch }}"


# site.yml
---
    -   hosts: all

        connection: local
        gather_facts: no

        roles:
            -   example


# inventory.ini
local_a ansible_host=127.0.0.1
local_b ansible_host=127.0.0.1
local_c ansible_host=127.0.0.1


# ansible-playbook -i inventory.ini site.yml
PLAY [all] **************************************************************************************************************************************************************************

TASK [example : include_role] *******************************************************************************************************************************************************

TASK [included : describe example role 1 with included role] ************************************************************************************************************************
ok: [local_b] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_a] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_c] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}

TASK [included : describe example role 1 with included role] ************************************************************************************************************************
ok: [local_a] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_b] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_c] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}

TASK [included : describe example role 1 with included role] ************************************************************************************************************************
ok: [local_a] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_b] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_c] => {
    "msg": "example role 1 [u'local_a', u'local_b', u'local_c']"
}

TASK [example : include] ************************************************************************************************************************************************************
included: /Users/francesco/Development/ansible_include_role/roles/example/tasks/example.yml for local_b, local_a, local_c

TASK [example : describe example task 1 with included task] *************************************************************************************************************************
ok: [local_a] => {
    "msg": "example task 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_b] => {
    "msg": "example task 1 [u'local_a', u'local_b', u'local_c']"
}
ok: [local_c] => {
    "msg": "example task 1 [u'local_a', u'local_b', u'local_c']"
}

PLAY RECAP **************************************************************************************************************************************************************************
local_a                    : ok=5    changed=0    unreachable=0    failed=0   
local_b                    : ok=5    changed=0    unreachable=0    failed=0   
local_c                    : ok=5    changed=0    unreachable=0    failed=0   


Am I missing something, perhaps in the documentation? Why would someone include the very same role in each host, one time for every host included in the playbook?

@jwdevs
Copy link

jwdevs commented Mar 3, 2017

Same problem for me. allow_duplicates: False did not work.
This is also here: http://stackoverflow.com/questions/42171103/ansible-include-role-on-a-loop-running-unexpected-number-of-times

I've set serial: 1 on the play and it did help (as a workaround).

@mansunkuo
Copy link
Contributor

Thanks @callipeo's example code.
There is another workaround that you can just replace include_role with include.
For example, you can replace

  tasks:
    - name: Create users
      include_role:
        name: add_user
      vars:
        add_user:
          name: "{{ item.key }}"
          password:
          key: "{{ item.value.key }}"
          is_admin: no
      with_dict: "{{ users }}"

with

  tasks:
    - name: Create users
      include: roles/add_user/tasks/main.yml
      vars:
        add_user:
          name: "{{ item.key }}"
          password:
          key: "{{ item.value.key }}"
          is_admin: no
      with_dict: "{{ users }}"

@ansibot ansibot added the support:core This issue/PR relates to code supported by the Ansible Engineering Team. label Jun 29, 2017
@dmizelle
Copy link

dmizelle commented Jul 5, 2017

it appears that with an inventory like:

[all]
host1
host2
host3
host4

You can avoid the looping by setting the include_role as static:

---
- name: Include some other role
  include_role:
    name: other_role
  static: yes

I don't really understand why this fixes it, but it stopped us from looping in our setup. It may be related to the fact that setting an include as static doesn't allow you to loop on it with things like with_items, etc.

@IngussNeilands
Copy link

Still exists on devel (2.4)

include_role with loop executes num_hosts*num_items times on each host

only thing that helps - serial: 1

@nrwahl2
Copy link
Contributor

nrwahl2 commented Aug 27, 2017

Looks like we need to get import_role implemented.

@mckerrj mckerrj added the affects_2.4 This issue/PR affects Ansible v2.4 label Sep 14, 2017
jimi-c added a commit to jimi-c/ansible that referenced this issue Sep 14, 2017
Also fixes instances where conditionals or other variables may result in
hosts executing lists of tasks of differing sizes.

Fixes ansible#18748
jimi-c added a commit that referenced this issue Sep 14, 2017
Also fixes instances where conditionals or other variables may result in
hosts executing lists of tasks of differing sizes.

Fixes #18748
abadger pushed a commit that referenced this issue Sep 14, 2017
Also fixes instances where conditionals or other variables may result in
hosts executing lists of tasks of differing sizes.

Fixes #18748
(cherry picked from commit 6730f81)
prasadkatti pushed a commit to prasadkatti/ansible that referenced this issue Oct 1, 2017
Also fixes instances where conditionals or other variables may result in
hosts executing lists of tasks of differing sizes.

Fixes ansible#18748
BondAnthony pushed a commit to BondAnthony/ansible that referenced this issue Oct 5, 2017
Also fixes instances where conditionals or other variables may result in
hosts executing lists of tasks of differing sizes.

Fixes ansible#18748
@ansibot ansibot added bug This issue/PR relates to a bug. and removed bug_report labels Mar 7, 2018
@ansible ansible locked and limited conversation to collaborators Apr 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.3 This issue/PR affects Ansible v2.3 affects_2.4 This issue/PR affects Ansible v2.4 bug This issue/PR relates to a bug. support:core This issue/PR relates to code supported by the Ansible Engineering Team.
Projects
None yet
Development

Successfully merging a pull request may close this issue.