# Exit with\_items loop after first success?

**URL:** <https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026>\
**Category:** Ansible Project\
**Created:** [December 11, 2014, 3:41pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026 "2014-12-11T15:41:54Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Hugh\_Saunders](https://avatars.discourse-cdn.com/v4/letter/h/e68b1a/32.png) [@Hugh\_Saunders](https://forum.ansible.com/u/Hugh_Saunders)\
**Post date:** [December 11, 2014, 3:41pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/1 "2014-12-11T15:41:54Z")

</div>

Hi All,  
I’ve been asking on IRC, [twitter](https://twitter.com/wherenow_hugh/status/543048678588829696), and [github](https://github.com/ansible/ansible/issues/9782) about this and was asked to post to the ML as well so here goes 🙂

I would like to be able to exit a with\_items loop based on the result of the previous iteration. Think of it as a generalisation of with\_first\_found.

Two use cases:

1. I have a list of mirrors known to host file, I want to iterate over that list until I successfully retrieve the file, then stop iterating. No point in downloading the file multiple times.
2. I have a git ref (branch/tag) and a list of mirrors of that repo ([git.openstack.org](http://git.openstack.org), [github.com](http://github.com)), I want to resolve that ref to a SHA without cloning the repo. Run git ls-remote via shell passing in each remote url in turn until the ref is successfully resolved. No point in resolving it twice. Note that for this use case I do not want to clone the repo.  
I’m sure there are other situations where it would be useful to break out of a loop.

As explained in the issue, I can think of two ways of doing this, both would require modifications to ansible:

1. Add previous\_iteration variable for use in when clause, eg when: previous\_iteration | failed

2. Allow registered variable to be used within a loop, eg when: shell\_result[‘results’][-1].rc != 0

Thanks for any insight.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [December 11, 2014, 4:00pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/2 "2014-12-11T16:00:48Z")

</div>

"I would like to be able to exit a with\_items loop based on the result of the previous iteration. Think of it as a generalisation of with\_first\_found. "

Would like to step back to use cases first before we propose it be done with the “with\_” here, as that’s not how that part works.

Curious what kinds of files you are downloading - for instance, package managers like yum already do this, etc.

---

<div class="post-metadata">

**Author:** ![Hugh\_Saunders](https://avatars.discourse-cdn.com/v4/letter/h/e68b1a/32.png) [@Hugh\_Saunders](https://forum.ansible.com/u/Hugh_Saunders)\
**Post date:** [December 11, 2014, 4:09pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/3 "2014-12-11T16:09:20Z")

</div>

In this particular instance, I am downloading tars of git repos.

See also the second use case, its a bit of an edge case but shows that a  
general answer may be more useful than fixing a specific module. For  
example the file download case could be solved by modifying they get\_url  
module to take a list of sources, but that only solves one specific case.  
Add the functionality to core and it can be used with any module.

I'm also not sure a new with\_ is needed, maybe access to another variable  
within loop conditionals, or a new conditional such as break\_when?

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [December 11, 2014, 4:18pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/4 "2014-12-11T16:18:07Z")

</div>

if you are downloading tars of git repos from GitHub from lots of production servers, that seems to be a bit of a bad practice to me that assaults the mirror.

I would consider setting up a mirror of all that content on one server initially and then have your individual production nodes download off that box.

---

<div class="post-metadata">

**Author:** ![Hugh\_Saunders](https://avatars.discourse-cdn.com/v4/letter/h/e68b1a/32.png) [@Hugh\_Saunders](https://forum.ansible.com/u/Hugh_Saunders)\
**Post date:** [December 11, 2014, 4:33pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/5 "2014-12-11T16:33:35Z")

</div>

I haven't said that I had multiple servers downloading the same content.

Anyway... is there a way of breaking out of a loop or would patches be  
accepted to provide such a mechanism?

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [December 11, 2014, 4:41pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/6 "2014-12-11T16:41:08Z")

</div>

“Anyway… is there a way of breaking out of a loop or would patches be accepted to provide such a mechanism?”

Still want to understand your use case before we start talking implementation and language changes to find the best way to express the construct.

Ultimately Ansible isn’t a arbitrary scripting language, and I don’t want to make it one - but we do want to find the best possible way to express what you may want to express.

---

<div class="post-metadata">

**Author:** ![Vladislav\_Rastrusny](https://avatars.discourse-cdn.com/v4/letter/v/e274bd/32.png) [@Vladislav\_Rastrusny](https://forum.ansible.com/u/Vladislav_Rastrusny)\
**Post date:** [May 1, 2015, 7:01pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/7 "2015-05-01T19:01:46Z")

</div>

My use case is the following:

I have a list of ntpd servers and I want to run ntpdate against the list. But since one sucessful sync is enough, I would like to break the cycle after the first successfully executed sync. How would I do that currently? As I understand do-until loop will not work in this case, right?

---

<div class="post-metadata">

**Author:** ![Pete\_Ahearn](https://avatars.discourse-cdn.com/v4/letter/p/3bc359/32.png) [@Pete\_Ahearn](https://forum.ansible.com/u/Pete_Ahearn)\
**Post date:** [August 4, 2015, 2:59pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/8 "2015-08-04T14:59:33Z")

</div>

Bump. Is there really no way to do this currently?

---

<div class="post-metadata">

**Author:** ![Chuck\_Carlino](https://avatars.discourse-cdn.com/v4/letter/c/b9bd4f/32.png) [@Chuck\_Carlino](https://forum.ansible.com/u/Chuck_Carlino)\
**Post date:** [August 5, 2015, 2:20pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/9 "2015-08-05T14:20:54Z")

</div>

[https://groups.google.com/forum/#!topic/ansible-project/z9iD55-4pPs](https://groups.google.com/forum/#!topic/ansible-project/z9iD55-4pPs) is a similar case.

---

<div class="post-metadata">

**Author:** ![Jonathan1](https://avatars.discourse-cdn.com/v4/letter/j/f14d63/32.png) [@Jonathan1](https://forum.ansible.com/u/Jonathan1)\
**Post date:** [January 4, 2016, 11:34pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/10 "2016-01-04T23:34:28Z")

</div>

I’d also be super interested in some way to do this. To me this is a very sane use case, and the Ansible appears to allow the use of until: along with with\_items:, but appears to just ignore the until statement. If this is not supported ideally there would be some sort of syntax issue.

Would the Ansible team be willing to take a pull request to allow until evaluations in the context of a with\_items loop?

For more clarity here is an example play. Lets say we want to send a update to a single web server out of a set, and you want to stop after the first successful call. Maybe the calls are not idempotent, maybe you don’t want to add extra load…

here is a test play with until and with\_items, and until apparently not being evaluated.

- hosts: localhost

gather\_facts: no

tasks:

- name: test

# action: debug msg=“cluster host {{ item }}”

# action: uri timeout=2 url={{ item }}

action: shell curl --max-time 1 {{ item }} \>/dev/null

with\_items: “{{input\_hosts|shuffle}}”

register: put\_status

until: put\_status.rc == 0

here is the output executing with an input array of URLs, you can see the first URL works yet it keeps going

ansible-playbook -vv -i ../hosts --sudo test2.yml --extra-vars=‘{“input\_hosts”: [“[https://www.google.com](https://www.google.com)”, “[https://www.snargoblarg.com](https://www.snargoblarg.com)”]}’

PLAY [localhost] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

TASK: [test] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

\<127.0.0.1\> REMOTE\_MODULE command curl --max-time 1 [https://www.google.com](https://www.google.com) \>/dev/null #USE\_SHELL

changed: [127.0.0.1] =\> (item=[https://www.google.com](https://www.google.com)) =\> {“attempts”: 0, “changed”: true, “cmd”: “curl --max-time 1 [https://www.google.com](https://www.google.com) \>/dev/null”, “delta”: “0:00:00.555617”, “end”: “2016-01-04 23:32:04.951993”, “item”: “[https://www.google.com](https://www.google.com)”, “rc”: 0, “start”: “2016-01-04 23:32:04.396376”, “stderr”: " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:–:-- --:–:-- --:–:-- 0\r100 18908 0 18908 0 0 35322 0 --:–:-- --:–:-- --:–:-- 36152", “stdout”: “”, “warnings”: [“Consider using get\_url module rather than running curl”]}

\<127.0.0.1\> REMOTE\_MODULE command curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null #USE\_SHELL

\<127.0.0.1\> REMOTE\_MODULE command curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null #USE\_SHELL

Result from run 1 is: {‘cmd’: ‘curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null’, ‘end’: ‘2016-01-04 23:32:11.354140’, ‘stdout’: u’‘, ‘changed’: True, ‘attempts’: 1, ‘start’: ‘2016-01-04 23:32:11.188499’, ‘delta’: ‘0:00:00.165641’, ‘stderr’: ’ % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:–:-- --:–:-- --:–:-- 0curl: (6) Could not resolve host: [www.snargoblarg.com](http://www.snargoblarg.com)’, ‘rc’: 6, ‘warnings’: [‘Consider using get\_url module rather than running curl’]}

\<127.0.0.1\> REMOTE\_MODULE command curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null #USE\_SHELL

Result from run 2 is: {‘cmd’: ‘curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null’, ‘end’: ‘2016-01-04 23:32:16.868708’, ‘stdout’: u’‘, ‘changed’: True, ‘attempts’: 2, ‘start’: ‘2016-01-04 23:32:16.703207’, ‘delta’: ‘0:00:00.165501’, ‘stderr’: ’ % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:–:-- --:–:-- --:–:-- 0curl: (6) Could not resolve host: [www.snargoblarg.com](http://www.snargoblarg.com)’, ‘rc’: 6, ‘warnings’: [‘Consider using get\_url module rather than running curl’]}

\<127.0.0.1\> REMOTE\_MODULE command curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null #USE\_SHELL

Result from run 3 is: {‘cmd’: ‘curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null’, ‘end’: ‘2016-01-04 23:32:22.253845’, ‘stdout’: u’‘, ‘changed’: True, ‘attempts’: 3, ‘start’: ‘2016-01-04 23:32:22.231865’, ‘delta’: ‘0:00:00.021980’, ‘stderr’: ’ % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:–:-- --:–:-- --:–:-- 0curl: (6) Could not resolve host: [www.snargoblarg.com](http://www.snargoblarg.com)’, ‘rc’: 6, ‘warnings’: [‘Consider using get\_url module rather than running curl’]}

failed: [127.0.0.1] =\> (item=[https://www.snargoblarg.com](https://www.snargoblarg.com)) =\> {“attempts”: 3, “changed”: true, “cmd”: “curl --max-time 1 [https://www.snargoblarg.com](https://www.snargoblarg.com) \>/dev/null”, “delta”: “0:00:00.021980”, “end”: “2016-01-04 23:32:22.253845”, “failed”: true, “item”: “[https://www.snargoblarg.com](https://www.snargoblarg.com)”, “rc”: 6, “start”: “2016-01-04 23:32:22.231865”, “warnings”: [“Consider using get\_url module rather than running curl”]}

stderr: % Total % Received % Xferd Average Speed Time Time Time Current

Dload Upload Total Spent Left Speed

0 0 0 0 0 0 0 0 --:–:-- --:–:-- --:–:-- 0curl: (6) Could not resolve host: [www.snargoblarg.com](http://www.snargoblarg.com)

msg: Task failed as maximum retries was encountered

FATAL: all hosts have already failed – aborting

---

<div class="post-metadata">

**Author:** ![Dayton\_Jones](https://avatars.discourse-cdn.com/v4/letter/d/22d042/32.png) [@Dayton\_Jones](https://forum.ansible.com/u/Dayton_Jones)\
**Post date:** [October 31, 2016, 3:03pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/11 "2016-10-31T15:03:06Z")

</div>

I have need of this feature too, would be quite beneficial to some tasks I need.

---

<div class="post-metadata">

**Author:** ![Ivan\_Ogai](https://avatars.discourse-cdn.com/v4/letter/i/3e96dc/32.png) [@Ivan\_Ogai](https://forum.ansible.com/u/Ivan_Ogai)\
**Post date:** [March 7, 2017, 9:47am UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/12 "2017-03-07T09:47:00Z")

</div>

I also need this feature.

---

<div class="post-metadata">

**Author:** ![Davide\_Scrimieri](https://avatars.discourse-cdn.com/v4/letter/d/8491ac/32.png) [@Davide\_Scrimieri](https://forum.ansible.com/u/Davide_Scrimieri)\
**Post date:** [November 20, 2019, 9:36am UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/13 "2019-11-20T09:36:15Z")

</div>

This feature would be really helpful. Are there any news on this?

---

<div class="post-metadata">

**Author:** ![Nikolay\_Dimov](https://avatars.discourse-cdn.com/v4/letter/n/7ab992/32.png) [@Nikolay\_Dimov](https://forum.ansible.com/u/Nikolay_Dimov)\
**Post date:** [May 16, 2020, 12:12pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/14 "2020-05-16T12:12:15Z")

</div>

This a very important feature to have, and not only on success but on any condition (e.g. on failure). Currently, it just keeps running until it finishes the loop which is not always a desired outcome.

---

<div class="post-metadata">

**Author:** ![Nikolay\_Dimov](https://avatars.discourse-cdn.com/v4/letter/n/7ab992/32.png) [@Nikolay\_Dimov](https://forum.ansible.com/u/Nikolay_Dimov)\
**Post date:** [May 17, 2020, 9:19am UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/15 "2020-05-17T09:19:26Z")

</div>

I ended up using the following hack:

- name: shell test  
shell: “{{ item }}”  
with\_items:
- /bin/true
- /bin/false
- /bin/true  
when: r\_shell.rc|default(0)==0  
register: r\_shell

This exits on first failure. To exit on success you can use:

when: r\_shell.rc|default(1)!=0

This is obviously a hack, and it is strange that register looks different in the task and after the task ends, but it does the job.  
It would have been great if the register had the final form and the item results were appended as tasks were executed so we can check the results there with filters.

---

<div class="post-metadata">

**Author:** ![racke](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/racke/32/4767_2.png) [@racke](https://forum.ansible.com/u/racke)\
**Post date:** [May 18, 2020, 1:50pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/16 "2020-05-18T13:50:06Z")

</div>

> This a very important feature to have, and not only on success but on any condition (e.g. on failure). Currently, it  
> just keeps running until it finishes the loop which is not always a desired outcome.

Hello Nikolay,

I never needed this very important feature, so what is your actual use case?

Regards  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Racke

---

<div class="post-metadata">

**Author:** ![vbotka](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/vbotka/32/359_2.png) [@vbotka](https://forum.ansible.com/u/vbotka)\
**Post date:** [May 18, 2020, 4:16pm UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/17 "2020-05-18T16:16:24Z")

</div>

> I ended up using the following hack:
> 
> - name: shell test  
> shell: "{{ item }}"  
> with\_items:  
> - /bin/true  
> - /bin/false  
> - /bin/true  
> when: r\_shell.rc|default(0)==0  
> register: r\_shell
> 
> This exits on first failure.

No. It does not. This does not solve the problem that the loop "just keeps  
running until it finishes the loop". The loop will run further after the  
failure and the remaining items will be skipped because of the condition.

Then, because of the failure, the playbook will be terminated.

> To exit on success you can use:
> 
> when: r\_shell.rc|default(1)!=0

The result of this condition is completely different. The first successful  
iteration makes all the rest to be skipped. But, because there was no  
failure, the playbook will continue. Right?

HTH,

&nbsp;&nbsp;-vlado

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [May 21, 2020, 3:31am UTC](https://forum.ansible.com/t/exit-with-items-loop-after-first-success/17026/18 "2020-05-21T03:31:12Z")

</div>

It is something i would like to add as part of a full looping revamp  
[https://github.com/ansible/proposals/issues/140](https://github.com/ansible/proposals/issues/140)
