Ansible: Stop a loop when the conditional is true the first time

Viewed 963

Is there a way to stop a loop when the conditional is true the first time? In the example below, I want the value of student to be betty. But it currently will be set to brad. If I add "and student is undefined" to the when condition then it will work, but is there a better way? Thanks!

---
- hosts: localhost

  vars:
   marks:
    - name: bob
      grade: a
    - name: betty
      grade: c
    - name: jenny
      grade: d
    - name: brad
      grade: c

  tasks:
  - set_fact:
       student: '{{ item.name }}'
    loop: '{{ marks }}'
    when: item.grade == 'c'

  - debug:
      var: student
1 Answers

Q: " ... when the conditional is true the first time ..."

Filters instead of a loop

There are more options. For example, select the first item that meets the condition

  - set_fact:
       student: "{{ marks|
                    selectattr('grade', 'eq', 'c')|
                    map(attribute='name')|
                    first }}"

json_query gives the same result

  - set_fact:
       student: "{{ marks|
                    json_query('[?grade==`c`].name')|
                    first }}"

Loop

Use a loop (iterate a list) when suitable filters are missing or if the data are created in the loop. In this case, it's possible to skip the rest of the loop. For example, let's simulate the use-case of iterating a command until it succeeds. The task below iterates the list [1,2,3,4,5] and the command test the item is greater than 3. The loop will skip the rest of the list after the condition is met

    - command: '[ "{{ item }}" -gt "3" ]'
      loop: "{{ range(1, 5 + 1)|list }}"
      register: result
      ignore_errors: true
      when: not condition
      vars:
        condition: "{{ (result|default({'rc': 1})).rc == 0 }}"
    - debug:
        msg: "{{ result.results|
                 json_query('[?rc==`0`].item')|
                 first }}"

gives (selected relevant part)

failed: [localhost] (item=3) => changed=true
  ...
  item: 3
  msg: non-zero return code
  rc: 1
  ...
changed: [localhost] => (item=4)
skipping: [localhost] => (item=5) 
...ignoring

TASK [debug] ****
ok: [localhost] => 
  msg: '4'

See details in the thread Looping a task until it succeeds.

Related