In this article we will see the usage of Ansible Loops
Ansible Loops are used to execute the task multiple times. Consider a scenario where we want to create multiple users or want to install multiple packages. In any normal programming language, we achieve these using loops. Anisble also provide a similar feature.
Using Loops for multiple tasks
By passing a list, Ansible will run the task for all packages listed. This is called Standard Loops. For example
[root@server1 loops]# cat loop3.yml
---
- hosts: ubuntu
tasks:
- name: Create Multiple users
shell: useradd {{ item }}
with_items:
- testuser1
- testuser2
This example playbook will run the useradd command taking each from the list defined under 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@server1 loops]# ansible-playbook loop3.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [Create Multiple users] *************************************************
changed: [172.18.188.24] => (item=testuser1)
changed: [172.18.188.24] => (item=testuser2)
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed
From the above example, we can now see that both users are created by using loops
How to use with_items construct using Ansible:
Lets see one more example of using with_items construct with variable substitution.
[root@server1 loops]# cat loop6.yml
---
- hosts: ubuntu
tasks:
- name: Installing Packages
yum: name={{item.name}} state={{item.value}}
with_items:
- {name: 'httpd', value: 'present'}
Here in the above example 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.
Lets execute the playbook:
[root@server1 loops]# ansible-playbook loop6.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [Installing Packages] ***************************************************
changed: [172.18.188.24] => (item={'name': 'httpd', 'value': 'present'})
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed=0
Nested Loops using with_nested construct
Nested loops comes into picture where we want to perform multiple operations on the same resource. Take a simple example of usecase where we want to set different permission on a file or directory thus defining them using sub elements. As the title explains, Nested loop is a loop within a loop.
[root@server1 loops]# cat nested_loop1.yml
---
- hosts: ubuntu
tasks:
- name: Nested Loop / Change File Permissions
shell: chmod -R {{ item[0] }} {{ item[1] }}
with_nested:
- [ '700' ]
- [ '/tmp/test' ]
Okay, here is the simple example of nested loops. In the above usecase we have defined a task which will change the permission on a file /tmp/test with 700. The values are defined with with_nested construct and can be accessed as an array access (a[0]), while executing the above playbook.
[root@server1 loops]# ansible-playbook nested_loop1.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [Nested Loop / Change File Permissions] *********************************
changed: [172.18.188.24] => (item=['700', '/tmp/test'])
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed=0
Sub Nested Loops using Ansible with_subelements
Sub Nested Loops come into picture when we want to give data dynamically. uptill now, we have seen loops with static data but what if we want give data dynamically. Consider an example of creating multiple users along with different comments. To deal with such cases, we can use a dictionary to loop over sub-elements. Using such loops, we can specify a set of comments per user. Consider a sample example as,
[root@server1 loops]# cat subnested1.yml
---
- hosts: ubuntu
vars:
users:
- name: testuser
comments:
- 'For testing purpose'
- name: devuser
comments:
- 'For Dev purpose'
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. As we can see 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. Now lets execute this playbook:
[root@server1 loops]# ansible-playbook subnested1.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [User Creation] *********************************************************
changed: [172.18.188.24] => (item=({'name': 'testuser'}, 'For testing purpose'))
changed: [172.18.188.24] => (item=({'name': 'devuser'}, 'For Dev purpose'))
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed=0
That’s all about Ansible Loops with multiple tasks, with_items, with_nested and with_subelements.
Ansible Loops are used to execute the task multiple times. Consider a scenario where we want to create multiple users or want to install multiple packages. In any normal programming language, we achieve these using loops. Anisble also provide a similar feature.
Example of Ansible Loops with_items, with_nested and with_subelements example
Using Loops for multiple tasks
By passing a list, Ansible will run the task for all packages listed. This is called Standard Loops. For example[root@server1 loops]# cat loop3.yml
---
- hosts: ubuntu
tasks:
- name: Create Multiple users
shell: useradd {{ item }}
with_items:
- testuser1
- testuser2
This example playbook will run the useradd command taking each from the list defined under 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@server1 loops]# ansible-playbook loop3.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [Create Multiple users] *************************************************
changed: [172.18.188.24] => (item=testuser1)
changed: [172.18.188.24] => (item=testuser2)
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed
From the above example, we can now see that both users are created by using loops
How to use with_items construct using Ansible:
Lets see one more example of using with_items construct with variable substitution.
[root@server1 loops]# cat loop6.yml
---
- hosts: ubuntu
tasks:
- name: Installing Packages
yum: name={{item.name}} state={{item.value}}
with_items:
- {name: 'httpd', value: 'present'}
Here in the above example 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.
Lets execute the playbook:
[root@server1 loops]# ansible-playbook loop6.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [Installing Packages] ***************************************************
changed: [172.18.188.24] => (item={'name': 'httpd', 'value': 'present'})
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed=0
Nested Loops using with_nested construct
Nested loops comes into picture where we want to perform multiple operations on the same resource. Take a simple example of usecase where we want to set different permission on a file or directory thus defining them using sub elements. As the title explains, Nested loop is a loop within a loop.[root@server1 loops]# cat nested_loop1.yml
---
- hosts: ubuntu
tasks:
- name: Nested Loop / Change File Permissions
shell: chmod -R {{ item[0] }} {{ item[1] }}
with_nested:
- [ '700' ]
- [ '/tmp/test' ]
Okay, here is the simple example of nested loops. In the above usecase we have defined a task which will change the permission on a file /tmp/test with 700. The values are defined with with_nested construct and can be accessed as an array access (a[0]), while executing the above playbook.
[root@server1 loops]# ansible-playbook nested_loop1.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [Nested Loop / Change File Permissions] *********************************
changed: [172.18.188.24] => (item=['700', '/tmp/test'])
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed=0
Sub Nested Loops using Ansible with_subelements
Sub Nested Loops come into picture when we want to give data dynamically. uptill now, we have seen loops with static data but what if we want give data dynamically. Consider an example of creating multiple users along with different comments. To deal with such cases, we can use a dictionary to loop over sub-elements. Using such loops, we can specify a set of comments per user. Consider a sample example as,[root@server1 loops]# cat subnested1.yml
---
- hosts: ubuntu
vars:
users:
- name: testuser
comments:
- 'For testing purpose'
- name: devuser
comments:
- 'For Dev purpose'
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. As we can see 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. Now lets execute this playbook:
[root@server1 loops]# ansible-playbook subnested1.yml
PLAY [ubuntu] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [172.18.188.24]
TASK: [User Creation] *********************************************************
changed: [172.18.188.24] => (item=({'name': 'testuser'}, 'For testing purpose'))
changed: [172.18.188.24] => (item=({'name': 'devuser'}, 'For Dev purpose'))
PLAY RECAP ********************************************************************
172.18.188.24 : ok=2 changed=1 unreachable=0 failed=0
That’s all about Ansible Loops with multiple tasks, with_items, with_nested and with_subelements.
Nice stuff Thanks
ReplyDeleteWelcome!
Delete'users' is a list, not a dictionary. You can tell because each element has a hyphen in front of it.
ReplyDelete