Filtering Lists Based on Conditions in Ansible

Hello everyone! In this blog post, we're going to look at how to filter lists in Ansible. Filtering is a key skill when working with lists, as it lets you sort through and find exactly what you need. We'll cover how to use Ansible's built-in filters like select and selectattr for both basic and more detailed filtering tasks. Whether you're just starting out with Ansible or have been using it for a while, I hope this post will help you learn how to effectively filter lists in your playbooks. Let's get into it!

Filtering Based on Element Values

Let's start with a basic example of filtering a list based on specific element values in Ansible. In this case, we'll use Ansible's select filter to extract items from a list that match a certain pattern. Suppose we have a list of fruits and we want to filter out those that start with the letter 'd'. Here's how we can do it.

---
- name: Filter list based on values
  hosts: localhost
  gather_facts: False

  vars:
    fruit_list: ["apple", "banana", "cherry", "date", "elderberry"]
    
  tasks:
    - name: Filter fruits starting with 'd'
      set_fact:
        filtered_list: "{{ fruit_list | select('match', '^d.*') }}"
    - name: Print the filtered list
      debug:
        msg: "{{ filtered_list }}"
  • We have a list named fruit_list that contains various fruit names.
  • The task uses the select filter with the match test to find fruits that start with the letter 'd'. The pattern ^d.* is a regular expression that matches any string starting with 'd'.
  • Finally, we use the debug module to print the filtered_list. The output will only include fruits from our original list that start with 'd', such as "date".

In the provided example, we use a regular expression (regex) pattern to filter the list. The regex pattern '^d.*' is used to match strings that start with the letter 'd'. Let's break down what this pattern means.

  • ^ - This is the beginning of line anchor in regex. It ensures that the pattern matches only at the start of the string. In other words, it looks for matches at the beginning of each item in the list.
  • d - This is simply the lowercase letter 'd'. The regex will look for strings that start with this character.
  • .* - This part of the pattern is made up of two symbols. The . (dot) represents any character (except newline characters), and the * means "zero or more of the preceding element". So .* together means "any sequence of characters", regardless of length.

When combined, ^d.* will match any string that starts with 'd', followed by any number of any characters. This is why in our example, a fruit name like "date" gets selected, as it starts with 'd' and is followed by other characters.

Filtering Based on Dictionary Properties

For our next example, let's explore how to filter a list of dictionaries in Ansible. This is particularly useful when dealing with more complex data structures. We'll use the selectattr filter to filter elements based on their properties.

Imagine we have a list of user dictionaries, and we want to filter out users with a specific role, say 'admin'. Here's how this can be accomplished.

---
- name: Filter list based on dictionary properties
  hosts: localhost
  gather_facts: False

  vars:
    users: 
      - { name: "Alice", role: "admin" }
      - { name: "Bob", role: "user" }
      - { name: "Charlie", role: "admin" }
      
  tasks:
    - name: Filter for admin users
      set_fact:
        admins: "{{ users | selectattr('role', 'equalto', 'admin') }}"
    - name: Print the list of admins
      debug:
        msg: "{{ admins }}"
  • We define a variable users as a list of dictionaries. Each dictionary represents a user with name and role keys.
  • The task Filter for admin users utilizes the selectattr filter. This filter is applied to each dictionary in the users list, checking whether the role key is equal to 'admin'.
  • The equalto test within selectattr is used to perform the comparison.
  • Finally, the debug module is used to print the list of admin users. The output will include dictionaries for Alice and Charlie, as they both have the role 'admin'.

This method of filtering is very effective for lists of dictionaries, allowing you to select elements based on specific criteria within each dictionary.

Filtering Lists Using Conditional Expressions

Another interesting way to filter lists in Ansible is by using conditional expressions. This approach is particularly useful when you need to filter based on more complex logic or multiple conditions. Let's see an example where we filter a list of numbers, keeping only the ones that are even and greater than 10.

Suppose we have a list of numbers and we want to filter out those that are both even and greater than 10. Here's an Ansible task to achieve this.

---
- name: Filter list using conditional expressions
  hosts: localhost
  gather_facts: False
  vars:
    number_list: [2, 5, 12, 17, 20, 25, 30]
  tasks:
    - name: Filter numbers greater than 10 and even
      set_fact:
        filtered_numbers: "{{ number_list | select('even') | map('int') | select('>', 10) }}"
    - name: Print the filtered numbers
      debug:
        msg: "{{ filtered_numbers }}"
  • The select('even') filter is first used to filter out the even numbers from number_list.
  • The map('int') is then applied to ensure each element is treated as an integer.
  • The select('>', 10) is used to filter numbers that are greater than 10. This works because select can be used with comparison operators for integers.

Closing Up

And there you have it! We've explored various ways to filter lists in Ansible, from basic value matching to more complex conditional filtering. These methods are essential tools in your Ansible toolkit, helping you manage and automate tasks more effectively. I hope you find these examples useful in your own Ansible projects. Happy automating!