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