Skip to Content

selectattr in Ansible

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>')

 

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.