[all]
host1
host2
host3
- name: Test Play
hosts: all
tasks:
- include: outer-task.yml- name: Outer task
include: inner-task.yml
when: inventory_hostname != 'host1'
- name: Inner task
command: do_something
run_once: True
When running a task with run_once, if the first node is skipped, the entire task is skipped, rather than running on the first host that is not skipped.This behavior is not what is intuitively understood, this behavior is not mentioned in the docs, and this behavior is almost certainly not what most of people want it to do. There are discussions of this in multiple github issues, the most detailed of which is at https://github.com/ansible/ansible/issues/19966, but there are also at least https://github.com/ansible/ansible/issues/11496, https://github.com/ansible/ansible/issues/13226, and https://github.com/ansible/ansible/issues/23594.
Below is an untested simple example of a scenario that would skip the run_once task, when it should (according to the docs, and common sense) run on one of either host2 or host3.Inventory[all]
host1
host2
host3Playbook- name: Test Play
hosts: all
tasks:
- include: outer-task.ymlouter-task.yml- name: Outer task
include: inner-task.yml
when: inventory_hostname != 'host1'inner-task.yml- name: Inner task
command: do_something
run_once: True
This issue is exacerbated by the fact that the inner task may have no idea why the first host is skipped (IE: we're including a reusable task that may get run many times in different ways). In those cases, there is no way to work around the issue with a simple `when: inventory_hostname == something`, since we don't know what to check against.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/1b542a8f-8f75-462a-8c11-0fd0c76054dc%40googlegroups.com.--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-project+unsubscribe@googlegroups.com.
To post to this group, send email to ansible-project@googlegroups.com.
[all]
host1
host2
host3
- name: Test Play
hosts: all
tasks:
- include: outer-task.yml- name: Outer task
include: inner-task.yml
when: inventory_hostname != 'host1'
- name: Inner task
command: do_something
run_once: True
delegate_to: 'host2'
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/1b542a8f-8f75-462a-8c11-0fd0c76054dc%40googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-project+unsubscribe@googlegroups.com.
To post to this group, send email to ansible-project@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/38cf4ed5-6285-464a-a81a-68a44d04709a%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/38cf4ed5-6285-464a-a81a-68a44d04709a%40googlegroups.com.
(.env) [exabeam@ip-10-10-2-162 test]$ ll
total 16
-rw-rw-r-- 1 exabeam exabeam 79 Mar 19 21:57 inner-task.yml
-rw-rw-r-- 1 exabeam exabeam 206 Mar 19 21:59 inventory
-rw-rw-r-- 1 exabeam exabeam 83 Mar 19 21:57 outer-task.yml
-rw-rw-r-- 1 exabeam exabeam 70 Mar 19 21:56 play.yml
(.env) [exabeam@ip-10-10-2-162 test]$ cat inventory
[all]
host1 ansible_host=10.10.2.162
host2 ansible_host=10.10.2.173
host3 ansible_host=10.10.2.206
[all:vars]
ansible_port=22
ansible_ssh_private_key_file=/home/exabeam/devkey.pem
ansible_ssh_user=exabeam
(.env) [exabeam@ip-10-10-2-162 test]$ cat play.yml
- name: Test Play
hosts: all
tasks:
- include: outer-task.yml
(.env) [exabeam@ip-10-10-2-162 test]$ cat outer-task.yml
- name: Outer task
include: inner-task.yml
when: inventory_hostname != 'host1'
(.env) [exabeam@ip-10-10-2-162 test]$ cat inner-task.yml
- name: Inner task
command: hostname
run_once: True
delegate_to: 'host2'
(.env) [exabeam@ip-10-10-2-162 test]$ ansible-playbook -i inventory play.yml
PLAY [Test Play] ***************************************************************
TASK [setup] *******************************************************************
ok: [host1]
ok: [host3]
ok: [host2]
TASK [Inner task] **************************************************************
skipping: [host1]
PLAY RECAP *********************************************************************
host1 : ok=1 changed=0 unreachable=0 failed=0
host2 : ok=1 changed=0 unreachable=0 failed=0
host3 : ok=1 changed=0 unreachable=0 failed=0(.env) [exabeam@ip-10-10-2-162 test]$ cat inner-task.yml
- name: Inner task
command: hostname
run_once: True
delegate_to: "{{ ansible_play_hosts|first }}"
(.env) [exabeam@ip-10-10-2-162 test]$ ansible-playbook -i inventory play.yml
PLAY [Test Play] ***************************************************************
TASK [setup] *******************************************************************
ok: [host1]
ok: [host3]
ok: [host2]
TASK [Inner task] **************************************************************
skipping: [host1]
PLAY RECAP *********************************************************************
host1 : ok=1 changed=0 unreachable=0 failed=0
host2 : ok=1 changed=0 unreachable=0 failed=0
host3 : ok=1 changed=0 unreachable=0 failed=0My use case involved roles. I had something like- hosts: web:app:dbroles:
- role: myrolewhen: color == "blue"
In the role, there was a task that ran on localhost (via delegate_to), but only once (via run_once) for the whole batch of hosts.Everything worked fine, except that if the first host in inventory happened not to be blue, the run_once caused the localhost task to be skipped. The order of the hosts in inventory was completely arbitrary -- these were EC2 instances at AWS.The eventual workaround was to add the `when` to every single task in the role *except* the run_once one, which made both the playbook and the role less readable.
- group_by: key: color_{{ color | default('octarine') }} - name: Run on localhost once delegate_to: localhost debug: msg: His pills, his hands, his jeans
when: inventory_hostname == groups.color_blue.0- name: Run on localhost once delegate_to: localhost debug: msg: Suddenly I was a lilac sky vars: first_host: "{{ ansible_play_hosts | map('extract', hostvars) | selectattr('color', 'defined') | selectattr('color', 'equalto', 'blue') | first }}" when: inventory_hostname == first_host.inventory_hostname`run_once: true` is effectively the same as adding `when: inventory_hostname == ansible_play_batch.0` to the task .
When “run_once” is not used with “delegate_to” it will execute on the first host, as defined by inventory, in the group(s) of hosts targeted by the play - e.g. webservers[0] if the play targeted “hosts: webservers”.
This approach is similar to applying a conditional to a task
- name: Inner task
command: hostname
when: inventory_hostname == ansible_not_already_skipped_hosts[0]
machine-a
machine-b- hosts: all gather_facts: no tasks: - name: first task ping:
- name: include for second task include_tasks: task.yml when: inventory_hostname == 'machine-b'- name: second task ping: run_once: true - name: include for second task
include: task.yml
static: no
when: inventory_hostname == 'machine-b'