In the course of executing tasks in Ansible playbook, you might come across some tasks that are repetitive in nature. These are tasks that require you to create multiple plays, something which can be quite tedious. As with any programming language, loops in Ansible provide an easier way of executing repetitive tasks using fewer lines of code in a playbook.
When creating loops, Ansible provides these two directives: loop and with_* keyword.
The loop keyword was recently added to Ansible 2.5. The loop keyword is usually used to create simple and standard loops that iterate through several items.
The with_* keyword is used with a number of lookup plugins when iterating through values. Lookup plugins enable Ansible to access information from external sources such as external datastores, filesystems, etc. The with_* lookup is still very much in use and has not yet been deprecated.
Let’s now have a look at how you can implement Loops in Ansible.
Iterating over simple loops
Consider a Playbook that adds a new user on the target system using the user module as shown:
---
- hosts: ubuntu_webserver
tasks:
- name: Create new user john
user:
name: john
state: present
This looks okay. But what if we have multiple users to add to the target system? How would we go about that? One way would be to duplicate the tasks as shown in the example below where we are adding 3 users.
---
- hosts: ubuntu_webserver
tasks:
- name: Create new user john
user:
name: john
state: present
- name: Create new user mike
user:
name: mike
state: present
- name: Create new user andrew
user:
name: andrew
state: present
As you can seem this calls for a lot of duplication and repetition.
To make things easier, the same playbook can be written using the loop directive. The loop directive executes the same task multiple times. It stores the value of each item in a variable called item.So, instead of specifying the names of the users to be added, simply specify a variable called item enclosed between double curly braces as shown.
name: ‘’
Therefore, each of the items within the loop will be referenced by the variable.
As you can see, our playbook is now much more organized with unnecessary duplication/repetition.
$ vi create_users.yaml
---
- hosts: ubuntu_webserver
tasks:
- name: Create new users
user:
name: ''
state: present
loop:
- john
- mike
- andrew
Also, you can use the with_items directive instead of the loop directive. Both will yield the same result.
---
- hosts: ubuntu_webserver
become: yes
tasks:
- name: Create new users
user:
name: ''
state: present
with_items:
- john
- mike
- andrew
You can now run the playbook to create the users using the ansible-playbook command as shown below:
$ ansible-playbook -i inventory.txt create_users.yaml
Iterating over a list of Dictionaries
In the first example, we looked at a simple standard loop where the array was a list of string values representing users to be added to the remote target.
But what if we need to add the uid to the loop such that each item now has two values: the username and uid. How would you pass 2 values in an array?
In this scenario, you will have to pass an array of dictionaries, each with 2 key-value pairs as shown. The keys would be the name and uid whilst the values will be the username and the ID of each user.
Under the ‘tasks‘ section, you can no longer define the variable item as before. Since we have 2 values, this will translate into two variables: item.name & item.uid.
The complete playbook is shown below:
$ vi create_users.yaml
---
- hosts: ubuntu_webserver
become: yes
tasks:
- name: Create new users
user:
name: ''
uid: ''
state: present
loop:
- name: john
uid: 1020
- name: mike
uid: 1030
- name: andrew
uid: 1040
The array of dictionaries can also be represented in a JSON format.
loop:
- { name: john , uid: 1020 }
- { name: mike , uid: 1030 }
- { name: andrew , uid: 1040}
When executed, you will get the following output:
$ ansible-playbook -i inventory.txt create_users.yaml
Ansible Loops with indexes
Occasionally, you may want to keep track of the index values within your array of items. For this, use the ‘with indexed_items‘ lookup. The index value begins from 0 whilst The loop index begins from item.0 and the value from item.1
Consider the playbook below:
$ vi indexes.yaml
---
- hosts: ubuntu_webserver
tasks:
- name: Indexes with Ansible loop
debug:
msg: "The car at is "
with_indexed_items:
- "Nissan"
- "Mercedes"
- "Toyota"
- "Mazda"
- "BMW"
When executed, the playbook displays the index value of each item in the array list.
$ ansible-playbook -i inventory.txt indexes.yaml
Conditionals in Ansible Loops
In Ansible loops you can use the conditional statement when to control the looping based on the nature of variables or system facts. Consider the playbook below where we have a list of packages that need to be installed.
We have specified an array called ‘packages‘ that contains a list of packages that need to be installed. Each of the items on the array contains the name of the package to be installed and the property called ‘required‘ which is set to ‘True‘ for 2 packages and ‘False‘ for one package.
$ vi install-packages.yaml
---
- name: Install software
become: yes
hosts: all
vars:
packages:
- name: neofetch
required: True
- name: cpu-checker
required: True
- name: screenfetch
required: False
tasks:
- name: Install "" on Ubuntu
apt:
name: ""
state: present
when:
- item.required == True
- ansible_facts['distribution'] =="Ubuntu"
loop: ""
The ‘when‘ conditional statement seeks to install the software packages with the property ‘required‘ set to ‘True’ on target systems which are Ubuntu distros. Below is the output of the playbook when executed.
The verbose output clearly shows the packages that are being installed and the one which is ignored based on the conditional statement.
And this brings us to the end of this topic. We do hope that you have a decent understanding of Loops in Ansible playbooks. Feel free to reach out for any clarification.
from Linuxtechi https://ift.tt/35Qjsac









0 Comments