Pages

Thursday, February 11, 2016

Ansible Loops

Share it Please

Unitl now we have seen how we can use with , in and not operators to perform basic check but what if we need some thing like executing the task multiple times. Consider a case where you want to create multiple users or want to install multiple packages. In a normall programming language we can achieve these using loops. Anisble does provide a similar feature.

Standard Loops
The standard loops allow passing a list so that Ansible will run the task for all packages listed. Let's now go through an example playbook.

[root@vx111a loops]# cat loop1.yml
---
- hosts: cent
  tasks:
 
  - name: Create Multiple users
    shell: useradd {{ item }}
    with_items:
       - hai
       - bai

This simple playbook will run the useradd command taking each from the list defined udner the with_items construct. Each of the names is exposed as item, which is a default variable that Ansible creates. Ansible then assigns a package name to item, based on the iteration it is currently part of.

Once we run the above playbook,

[root@vx111a loops]# ansible-playbook loop1.yml

PLAY [cent] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.202.96]

TASK: [Create Multiple users] *************************************************
changed: [172.16.202.96] => (item=hai)
changed: [172.16.202.96] => (item=bai)

PLAY RECAP ********************************************************************
172.16.202.96              : ok=2    changed=1    unreachable=0    failed=0  
We can see that both users are created by using the loops in Ansible

Lets see another example of using the with_items construct with variable substitution.

[root@vx111a loops]# cat loop2.yml
---
- hosts: cent
  tasks:
 
  - name: Installing Packages
    yum: name={{item.name}} state={{item.value}}
    with_items:
       - {name: 'httpd', value: 'present'}

In the above playbook we have defined a task which installs packages that are defined in the with_items construct. We have defined the package name with name and value variable which are then accessed by the item element. The item does then have the name and value data which will substitute when needed. When we execute the playbook we see,

[root@vx111a loops]# ansible-playbook loop2.yml

PLAY [cent] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.202.96]

TASK: [Installing Packages] ***************************************************
changed: [172.16.202.96] => (item={'name': 'httpd', 'value': 'present'})

PLAY RECAP ********************************************************************
172.16.202.96              : ok=2    changed=1    unreachable=0    failed=0  

Nested Loops
Nested loops are usefull when we want to perform multiple operations on the same resource. For example consider a case where we want to set different permission on a file or directory thus defining them using sub elements.

[root@vx111a loops]# cat nested_loop.yml
---
- hosts: cent
  tasks:
 
  - name: Nested Loop / Change File Permissions
    shell: chmod -R {{ item[0] }} {{ item[1] }}
    with_nested:
       - [ '755' ]
       - [ '/tmp/hai' ]

The above playbook is a simple example of nested loops. In the above one we have defined a task which will change the permission on a file /tmp/hai with 755. The values are defined with with_nested construct and can be accessed as an array access (a[0]). When we execute the above playbook,

 [root@vx111a loops]# ansible-playbook nested_loop.yml

PLAY [cent] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.202.96]

TASK: [Nested Loop / Change File Permissions] *********************************
changed: [172.16.202.96] => (item=['755', '/tmp/hai'])

PLAY RECAP ********************************************************************
172.16.202.96              : ok=2    changed=1    unreachable=0    failed=0  

I will add a more sophisticated example for the nested loops

Sub Nested Loops
Till now we have seens loops with static data and what if we want give data dynamically. Consider an example of creating multiple users along with different comments. To deal with such cases, you can use a dictionary to loop over subelements. Using such loops, you can specify a set of comments per user. Consider a sample example as,

[root@vx111a loops]# cat subnested.yml
---
- hosts: cent
  vars:
    users:
     - name: jagadish
       comments:
         - 'Jagadish is Good'

     - name: srini
       comments:
         - 'Srini is Bad' 

  tasks:
   - name: User Creation
     shell: useradd -c "{{ item.1 }}" "{{ item.0.name }}"
     with_subelements:
         - users
         - comments

In the above playbook we defined a task which will create users along with user comments taken from 2 dictionaries users and comments. Both users and comments are defined in the vars element above. Both dictionaries are defined under the with_subelements construct making Ansible to get sub elements from users and comments for running the task. When we execute the playbook we can see,

[root@vx111a loops]# ansible-playbook subnested.yml

PLAY [cent] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.202.96]

TASK: [User Creation] *********************************************************
changed: [172.16.202.96] => (item=({'name': 'jagadish'}, 'Jagadish is Good'))
changed: [172.16.202.96] => (item=({'name': 'srini'}, 'Srini is Bad'))

PLAY RECAP ********************************************************************
172.16.202.96              : ok=2    changed=1    unreachable=0    failed=0  


That’s all about Loops. In the next article we will see more options provided by Ansible.

2 comments :

  1. can you please give more explanation as why comments are referred as item.1 and name as item.0.1? i need to use with_subelements with my ansible script but i cant get to understand the logic of it

    ReplyDelete