Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
Further note for people on older releases (2 or newer I believe, < 2.4): You can achieve the same thing as include_tasks with include and static: no, like so: - name: include for second task include: task.yml static: no when: inventory_hostname == 'machine-b' Hope that helps! On Friday, 23 March 2018 19:06:11 UTC, Alex Hunt wrote: > > Thank you Brian for updating the docs. That makes it much more clear. > > And thank you James for the workaround!!! The change to dynamic > include_tasks rather than the older static include statement seems to work > great. > > Note for people on older releases, you have to be running at least Ansible > 2.4 to have include_tasks. > -- 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/5ea94eea-28ef-4956-a6c0-dcf3d198e24a%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
Thank you Brian for updating the docs. That makes it much more clear. And thank you James for the workaround!!! The change to dynamic include_tasks rather than the older static include statement seems to work great. Note for people on older releases, you have to be running at least Ansible 2.4 to have include_tasks. -- 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/22928346-7ef8-40ee-81e5-08db6df8e3c1%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
I updated the docs in an effort to clarify this, https://github.com/ansible/ansible/pull/37754, any suggestions that help avoid more confusion on this subject are welcomed. -- -- Brian Coca -- 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/CACVha7exL3bQ60D%2BEAHkL%3DKW6-VzeJ1rC%2BYDtnas_c8Sr%2BBJBA%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
Thank you everyone who chimed in on this discussion, it's really helped me understand how run_once works. As for workarounds - Alex I think you were on the right track with the include, but it needs to be dynamic. I think this does what you want: inventory: machine-a machine-b playbook.yml: - hosts: all gather_facts: no tasks: - name: first task ping: - name: include for second task include_tasks: task.yml when: inventory_hostname == 'machine-b' task.yml: - name: second task ping: run_once: true Because this include is dynamic instead of static, the first host - "machine-a" - doesn't encounter the "run_once" task at all, so it runs when the second host reaches it. (The reason this doesn't happen with your example in the first message on this thread is because the import is static: the include task runs for all machines, and the condition applies to the tasks it includes, so it's equivalent to having the "when" written on the run_once task.) This example is trivial, but in a larger setup this could be used to run a task only once, on a host matching certain conditions, in a way that is far less fragile than depending on inventory order. Hopefully this is helpful to anyone trying to combine run_once and conditions. On Tuesday, 20 March 2018 17:46:38 UTC, Alex Hunt wrote: > > Thanks everyone, I think the root of the issue is finally clear. > > I'd love to have a 'run_first_host_that_matches_when' keyword, though I > understand there might be technical issues getting in the way. I think the > most intuitive way to set the status would be to set it for all hosts that > match the when, but that's a bit of an arbitrary thing. > > The current set of keywords makes it very difficult to make reusable code. > If we want to include roles or tasks conditionally, we simply can't use > run_once safely. Even the "ugly-ass workarounds" mentioned above are not > possible in some instances, since the conditions might be completely > different depending on where it gets included. > > Another alternative would be to expose the list of hosts skipped by outer > when clauses in another variable that can be used in inner when clauses. > Something like "ansible_not_already_skipped_hosts". I know the logic is to > skip the task, not the host, but when using includes, it's effectively the > same. If we haven't done any includes with when clauses, it'd be > effectively the same as ansible_play_hosts. > > If we had a variable like that, I could put something like this in the > inner-task.yml: > - name: Inner task > command: hostname > when: inventory_hostname == ansible_not_already_skipped_hosts[0] > If I needed to save the result to all hosts, I could register the result > and then follow up with a set_fact using the var from that one host. > > This isn't as clean as having a 'run_first_host_that_matches_when' > keyword, but still prevents the "ugly-ass workarounds" from being needed on > EVERY included task. > > On Tuesday, March 20, 2018 at 7:07:27 AM UTC-7, Brian Coca wrote: >> >> A couple of clarifications, these are important when you hit the >> corner case in which it matters: >> >> - its not 'run on the first host in play/inventory' its 'run on the >> first host that reaches the task' which means that hosts that fail >> and/or are removed in previous tasks are not considered. Normally (in >> the absence of failure) this does mean the first host in >> play/inventory, changing to other strategies can affect this. >> >> - it is 'mostly' equivalent to `when: inventory_hostname == >> ansible_play_batch.0` but there is one major difference, other hosts >> are not 'skipped', they are all given the same status/return from the >> single execution. >> >> >> The feature should really be named >> 'only_first_host_tries_to_run_and_applies_status_to_rest'. To make it >> work as 'run_first_host_that_matches_when' would make the part of >> applying the status to all hosts a lot more difficult to do sanely ... >> do we set 'skipped' for the ones we skipped? do we set same status for >> all hosts? >> >> At this point I don't see us modifying the feature (maybe clarifying >> docs?), but I'm open to create a new set of keywords that allows for >> the difference in range of behaviors not already available via >> conditional construction. >> >> -- >> -- >> Brian Coca >> > -- 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/4b365dd9-8307-49f2-9240-2cc02ff1bf3e%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
A couple of clarifications, these are important when you hit the corner case in which it matters: - its not 'run on the first host in play/inventory' its 'run on the first host that reaches the task' which means that hosts that fail and/or are removed in previous tasks are not considered. Normally (in the absence of failure) this does mean the first host in play/inventory, changing to other strategies can affect this. - it is 'mostly' equivalent to `when: inventory_hostname == ansible_play_batch.0` but there is one major difference, other hosts are not 'skipped', they are all given the same status/return from the single execution. The feature should really be named 'only_first_host_tries_to_run_and_applies_status_to_rest'. To make it work as 'run_first_host_that_matches_when' would make the part of applying the status to all hosts a lot more difficult to do sanely ... do we set 'skipped' for the ones we skipped? do we set same status for all hosts? At this point I don't see us modifying the feature (maybe clarifying docs?), but I'm open to create a new set of keywords that allows for the difference in range of behaviors not already available via conditional construction. -- -- Brian Coca -- 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/CACVha7e2HFYBmMjiXTU83gO0N-XErCQAGVy2cz3dMHtgsWY9HQ%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
Yep, your suggestions there are the kind of things I had in mind with the phrase "ugly-ass workaround". :^) (They're task-level, and can't be applied to the inclusion of the role in the playbook; they require baking logic about the way you manage colors into the role; etc.) `run_once: true` is effectively the same as adding `when: > inventory_hostname == ansible_play_batch.0` to the task . > This is a very clear and concise way to put it, and highlights exactly how run_once works, and why it doesn't mean "run this task once", but "run this task on the first host in the list of hosts in the play, not the first host that you're actually running tasks on". It's not a guarantee that a task will run once, it's an alias for a common `when` pattern. I'm juggling too many other things to want to put in a documentation PR right now, but if anyone else does, I think this would be useful to clarify. In particular, where the docs say 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 I think it'd be clearer if this said something about how it *always* executes in the context of the first host, as defined by inventory, in the group(s) of hosts targeted by the play -- the delegate_to part doesn't change that, it just changes which host actually runs the task -- and that this isn't just "similar" to applying a conditional to a task, it's *identical* to supplying a conditional to a task, and that in particular, this condition is logical-AND-ed with any other conditions on the task, such that if the task has conditions that cause it to get skipped on the first host in inventory, this condition will cause it to get skipped on all the other hosts as well. On Tuesday, March 20, 2018 at 1:13:58 AM UTC-4, flowerysong wrote: > > On Monday, March 19, 2018 at 9:42:58 PM UTC-4, Josh Smift wrote: >> >> My use case involved roles. I had something like >> >> - hosts: web:app:db >> roles: >> - role: myrole >> when: 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. >> > > Disregarding the implementation details, `run_once: true` is effectively > the same as adding `when: inventory_hostname == ansible_play_batch.0` to > the task . As I said before, if that's not what you want you should instead > write a conditional that expresses your actual intent. > > Here's one approach: > > - 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 > > Or you might opt for something like this, which is overly clever and > requires a very recent version of Jinja: > > - 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 > > Or you might restructure the playbook so it only runs the role on blue > hosts and doesn't need a separate conditional, and use `run_once` on the > task. The best approach depends on personal taste and other decisions made > in writing the playbook and setting up your Ansible environment. > > -- 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/5442ecce-dd03-46fa-9903-08b4240617d6%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
On Monday, March 19, 2018 at 9:42:58 PM UTC-4, Josh Smift wrote: > > My use case involved roles. I had something like > > - hosts: web:app:db > roles: > - role: myrole > when: 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. > Disregarding the implementation details, `run_once: true` is effectively the same as adding `when: inventory_hostname == ansible_play_batch.0` to the task . As I said before, if that's not what you want you should instead write a conditional that expresses your actual intent. Here's one approach: - 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 Or you might opt for something like this, which is overly clever and requires a very recent version of Jinja: - 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 Or you might restructure the playbook so it only runs the role on blue hosts and doesn't need a separate conditional, and use `run_once` on the task. The best approach depends on personal taste and other decisions made in writing the playbook and setting up your Ansible environment. -- 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/ba1a1714-7c7b-4f2c-bcdf-e200b938e495%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
My use case involved roles. I had something like - hosts: web:app:db roles: - role: myrole when: 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. I don't have any hope that the Ansible team will ever address this; for whatever reason, this use case is relatively common among people who aren't on the Ansible team, and impossible to explain to the Ansible team in a way that anyone finds convincing. We haven't yet found a blocker that we couldn't work around in one ugly-ass way or another. On Monday, March 19, 2018 at 6:06:13 PM UTC-4, Alex Hunt wrote: > > 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=1changed=0unreachable=0failed= > 0 > host2 : ok=1changed=0unreachable=0failed= > 0 > host3 : ok=1changed=0unreachable=0failed= > 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=1changed=0unreachable=0failed= > 0 > host2 : ok=1changed=0unreachable=0failed= > 0 > host3 : ok=1changed=0unreachable=0failed= > 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
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
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=1changed=0unreachable=0failed=0 host2 : ok=1changed=0unreachable=0failed=0 host3 : ok=1changed=0unreachable=0failed=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=1changed=0unreachable=0failed=0 host2 : ok=1changed=0unreachable=0failed=0 host3 : ok=1changed=0unreachable=0failed=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
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
@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> 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
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
That'd be a perfectly fine solution, yes. I honestly don't even care if it always chooses to run on host1, as long as it doesn't only use host1 to determine if it should run at all. On Monday, March 19, 2018 at 2:23:53 PM UTC-7, Marcos Alano wrote: > > You mean the tasks should run in the first node available? If host1 is > unavailable the tasks should run in the host2, but if host2 is also > unavailable should run in host3 and so on? > I think is a valid concern. Even delegate_to could be set to a host > which may be is unavailable. The idea here is the tasks must run, > don't care which host, but must run anyway. May be an option? > > -- 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/e092102a-b613-412d-ac5f-61679d227bbc%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
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 Huntwrote: > 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 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
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
You mean the tasks should run in the first node available? If host1 is unavailable the tasks should run in the host2, but if host2 is also unavailable should run in host3 and so on? I think is a valid concern. Even delegate_to could be set to a host which may be is unavailable. The idea here is the tasks must run, don't care which host, but must run anyway. May be an option? On Mon, Mar 19, 2018 at 6:18 PM, Alex Huntwrote: > 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 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
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
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> 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
Re: [ansible-project] Re: Absurd run_once behavior, skipping entirely if first node fails a when test
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 Huntwrote: > 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 >>>