I have the following Ansible playbook (im using 2.9.21), which is working perfectly fine, just as I want it to work:
- name: Sync package_00 package to the remote hosts
ansible.builtin.synchronize:
src: /home/ansible/files/package_00
dest: /tmp/
recursive: false
archive: false
checksum: true
delete: false
- name: Sync package_01 package to the remote hosts
ansible.builtin.synchronize:
src: /home/ansible/files/package_01
dest: /tmp/
recursive: false
archive: false
checksum: true
delete: false
- name: Sync package_02 package to the remote hosts
ansible.builtin.synchronize:
src: /home/ansible/files/package_02
dest: /tmp/
recursive: false
archive: false
checksum: true
delete: false
It correctly grabs the first task and copies the first file package_00 to all the hosts specified. As soon as it is ready with the first file, it starts the second file.
Now, since I have a huge number of files and the above mentioned example is quite ugly it would be nice to have some loop or with_items solution, but unfortunately I was unable to achieve the exact same functionality as described. Whenever I change to something like this, the execution is completely different:
- name: Sync the packages to the remote host
ansible.builtin.synchronize:
src: /home/ansible/files/package_{{ item }}
dest: /tmp/
recursive: false
archive: false
checksum: true
delete: false
loop: "{{ range(0, 100) | list }}"
Now Ansible tries to copy all the files to the first host, and all the files to the second host, and so on.
I have tried to experiment with loop, with_items, serial keyword, but no luck.
With significant overhead, decreased performance and increased runtime, the following minimal example show how to achieve such behavior.
Inventory example.ini
[managed]
remote.example.com
managed.example.com
external.example.com
Task file debug.yml
- name: "Loop included {{ item }}"
debug:
msg: "package_{{ ansible_loop.index0 }}"
Playbook main.yml
---
- hosts: managed
become: false
gather_facts: false
tasks:
- name: Loop directly
debug:
msg: "package_{{ item }}"
loop: "{{ range(0, 3) | list }}"
- name: Include
include_tasks:
file: debug.yml
loop: "{{ ansible_play_hosts }}"
loop_control:
extended: true
Called via
ansible-playbook --inventory example.ini main.yml
Resulted output and runtime
PLAY [managed] *****************************************************************************************************
Friday 04 October 2024 18:46:44 +0200 (0:00:00.027) 0:00:00.027 ********
TASK [Loop directly] ***********************************************************************************************
ok: [remote.example.com] => (item=0) =>
msg: package_0
ok: [remote.example.com] => (item=1) =>
msg: package_1
ok: [remote.example.com] => (item=2) =>
msg: package_2
ok: [managed.example.com] => (item=0) =>
msg: package_0
ok: [managed.example.com] => (item=1) =>
msg: package_1
ok: [external.example.com] => (item=0) =>
msg: package_0
ok: [managed.example.com] => (item=2) =>
msg: package_2
ok: [external.example.com] => (item=1) =>
msg: package_1
ok: [external.example.com] => (item=2) =>
msg: package_2
Friday 04 October 2024 18:46:44 +0200 (0:00:00.065) 0:00:00.093 ********
TASK [Include] *****************************************************************************************************
included: debug.yml for remote.example.com, managed.example.com, external.example.com => (item=remote.example.com)
included: debug.yml for remote.example.com, managed.example.com, external.example.com => (item=managed.example.com)
included: debug.yml for remote.example.com, managed.example.com, external.example.com => (item=external.example.com)
Friday 04 October 2024 18:46:45 +0200 (0:00:00.048) 0:00:00.141 ********
TASK [Loop included remote.example.com] ****************************************************************************
ok: [remote.example.com] =>
msg: package_0
ok: [managed.example.com] =>
msg: package_0
ok: [external.example.com] =>
msg: package_0
Friday 04 October 2024 18:46:45 +0200 (0:00:00.037) 0:00:00.179 ********
TASK [Loop included managed.example.com] ***************************************************************************
ok: [remote.example.com] =>
msg: package_1
ok: [managed.example.com] =>
msg: package_1
ok: [external.example.com] =>
msg: package_1
Friday 04 October 2024 18:46:45 +0200 (0:00:00.036) 0:00:00.215 ********
TASK [Loop included external.example.com] **************************************************************************
ok: [remote.example.com] =>
msg: package_2
ok: [managed.example.com] =>
msg: package_2
ok: [external.example.com] =>
msg: package_2
PLAY RECAP *********************************************************************************************************
external.example.com : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
managed.example.com : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remote.example.com : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
Friday 04 October 2024 18:46:45 +0200 (0:00:00.067) 0:00:00.283 ********
===============================================================================
Loop included external.example.com --------------------------------------------------------------------------- 0.07s
Loop directly ------------------------------------------------------------------------------------------------ 0.07s
Include ------------------------------------------------------------------------------------------------------ 0.05s
Loop included remote.example.com ----------------------------------------------------------------------------- 0.04s
Loop included managed.example.com ---------------------------------------------------------------------------- 0.04s
Please take note that
"... since I have a huge number of files ... achieve the exact same functionality as described."
that should be avoided and you should overthink your Use Case.