Search code examples
ansible

How to break a loop in Ansible when some condition matched?


I need a method to stop looping in Ansible like break in for statement in C++ or Bash. For example, I need to the last value before the loop scan to 0.

The default/main.yml

---
os_vars:
  - 8
  - 10
  - 15
  - 6
  - 0
  - 7
  - 25

The tasks/main.yml

- name: Debug variables
  ansible.builtin.set_fact:
    a: "{{ item }}"
  loop: "{{ os_vars }}"
  when: item > 0

And the output

TASK [test_role : Debug variables] *********************************************
ok: [localhost] => (item=8)
ok: [localhost] => (item=10)
ok: [localhost] => (item=15)
ok: [localhost] => (item=6)
skipping: [localhost] => (item=0)
ok: [localhost] => (item=7)
ok: [localhost] => (item=25)

I know I can set other bool variable to control the looping didn't assign a with following items, but I also need to save time to increase performance of this playbook, as sometime this looping body might be a huge array and we don't need to check the following items when some condition matched ...

Please share your comments. Thanks in advance.


Solution

  • Q: "I know I can set other bool variable to control the looping didn't assign a with following items"

    Right, as there are

    Similar Q&A

    and many more ...

    Q: "I need a method to stop looping in Ansible like break in for statement in C++ or Bash."

    Such is not available. You can't break out the loop, you can only implement to skip.

    This is because

    • Things to know about programming using Ansible

      Ansible is not a language: If Ansible isn't a programming language, then what is it? Ansible is a tool written in Python, and it uses the declarative markup language YAML to describe the Desired State of devices and configuration. ... You declare aspects you want to be configured on a target device, such as that a file or directory exists, a package is installed, a service is running, and so on.

    • The Zen of Ansible

      Think declaratively: Ansible is a Desired State Engine by design. If you’re trying to “write code” in your plays and roles, you’re setting yourself up for failure. Our YAML-based playbooks were never meant to be for programming.

    Q: "I also need to save time to increase performance of this playbook, as sometime this looping body might be a huge array and we don't need to check the following items when some condition matched."

    If you like or need to implement such behavior you may need to write something by yourself. See in example Should you develop a module? and Developing modules.

    An other approach can be to do some pre-processing on the data structure, os_vars list to have after that only

    os_vars:
      - 8
      - 10
      - 15
      - 6
    

    to provide for the loop. Then, no break or if then else construct would be necessary at all.

    Further Reading


    Based on the given comments and as I understood the Use Case a possible solution approach without BREAK, when: or any IF, THEN, ELSE construct.

    A minimal example playbook

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        os_vars:
          - 8
          - 10
          - 15
          - 6
          - 0
          - 7
          - 25
    
      tasks:
    
      - name: Loop up to idx
        debug:
          msg: "{{ item }}"
        loop: "{{ os_vars[:idx | int] }}"
        loop_control:
          extended: true
          label: "{{ ansible_loop.index }}"
        # Get index of zero (0) value
        vars:
          idx: "{{ os_vars.index(os_vars | min) }}"
    

    will result into an output of

    TASK [Loop up to idx] ********
    ok: [localhost] => (item=1) =>
      msg: 8
    ok: [localhost] => (item=2) =>
      msg: 10
    ok: [localhost] => (item=3) =>
      msg: 15
    ok: [localhost] => (item=4) =>
      msg: 6
    

    Based On