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.
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
ReplyDeleteWell said .Keep updating Devops Online Training
ReplyDelete