In this article, we are going to see the various use cases of Ansible Map Function or Filter.
As Ansible Official documentation claims, All Jinja2 Filters can be used within Ansible.
One such function or filter is map
It helps us to filter and iterate complex datasets and a list of objects. Helps in filtering the attributes or in applying other available filters onto the list like replace
etc
In this article, we will cover various examples of Ansible Map and how to use them in real-time.
Let's go ahead.
What is Ansible Map Filter and How it works?
Ansible Map Filter does two things
- It applies a filter on a sequence of objects
- It looks up an attribute.
This is useful when dealing with lists of objects but you are really only interested in a certain value of it.
The basic usage of map is to look up an attribute. Let's cover it first
Imagine you have a list of users but you are only interested in a list of usernames:
for example consider the following employee data with lot of values like first name, lastname, address, mobile etc. But what I want is only their city
names: [ { "first": "Paul", "last": "Thompson", "mobile": "+1-234-31245543", "ctc": "100000", "address": { "city": "LasVegas", "country": "USA" } }, { "first": "Sarav", "last": "AK", "mobile": "+919876543210", "ctc": "200000", "address": { "city": "Chennai", "country": "India" } }]
So this is how, ansible map can help to list only the cities from the employee data.
{{ names | map(attribute='address') | map(attribute='city')}}
Or to get only the First Names
{{ names | map(attribute='first') | join(',') }}
Ansible Map Filter Examples - Looking up an Attribute
Here is the playbook with multiple Ansible Map filter examples with attribute
selection
Each task has self-explanatory comments for you to understand what exactly they are doing.
--- - name: filter test hosts: localhost vars: names: [ { "first": "Paul", "last": "Thompson", "mobile": "+1-234-31245543", "ctc": "100000", "address": { "city": "LasVegas", "country": "USA" } }, { "first": "Rod", "last": "Johnson", "mobile": "+1-584-31551209", "ctc": "300000", "address": { "city": "Boston", "country": "USA" } }, { "first": "Sarav", "last": "AK", "mobile": "+919876543210", "ctc": "200000", "address": { "city": "Chennai", "country": "India" } }] tasks: # Map Filter only selective attributes from list of objects [{},{}] - name: Select and Extract only the cities debug: msg="{{ names | map(attribute='address') | map(attribute='city')}}" # using attirubtes with list of objects [{},{}] - Selecting only mobile numbers - name: Select and Extract only mobile numbers debug: msg: "{{ names | map(attribute='mobile') }}" # Select Attributes Joined with Comma in Singleline ( By Default it returns a List) - debug: msg={{ names | map(attribute='first') | join(',') }} - debug: msg={{ names | map(attribute='last') | join(',') }} # Convert the lastname to uppercase - debug: msg={{ names | map(attribute='last') | map('upper') }} # Convert the CTC attriute to float value - debug: msg={{ names | map(attribute='ctc') | map('float') }} # Appending USD to each CTC value and print - debug: msg={{ names | map(attribute='ctc') | product(['USD']) | map('join',' ')}}
The Primary use of map
filter is with attribute selection from the sequence of elements or objects.
It helps us to select only the values we want from the huge dataset.
In the preceding playbook, you can see we have various examples of map attribute selection.
The last three examples have additional map another filter like upper
and float
etc.
The join
is used to format the output to single-line string which is otherwise a list. As map returns a list by default.
Here is the output of this playbook
PLAY [filter test] *************************************************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************************************************** ok: [localhost] TASK [Select and Extract only the cities] *************************************************************************************************************************************************** ok: [localhost] => { "msg": [ "LasVegas", "Boston", "Chennai" ] } TASK [Select only Attributes from List of Objects - Selecting only mobile numbers] *********************************************************************************************** ok: [localhost] => { "msg": [ "+1-234-31245543", "+1-584-31551209", "+919876543210" ] } TASK [debug] ********************************************************************************************************************************************************************* ok: [localhost] => { "msg": "Paul,Rod,Sarav" } TASK [debug] ********************************************************************************************************************************************************************* ok: [localhost] => { "msg": "Thompson,Johnson,AK" } TASK [debug] ********************************************************************************************************************************************************************* ok: [localhost] => { "msg": [ "THOMPSON", "JOHNSON", "AK" ] } TASK [debug] ********************************************************************************************************************************************************************* ok: [localhost] => { "msg": [ 100000.0, 300000.0, 200000.0 ] } TASK [debug] ********************************************************************************************************************************************************************* ok: [localhost] => { "msg": [ "100000 USD", "300000 USD", "200000 USD" ] }
Ansible Map Examples - using other Filters
The Second but major role of Ansible map
filter is to apply an another filter on a sequence of objects/lists.
Let's suppose you have a list of names you want to convert all of them to an upper
case strings.
For this example, you can consider the same dataset we have used in our first playbook.
In fact, we had one task to convert the last name to upper case like this
- debug: msg={{ names | map(attribute='last') | map('upper') }}
which resulted in the upper case converting last names like this.
TASK [debug] ********************************************************************************************************************************************************************* ok: [localhost] => { "msg": [ "THOMPSON", "JOHNSON", "AK" ] }
This is just a simple example on Applying other filters using map.
There are more advanced uses of this scenario.
Using Replace filter with Ansible Map
--- - name: Ansible Map with Other Filters hosts: localhost vars: servers: - "AppServer01" - "AppServer02" - "WebServer01" - "WebServer02" tasks: - name: Append the Domain Name to the end of the hosts debug: msg={{servers|map('lower')|map('regex_replace','^(.+)$','\\1.gritfy.io')}}
In the preceding Playbook, you can see we have list of hostnames assigned to the variable named servers
they are in Camel case which needs to be converted to lower
case and a valid domain name gritfy.io
has to be added at the end of each host.
Here comes the map to the help
{{servers|map('lower')|map('regex_replace','^(.+)$','\\1.gritfy.io')}}
we use two map
filters here, one is to convert them to lower
case and another one is to apply regex_replace
filter to replace each hostname with a proper domain suffix.
here is the execution output of this playbook look like
you can see that the hostnames are now in lower case with proper domain extensions.
Using Extract filter in Ansible Map - with List/Sequence
Extract filter within Ansible map used to map list of indices to list of values. the list of values can be a simple list or sequence or complex hashtable aka dictionary.
let us first see how an ansible map can be used to iterate a simple list
Here is the example playbook where we have a list of values (names) and we want to take certain names based on their positional index.
--- - name: filter test hosts: localhost tasks: - name: Extract Filter with Ansible Map - Select based on indices debug: msg={{ [0,2] | map('extract', ['Sarav','Hanu','Gopi']) | list }}
Now we are taking only the 0th
and 2nd
element from the list.
The result would be Sarav, Gopi
as they are on 0 and 2nd place based on the indices value
Using Extract filter in Ansible Map - with Dictionary/Hashtable
As we have already seen how Ansible map
filter can be used to select or filter an element using numeric index values.
Let us see an example of how it can be used with dictionary
also called as hash table
Unlike the simple list, the dictionary would contain string
index as most often called as key
Consider the following dataset of employees at Gritfy
{ "sarav":{ "mobile":"985643210","email":"[email protected]", "city":"Coimbatore" }, "hanu":{ "mobile":"7865432109","email":"[email protected]","city":"Hyderabad" }, "gopi":{ "mobile":"9812990123","email":"[email protected]","city":"Chennai" } }
Now I want to perform a few iterations and select different values from this dataset using extract
and map
Here is the playbook
--- - name: Ansible Map Extract filter hosts: localhost vars: employees: { "sarav":{ "mobile":"985643210","email":"[email protected]", "city":"Coimbatore" }, "hanu":{ "mobile":"7865432109","email":"[email protected]","city":"Hyderabad" }, "gopi":{ "mobile":"9812990123","email":"[email protected]","city":"Chennai" } } tasks: - name: Task1 - Select only Sarav's records from the Dictionary or Hash table debug: msg={{ ['sarav']| map('extract', employees ) }} - name: Task2 - Select Hanu's record and look for his email ID using Third argument debug: msg=" Hanu`s Email ID is {{ ['hanu']| map('extract', employees, 'email') | last}} " - name: Task3 - Select Gopi's record and look for his City using Third argument debug: msg=" Gopi is residing in {{ ['gopi']| map('extract', employees, 'city') | last }} "
we have three tasks here
- Task1task is to lookup only Sarav's records from the employees dataset
Task2
is to lookup Hanu's records first and then to look up his email ID using the third argumentTask3
is to lookup Gopi's records first and then to select his city using third argument
Here is the execution output of this playbook
Conclusion
Ansible Map is an advanced topic and it's a little hard to understand at the beginning
I personally have spent a long time understanding the different usage of Ansible Map and I know I have more to learn.
In a nutshell, Ansible Map helps us in two ways
- To look up an attribute
- To apply other filters on list and dictionaries
we have learnt various examples on both these scenarios and use cases.
A highlight here is the map with extract
filter. this is more helpful while parsing hostvars
and their elements.
If you have any comments, feedback or best practices please use the comments section or write to us.
Cheers
Sarav
Follow me on Linkedin My Profile Follow DevopsJunction onFacebook orTwitter For more practical videos and tutorials. Subscribe to our channel
Signup for Exclusive "Subscriber-only" Content