How to Use Ansible 'map' filter
In this blog post, let's explore what a map filter is in Ansible and look at some practical use cases. The map filter is a handy tool in Ansible, making it easier to manipulate and transform data within your playbooks. We'll keep things straightforward and show you how this filter can be a real game-changer in automating tasks.
What is a Map Filter?
The map filter in Ansible is a powerful tool that lets you modify or transform each item in a list without the need for looping. It's like giving a single command that all items in the list follow, saving you time and making your playbooks cleaner and more efficient.
The map filter applies a specified function to each element in a list. This function could be anything from changing the data type (like converting numbers to strings), appending or modifying strings, to more complex operations. Think of it as telling each item in your list to go through a transformation process, and what comes out is a new list with these changes applied.
Ansible Map Filter - Simple Example
To demonstrate the map filter in action, let's look at a straightforward example where we convert a list of numbers into strings. This is particularly useful when you need to ensure that your data is in the correct format for further processing or output.
---
- name: Convert numbers to strings
hosts: localhost
gather_facts: no
vars:
numbers: [1, 2, 3]
tasks:
- name: Convert each number to a string
debug:
msg: "{{ numbers | map('string') }}"
- A list of numbers: 1, 2, and 3.
- A task that uses the map filter with the
string
function. This function converts each number in our list into its string representation.
When you run this playbook, it will display each number as a string, like '1', '2', and '3'. This is a simple yet practical use of the map filter, showcasing how you can easily transform data in your Ansible playbooks.
Another Example - Adding a Prefix to List Items
Here's another easy-to-understand example using the map filter. Let's say you have a list of words, and you want to add a prefix to each word.
---
- name: Add prefix to words
hosts: localhost
gather_facts: no
vars:
words: ['dog', 'cat', 'bird']
tasks:
- name: Add 'pet_' prefix to each word
debug:
msg: "{{ words | map('regex_replace', '^', 'pet_') }}"
- We define a list called
words
with the items 'dog', 'cat', and 'bird'. - In the task, we use the map filter with
regex_replace
. regex_replace
is a function that takes two main arguments:- A regular expression pattern.
- The string to replace the pattern with.
- In our case, the pattern is
'^'
, and the replacement string is'pet_'
.
- The caret (^) sign in regular expressions represents the start of a string.
- By using
'^'
as our pattern, we tellregex_replace
to look at the beginning of each string in our list. - The replacement,
'pet_'
, is then added at the starting point of each string.
When you run this playbook, regex_replace
acts on each item in the words
list, adding 'pet_' at the start. So 'dog' becomes 'pet_dog', 'cat' becomes 'pet_cat', and 'bird' becomes 'pet_bird'.
Yet Another Example - Changing Case of List Items
Let's look at another example of using the map filter in Ansible. This time, we'll change the case of each item in a list from lowercase to uppercase.
---
- name: Convert list items to uppercase and update the list
hosts: localhost
gather_facts: no
vars:
items: ['apple', 'banana', 'cherry']
tasks:
- name: Change each item to uppercase
set_fact:
items: "{{ items | map('upper') }}"
- name: Display the updated list
debug:
msg: "{{ items }}"
- We start with a list called
items
containing 'apple', 'banana', and 'cherry'. - Using
set_fact
to Update the List- The
set_fact
module is used to redefine theitems
variable. - We apply the
map
filter with theupper
function to each item in the list, which converts them to uppercase. - The result is then saved back into the
items
variable, effectively updating it.
- The
- Displaying the Updated List
- Finally, we use the
debug
module to display the updateditems
list. - Now,
items
will contain 'APPLE', 'BANANA', and 'CHERRY'.
- Finally, we use the
Extracting Specific JSON Data
For a more advanced use of the map filter, let's consider a scenario where we have a list of JSON objects and we want to extract a specific value from each object. This kind of task is common when dealing with structured data like JSON, often used in configurations or API responses.
---
- name: Extract specific data from JSON objects
hosts: localhost
gather_facts: no
vars:
json_data:
- { name: "Alice", role: "Developer" }
- { name: "Bob", role: "Designer" }
- { name: "Charlie", role: "Manager" }
tasks:
- name: Extract the role of each person
set_fact:
roles: "{{ json_data | map(attribute='role') }}"
- name: Display the extracted roles
debug:
msg: "{{ roles }}"
- We start with a variable
json_data
that contains a list of JSON objects. Each object represents a person with aname
androle
. - Extracting Specific Information
- The task uses
set_fact
to create a new listroles
. - We use the map filter with the
attribute='role'
parameter. This tells Ansible to look inside each JSON object and pull out the value associated with therole
key.
- The task uses
- The resulting list, containing only the roles, is then stored in the
roles
variable. - The
debug
module is used to print the list of roles, which will be ['Developer', 'Designer', 'Manager'].
Navigating Nested JSON Data in Ansible
In this final example, we'll tackle a more complex scenario where we have a nested JSON structure. We'll extract specific data from this nested JSON which is all the department names.
---
- name: Extract data from nested JSON
hosts: localhost
gather_facts: no
vars:
json_data:
[
{
"name": "Alice",
"details": {
"age": 30,
"department": "Engineering"
}
},
{
"name": "Bob",
"details": {
"age": 25,
"department": "Design"
}
},
{
"name": "Charlie",
"details": {
"age": 35,
"department": "Management"
}
}
]
tasks:
- name: Extract department of each person
set_fact:
departments: "{{ json_data | map(attribute='details') | map(attribute='department') }}"
- name: Display the extracted departments
debug:
msg: "{{ departments }}"
- We have a list
json_data
, each item containing aname
and a nesteddetails
object withage
anddepartment
. - Navigating the Nested Structure
- The first
map
filter uses theextract
function to navigate into thedetails
sub-object for each item in the list. - The second
map
filter then extracts thedepartment
attribute from these details.
- The first
- Storing and Displaying the Results
- The resulting list of departments is stored in the
departments
variable usingset_fact
. - Finally, we use
debug
to display thedepartments
list, which will contain ['Engineering', 'Design', 'Management'].
- The resulting list of departments is stored in the
Closing Up
To wrap up, the map filter in Ansible is a powerful yet straightforward tool for transforming lists. From appending prefixes to extracting data from nested JSON, this filter can handle a variety of tasks, making your playbooks cleaner and more efficient.