Table of Contents
selectattr in Ansible
selectattr is a filter plugin in Ansible that allows you to select a subset of elements from a list of dictionaries based on the value of a particular attribute.
Its syntax is as follows:
<list of dictionaries> | selectattr('<attribute>', '<operator>', '<value>')
Get Your Free Linux training!
Join our free Linux training and discover the power of open-source technology. Enhance your skills and boost your career! Learn Linux for Free!Key | Description |
---|---|
list_of_dictionaries | A list of dictionaries representing items to be filtered |
attribute | The name of the attribute to be checked in each item |
operator | The comparison operator to be used to check the attribute value. This can be one of the following: == (equals), != (not equals), < (less than), <= (less than or equal to), > (greater than), >= (greater than or equal to) |
value | The value to be compared against the attribute value |
This will return a new list of items that meet the filter criteria.
Here are examples of using selectattr in Ansible with their results:
- hosts: localhost vars: users: - name: john age: 25 - name: jane age: 30 - name: bob age: 20 tasks: - name: Get users over 25 debug: var: users | selectattr('age', '>=', 25) | map(attribute='name') | list
This is an Ansible playbook that targets the localhost host, which is the machine where the playbook is being executed.
The playbook defines a variable named users which is a list of dictionaries, with each dictionary containing name and age key-value pairs for a user.
The playbook includes a task named “Get users over 25”. This task uses the selectattr filter plugin to select only those users whose age is greater than or equal to 25. It then uses the map filter plugin to extract only the name attribute from each selected user. Finally, the list filter plugin converts the resulting sequence of names into a list.
The debug module is used to display the resulting list of names.
PLAY [localhost] ******************************************************************************************************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************************************************************************************************************* ok: [localhost] TASK [Get users over 25] *********************************************************************************************************************************************************************************************** ok: [localhost] => { "users | selectattr('age', '>=', 25) | map(attribute='name')": [ "john", "jane" ] }
We can get the same result with the following code.
- name: Get users over 25 vars: my_list: [] set_fact: my_list: "{{ my_list + [item.name] }}" when: "{{ item.age >= 25 }}" loop: "{{ users}}" - name: Display Updated List debug: var: my_list
Let’s see another example.
Here’s an example that uses a list for the selectattr filter to select all items in the list fruits whose color is “red”:
- name: Select red fruits vars: fruits: - name: apple color: red - name: banana color: yellow - name: cherry color: red debug: var: fruits | selectattr('color', '==', 'red') | list
In this example, the selectattr filter is applied to the fruits list. The filter selects all dictionaries in the list whose color attribute is equal to “red”. The resulting subset of dictionaries is then converted to a list and printed using the debug module.
The output of this playbook will be:
TASK [Select red fruits] ****************************************************** ok: [localhost] => { "fruits | selectattr('color', '==', 'red') | list": [ { "color": "red", "name": "apple" }, { "color": "red", "name": "cherry" } ] }
Let’s see another complex example.
- name: Apply different actions to subsets of servers hosts: all vars: servers: - name: webserver1 os: linux environment: production disk: - name: /dev/sda size: 100GB - name: /dev/sdb size: 500GB - name: dbserver1 os: windows environment: staging disks: - name: C: size: 500GB - name: D: size: 1TB - name: appserver1 os: linux environment: development disks: - name: /dev/sda size: 200GB - name: /dev/sdb size: 200GB tasks: - name: Install httpd on Linux servers in production yum: name: httpd loop: "{{ servers | selectattr('os', '==', 'linux') | selectattr('environment', '==', 'production') | list }}" - name: Install Notepad++ on Windows servers in staging win_package: name: Notepad++ loop: "{{ servers | selectattr('os', '==', 'windows') | selectattr('environment', '==', 'staging') | list }}" - name: Create mount points on Linux servers in development filesystem: fstype: xfs dev: "{{ item.disks | map(attribute='name') }}" loop: "{{ servers | selectattr('os', '==', 'linux') | selectattr('environment', '==', 'development') | list }}"
This example accomplishes the same task as the previous example, but with a slightly different format. The hosts, vars, and tasks sections are all included in the playbook.
In the vars section, the servers variable is defined as a list of dictionaries, with each dictionary representing a server and its properties.
The tasks section includes three tasks that apply different actions to subsets of the servers list based on the values of their os and environment attributes. Each task uses the when keyword to filter the servers list based on the os and environment attributes, and the loop keyword to iterate over the resulting list of servers.
In the first task, yum module is used to install the httpd package on Linux servers in production.
In the second task, win_package module is used to install the Notepad++ package on Windows servers in staging.
In the third task, filesystem module is used to create filesystem on the name of each disk in the disks list of each selected server.
The rewritten example uses the same selectattr filter plugin to filter a list of servers based on multiple attributes, and then apply different actions to each filtered subset of servers.
selectattr and dict in Ansible
As you can see that, selectattr filter works with a list of dictionaries. Does this work with dict object?
dict2items is another Jinja2 filter that can be used to convert a dictionary to a list of key-value pairs.
Here is an example of how to use selectattr in combination with dict2items in an Ansible playbook to select all items from a dictionary where the value of the “name” attribute is “John”:
- name: Select items with name "John" debug: var: my_dict | dict2items | selectattr('value.name', '==', 'John') | list vars: my_dict: john: name: John age: 25 jane: name: Jane age: 30
In the above example, my_dict is a dictionary, and dict2items is used to convert this dictionary to a list of key-value pairs. selectattr is then used to filter this list based on the value of the “name” attribute of the dictionary value. The | list filter at the end is used to convert the result to a list.
- name: Select items with name "John" ok: [localhost] => { "my_dict | dict2items | selectattr('value.name', '==', 'John') | list": [ { "key": "john", "value": { "age": 25, "name": "John" } } ] }
selectattr vs map filter in Ansible
The syntax of the “map” filter in Ansible is as follows:
{{ list | map('operation') }}
In this syntax, “list” is the list to be transformed, and “operation” is the operation to be performed on each element of the list.
Here are some examples of how to use the “map” filter with different operations:
Multiply each element in a list by 2:
{{ my_list | map('multiply', 2) | list }}
Add a prefix to each element in a list:
{{ my_list | map('regex_replace', '^(.*)$', 'prefix\\1') | list }}
Extract a specific field from a list of dictionaries:
{{ my_dict_list | map(attribute='my_key') | list }}
Note that the “map” filter returns a generator object, so you need to use the “list” filter to convert the generator to a list.
selectattr is used to select items from a collection based on a specific attribute, map is used to apply a function to every item in a collection and return a new collection.