Heres some actual execution output for my second example, and for the one 
from @Matt Martz.

Mine
(.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

@Matt Martz' (the only difference is the delegate_to line):
(.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=0

In both cases, the task in inner-task.yml is skipped, since host1 does not 
match the when clause in outer-task.yml. The delegate_to makes no 
difference. If I left that out, it would behave the same. The issue is not 
where it runs, but that it doesn't run at all. It would be perfectly 
acceptable for it to execute on host1, which is in line with the docs, but 
it doesn't run at all.

On Monday, March 19, 2018 at 2:53:44 PM UTC-7, Alex Hunt wrote:
>
> @Matt Martz I have no problem with how delegate_to works. I don't care if 
> it executes on host1. The stuff you wrote does not actually change *if it 
> gets run at all*, only where it would be run if host1 had failed a prior 
> task. It isn't that it tries to run it and fails, but that it doesn't even 
> try to run. The host1 is still in the list of play_hosts, even if it is 
> skipped, so it is still used to determine if we should run. *I have 
> actually run the code you wrote, and it does not solve this issue.*
>
> If you're worried about breaking some obscure code that relies on skipping 
> the task entirely based on the order of the hosts in the inventory, that's 
> fine, but the community needs a way to reliably decide to run exactly one 
> time. It's totally fine for it to be a new directive "actually_run_once".
>
> Where it executes doesn't matter, but that it executes at all, does. It is 
> trivial to use the properly working "delegate_to" clause to control where 
> the task is actually run, but it has no effect on if the ansible tries to 
> run it in the first place.
>
> My interpretation of your code is that you are trying to supply a host to 
> execute the task on in the case that host1 has failed out of the execution 
> due to a prior task failure. In my example, host1 is reachable, working 
> properly, and has not failed any tasks. It is simply skipped due to a when 
> clause that is not attached to the task with run_once. It would be 
> perfectly acceptable and in line with the documentation for the task to 
> execute on host1, but instead the entire task is skipped.
>
> The problem is that the decision to run the task is tied to the first host 
> in the play, not that the execution defaults to the first host in the play.
>
> On Monday, March 19, 2018 at 2:27:46 PM UTC-7, Matt Martz wrote:
>>
>> I fully understand what you are saying. However the difference here is 
>> that you have a misunderstanding about the feature.  You have an idea in 
>> your head, that doesn't match the implementation.
>>
>> The way `run_once` works, is that it defaults to execute on the first 
>> host in the list of hosts on the play, as defined by inventory.  If that 
>> host is failed, that task is then skipped.  Using `delegate_to` offers you 
>> a way to avoid your specific scenario, as it permits you to change what 
>> host ansible targets.  Take special care to re-read what I wrote, instead 
>> of ignoring it.  I recommend using `ansible_play_hosts` in `delegate_to` to 
>> ensure it always targets an available host.  But that may not meet every 
>> persons requirements.  You will have to implement a `delegate_to` on that 
>> host that properly reflects what host to operate on if the "first" host is 
>> not available.
>>
>> Unfortunately, your expectation doesn't align with the implementation and 
>> our definition of what is expected here.
>>
>> I'm telling you how to do what you want, within the context of how 
>> `run_once` actually works. We have no intentions on changing how `run_once` 
>> works.  You'll have to operate within the confines of how run_once 
>> *actually* operates.
>>
>> On Mon, Mar 19, 2018 at 4:18 PM, Alex Hunt <al...@exabeam.com> wrote:
>>
>>> The issue has nothing to do with delegate_to. The issue has to do with 
>>> whether it decides to run at all, which delegate_to has no effect on. I 
>>> don't care which host it runs on, and if I did, I could use delegate_to as 
>>> you have noted. The delegate_to directive works properly.
>>>
>>> It is totally fine for it to execute on the first host in the inventory, 
>>> as long as it runs when that host is skipped for the included task book. I 
>>> apologize if I'm not being clear about what the issue is.
>>>
>>> Here's the same example, updated with a delegate_to, since everyone 
>>> seems to think that matters.
>>>
>>> Inventory
>>> [all]
>>> host1
>>> host2
>>> host3
>>>
>>> Playbook
>>> - name: Test Play
>>>   hosts: all
>>>   tasks:
>>>     - include: outer-task.yml
>>>
>>> outer-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
>>>   delegate_to: 'host2'
>>>
>>> In this example, it should run on host2, but it does not, since host1 
>>> skips the entire inner-task.yml. This is the problem.
>>>
>>> In my original example, I didn't care if it ran on host1, as long as it 
>>> ran, but it doesn't run at all.
>>>
>>> On Monday, March 19, 2018 at 1:54:06 PM UTC-7, Matt Martz wrote:
>>>>
>>>> The behavior is documented via that information provided 
>>>> above. `run_once` in it's current form is designed to be consistent and 
>>>> predictable in which host is picked to execute the task against.
>>>>
>>>> > 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
>>>>
>>>> If the first host is failed, it is removed from the play list, and 
>>>> run_once will therefore be skipped.
>>>>
>>>> Using `delegate_to` allows you to define what you believe is consistent 
>>>> or predictable. If you don't care what host it executes on, using 
>>>> `delegate_to` can be made to do what you want:
>>>>
>>>> - command: whoami
>>>>   run_once: true
>>>>   delegate_to: "{{ ansible_play_hosts|first }}"
>>>>
>>>> `ansible_play_hosts` is updated as hosts fail.
>>>>
>>>> So if it started as:
>>>>
>>>>     "ansible_play_hosts": [
>>>>         "host0",
>>>>         "host1",
>>>>         "host2",
>>>>         "host3",
>>>>         "host4"
>>>>     ]
>>>>
>>>> and `host0` failed, that `delegate_to` above will utilize `host1`.  
>>>> Instead of first, something like `random` could be used too.
>>>>
>>>> If you wish to add further, constructive, clarification to the docs, 
>>>> and potentially examples such as the one I provide above, feel free to 
>>>> submit a documentation pull request.
>>>>
>>>> On Mon, Mar 19, 2018 at 3:33 PM, Alex Hunt <al...@exabeam.com> wrote:
>>>>
>>>>> I think you're confused by what the issue is. Whether I use 
>>>>> delegate_to or not is irrelevant. I don't care which host it runs on, and 
>>>>> if I did, I would use the delegate_to. Even if I use delegate_to, it will 
>>>>> still be skipped, since it evaluates whether to run the task at all based 
>>>>> on the first host. I'm sorry I didn't include a delegate_to in my 
>>>>> example, 
>>>>> which lead to this confusion.
>>>>>
>>>>>
>>>>> http://docs.ansible.com/ansible/latest/playbooks_delegation.html#run-once 
>>>>> makes no mention of the fact that *even with delegate_to* it decides 
>>>>> *whether 
>>>>> to run at all* based on the first host. The mention of delegate_to 
>>>>> actually makes this more confusing, since that The delegate_to should 
>>>>> control where the execution happens (something irrelevant to this issue), 
>>>>> not whether it runs at all. That part is at least consistent, since 
>>>>> delegate_to does not control whether to run it.
>>>>>
>>>>> The issue is that run_once is not actually running once. It is "run 
>>>>> only if the first node in the play says to run it", not "run one time if 
>>>>> it 
>>>>> should run for any host in the play". The latter is intuitive behavior. 
>>>>> You 
>>>>> talk of predictable results, and it is not predictable to have behavior 
>>>>> that changes based on the order of hosts in your inventory file (the 
>>>>> current behavior).
>>>>>
>>>>> Please note that in my example, the when clause is NOT on the task 
>>>>> with run_once. If we make reusable code, we may be including that piece 
>>>>> in 
>>>>> many places, with or without the when clause.
>>>>>
>>>>>
>>>>> On Monday, March 19, 2018 at 12:15:13 PM UTC-7, flowerysong wrote:
>>>>>>
>>>>>> On Monday, March 19, 2018 at 2:49:12 PM UTC-4, Alex Hunt wrote:
>>>>>>>
>>>>>>> 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.
>>>>>>>
>>>>>>
>>>>>> It may confuse some people, but it's both the documented behaviour 
>>>>>> and the least surprising way to do things. Conditionals should not 
>>>>>> affect 
>>>>>> the number of times a run_once task is evaluated even if they result in 
>>>>>> the 
>>>>>> task being skipped.
>>>>>>
>>>>>>
>>>>>> https://docs.ansible.com/ansible/latest/playbooks_delegation.html#run-once
>>>>>>  
>>>>>> says: "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”."
>>>>>>  
>>>>>>
>>>>>>> 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
>>>>>>> host3
>>>>>>>
>>>>>>> Playbook
>>>>>>> - name: Test Play
>>>>>>>   hosts: all
>>>>>>>   tasks:
>>>>>>>     - include: outer-task.yml
>>>>>>>
>>>>>>> outer-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.
>>>>>>>
>>>>>>
>>>>>> You're mixing different ways of limiting where a task runs, with 
>>>>>> predictable results (the task is assigned to one host, and the 
>>>>>> conditional 
>>>>>> results in it being skipped). If you don't care which host it runs on, 
>>>>>> use 
>>>>>> run_once without a conditional. If you want to run it on a specific 
>>>>>> host, 
>>>>>> use delegate_to with run_once or a conditional without run_once.
>>>>>>
>>>>> -- 
>>>>> 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-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
>>>>>  
>>>>> <https://groups.google.com/d/msgid/ansible-project/1b542a8f-8f75-462a-8c11-0fd0c76054dc%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>
>>>>
>>>>
>>>>
>>>> -- 
>>>> Matt Martz
>>>> @sivel
>>>> sivel.net
>>>>
>>> -- 
>>> 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-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/38cf4ed5-6285-464a-a81a-68a44d04709a%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/ansible-project/38cf4ed5-6285-464a-a81a-68a44d04709a%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>
>>
>> -- 
>> Matt Martz
>> @sivel
>> sivel.net
>>
>

-- 
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+unsubscr...@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/ec5ba4dd-a885-4875-8ad6-372777e5fe38%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to