Using Loops and Items
Using Loops and Items
- Some modules enable you to provide a list that needs to be processed.
- Many modules don’t, and in these cases, it makes sense to use a loop mechanism to iterate over a list of items.
- Take, for instance, the yum module. While specifying the names of packages, you can use a list of packages.
- If, however, you want to do something similar for the service module, you find out that this is not possible.
- That is where loops come in.
Working with Loops
Install software packages using the yum module and then ensures that services installed from these packages are started using the service module:
---
- name: install and start services
hosts: ansible1
tasks:
- name: install packages
yum:
name:
- vsftpd
- httpd
- samba
state: latest
- name: start the services
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- vsftpd
- httpd
- smb-
A loop is defined at the same level as the service module.
-
The loop has a list of services in a list (array) statement
-
Items in the loop can be accessed by using the system internal variable item.
-
At no place in the playbook is there a definition of the variable item; the loop takes care of this.
-
When considering whether to use a loop, you should first investigate whether a module offers support for providing lists as values to the keys that are used.
-
If this is the case, just provide a list, as all items in the list can be considered in one run of the module.
-
If not, define the list using loop and provide "{{ item }}" as the value to the key.
-
When using loop, the module is activated again on each iteration.
Using Loops on Variables
- Although it’s possible to define a loop within a task, it’s not the most elegant way.
- To create a flexible environment where static code is separated from dynamic site-specific parameters, it’s a much better idea to define loops outside the static code, in variables.
- When you define loops within a variable, all the normal rules for working with variables apply: The variables can be defined in the play header, using an include file, or as host/hostgroup variables.
Include the loop from a variable:
---
- name: install and start services
hosts: ansible1
vars:
services:
- vsftpd
- httpd
- smb
tasks:
- name: install packages
yum:
name:
- vsftpd
- httpd
- samba
state: latest
- name: start the services
service:
name: "{{ item }}"
state: started
enabled: yes
loop: "{{ services }}"Using Loops on Multivalued Variables
An item can be a simple list, but it can also be presented as a multivalued variable, as long as the multivalued variable is presented as a list.
Use variables that are imported from the file vars/users-list:
users:
- username: linda
homedir: /home/linda
shell: /bin/bash
groups: wheel
- username: lisa
homedir: /home/lisa
shell: /bin/bash
groups: users
- username: anna
homedir: /home/anna
shell: /bin/bash
groups: usersUse the list in a playbook:
---
- name: create users using a loop from a list
hosts: ansible1
vars_files: vars/users-list
tasks:
- name: create users
user:
name: "{{ item.username }}"
state: present
groups: "{{ item.groups }}"
shell: "{{ item.shell }}"
loop: "{{ users }}"- Working with multivalued variables is possible, but the variables in that case must be presented as a list; using dictionaries is not supported.
- The only way to loop over dictionaries is to use the dict2items filter.
- Use of filters is not included in the RHCE topics and for that reason is not explained further here.
- You can look up “Iterating over a dictionary” in the Ansible documentation for more information.
Understanding with_items
- Since Ansible 2.5, using loop has been the command way to iterate over the values in a list.
- In earlier versions of Ansible, the with_keyword statement was used instead.
- In this approach, the keyword is replaced with the name of an Ansible look-up plug-in, but the rest of the syntax is very common.
- Will be deprecated in a future version of Ansible.
With_keyword Options Overview with_items
- Used like loop to iterate over values in a list with_file
- Used to iterate over a list of filenames on the control node with_sequence
- Used to generate a list of values based on a numeric sequence
Loop over a list using with_keyword:
---
- name: install and start services
hosts: ansible1
vars:
services:
- vsftpd
- httpd
- smb
tasks:
- name: install packages
yum:
name:
- vsftpd
- httpd
- samba
state: latest
- name: start the services
service:
name: "{{ item }}"
state: started
enabled: yes
with_items: "{{ services }}"Lab: Working with loop
1. Use your editor to define a variables file with the name vars/packages and the following contents:
packages:
- name: httpd
state: absent
- name: vsftpd
state: installed
- name: mysql-server
state: latest2. Use your editor to define a playbook with the name exercise71.yaml and create the play header:
- name: manage packages using a loop from a list
hosts: ansible1
vars_files: vars/packages
tasks:3. Continue the playbook by adding the yum task that will manage the packages, using the packages variable as defined in the vars/packages variable include file:
- name: manage packages using a loop from a list
hosts: ansible1
vars_files: vars/packages
tasks:
- name: install packages
yum:
name: "{{ item.name }}"
state: "{{ item.state }}"
loop: "{{ packages }}"4. Run the playbook using ansible-playbook exercise71.yaml, and observe the results. In the results you should see which packages it is trying to manage and in which state it is trying to get the packages.