Ansible Loops
Overview
Loops in Ansible allow you to perform tasks repeatedly with different values. They're essential for efficient automation and reducing playbook complexity.
Basic Loops
Standard Loop
# Simple list loop
- name: Create multiple users
ansible.builtin.user:
name: "{{ item }}"
state: present
loop:
- john
- jane
- bob
# Dictionary loop
- name: Configure user details
ansible.builtin.user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
shell: "{{ item.shell }}"
loop:
- { name: 'john', groups: 'admin', shell: '/bin/bash' }
- { name: 'jane', groups: 'dev', shell: '/bin/zsh' }
Loop with Index
# Using loop_control
- name: Create numbered files
ansible.builtin.copy:
content: "File content"
dest: "/tmp/file{{ ansible_loop.index }}.txt"
loop:
- alpha
- beta
- gamma
loop_control:
index_var: ansible_loop.index
Advanced Loop Techniques
Nested Loops
# Using nested items
- name: Configure virtual hosts
ansible.builtin.template:
src: vhost.conf.j2
dest: "/etc/nginx/sites-available/{{ item.0.domain }}_{{ item.1 }}.conf"
loop: "{{ domains | product(environments) | list }}"
vars:
domains:
- { domain: 'example.com', root: '/var/www/example' }
- { domain: 'test.com', root: '/var/www/test' }
environments:
- dev
- staging
- prod
Loop Controls
# Loop with label
- name: Install packages with status
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis-server
loop_control:
label: "Installing {{ item }}"
pause: 2 # 2 second pause between iterations
# Loop with index
- name: Create sequential files
ansible.builtin.copy:
content: "Content for file {{ ansible_loop.index }}"
dest: "/tmp/file{{ ansible_loop.index }}.txt"
loop:
- first
- second
- third
loop_control:
index_var: ansible_loop.index
Conditional Loops
# Loop with conditionals
- name: Start services if enabled
ansible.builtin.service:
name: "{{ item.name }}"
state: started
loop: "{{ services }}"
when: item.enabled | bool
vars:
services:
- { name: 'nginx', enabled: true }
- { name: 'mysql', enabled: false }
- { name: 'redis', enabled: true }
Loop with Filters
Filtering Lists
# Select specific items
- name: Process active users
debug:
msg: "Processing user {{ item }}"
loop: "{{ users | selectattr('active', 'eq', true) | list }}"
vars:
users:
- { name: 'john', active: true }
- { name: 'jane', active: false }
- { name: 'bob', active: true }
Transform and Loop
# Map and loop
- name: Display uppercase names
debug:
msg: "Name: {{ item }}"
loop: "{{ users | map(attribute='name') | map('upper') | list }}"
Error Handling in Loops
Continue on Error
# Ignore failures
- name: Install packages with failure handling
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- package1
- package2
ignore_errors: yes
Retry Logic
# Retry failed operations
- name: Attempt operations with retry
ansible.builtin.command: "{{ item }}"
loop:
- "service1 start"
- "service2 start"
register: result
until: result.rc == 0
retries: 3
delay: 5
Best Practices
Performance Optimization
# Use with_items for large lists
- name: Process large lists efficiently
debug:
msg: "Processing {{ item }}"
with_items: "{{ large_list }}"
# Parallel execution
- name: Run tasks in parallel
command: "long_running_task.sh"
async: 3600
poll: 0
loop: "{{ tasks }}"
register: async_results
- name: Wait for completion
async_status:
jid: "{{ async_result_item.ansible_job_id }}"
loop: "{{ async_results.results }}"
loop_control:
loop_var: "async_result_item"
register: async_poll_results
until: async_poll_results.finished
retries: 30
Loop Documentation
# Document complex loops
- name: Complex loop operation
vars:
loop_description: |
This loop:
1. Filters active items
2. Transforms data
3. Processes results
debug:
msg: "{{ loop_description }}"
loop: "{{ complex_data | selectattr('active', 'eq', true) | map(attribute='name') | list }}"