Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Ansible loop over a sequence of tasks?

How can an Ansible playbook loop over a sequence of tasks? I wish to implement a polling loop that executes a task sequence until the task is successful. When it fails, an exception handler will attempt to fix the condition and then the loop will repeat the task sequence.

Consider the following imaginary example:

- action:
    - block:
        - debug: msg='i execute normally'
        - command: /bin/foo
      rescue:
        - debug: msg='I caught an error'
        - command: /bin/fixfoo
      always:
        - debug: msg="this always executes"
  register: result
  until: result
  retries: 5
  delay: 10
like image 265
Derek Mahar Avatar asked Nov 13 '15 20:11

Derek Mahar


2 Answers

As of Ansible 2.5, loop is recommended over with_items. Furthermore, since you don't want to assume your sub-task won't have any loops, you can use a more descriptive name than "item". Here's an example which uses a loop within a loop, slightly truncated but still working if you define the appropriate config:

# terminate-instances-main.yml:
---
- hosts: local
  connection: local
  vars:
    regions:
      - ap-southeast-1
      - us-west-1
  tasks:
    - include_tasks: "terminate-instance-tasks.yml"
      loop: "{{ regions }}"
      loop_control:
        loop_var: region

# terminate-instance-tasks.yml:
---
- name: Gather EC2 facts
  ec2_instance_facts:
    region: "{{ region }}"
    filters:
      "tag:temporary": "true"
    aws_access_key: "{{ aws_access_key }}"
    aws_secret_key: "{{ aws_secret_key }}"
  register: ec2

- name: Terminate Temp EC2 Instance(s)
  ec2:
    instance_ids: '{{ item.instance_id }}'
    state: absent
    region: "{{ region }}"
    aws_access_key: "{{ aws_access_key }}"
    aws_secret_key: "{{ aws_secret_key }}"
  loop: "{{ ec2.instances }}"
like image 127
piojo Avatar answered Sep 28 '22 17:09

piojo


In Ansible 1.x this simply can't be done. It's just not designed that way.

Ansible 2.0 supports looping over include files, so you could put all your tasks in one file then do something like this:

- include: test.yml
  with_items:
    - 1
    - 2
    - 3

However I don't believe any of the other constructs you mention (register, until, retries, delay, etc) will work with this. While some of those could theoretically be applied to all tasks in an include file others like register and until are explicitly bound to individual tasks. It makes no sense to have multiple tasks try to register the same output variable.

like image 43
Bruce P Avatar answered Sep 28 '22 16:09

Bruce P