Ansible selectattr filter is to select matching objects from the dictionary by applying a test across all the objects in a dictionary/sequence.
Ansible selectattr filter is basically an inherited version of Jinja selectattr
filter. As Ansible Quotes in their documentation besides the built-in Ansible filters, all JINJA2 filters can be used in Ansible playbooks.
Be informed that, Only Ansible 2.7+ with Jinja2 supports the selectattr
for those who are not there yet, you can use ansible json_query. Here is our article that can help
To see what version of ansible that you are using and what version of JINJA does it support you can use the ansible – version
command
⇒ ansible – version | grep "jinja" jinja version = 3.0.2
In the preceding output you can see that my ansible supports Jinja 3.0.2
Having said that. Let's go ahead in to our today topic.
List of Objects / Dictionary we are going to use
Consider the following dataset
[ { "name": "Shanmugam", "gender": "male", "mobile": "9875643210", "dose1completed" : "yes", "dose2completed" : "yes", "age": "25", "city": "pudukottai", "state": "Tamilnadu" }, { "name": "Lakshmi", "gender": "female", "mobile": "9875623410", "dose1completed" : "yes", "dose2completed" : "no", "age": "32", "city": "Chennai", "state": "Tamilnadu" }, { "name": "Albert", "gender": "male", "mobile": "9875634510", "dose1completed" : "yes", "dose2completed" : "yes", "age": "65", "city": "Coimbatore", "state": "Tamilnadu" }, { "name": "Abdul", "gender": "male", "mobile": "9875632341", "dose1completed" : "no", "dose2completed" : "no", "age": "45", "city": "Hosur", "state": "Tamilnadu" } ]
It is a list of objects/dictionary with few fields about the vaccination status and personal details of individuals.
On a side note, If you have not vaccinated yet. Please do it. Vaccination is our only hope now.
Back to the subject.
this is a sample dataset I have taken with 4 objects/persons but you can add more if you would like to.
From this dataset, Let us create some statistics of
- individuals with in age group of 18 to 45
- individuals with age group 45 and above
- who are yet to put their second dose of vaccination
- people who are not vaccinated at all
- who are living in red zone ( based on the active cases)
- who are living in green zone
- People who are living in cities
you can create N number of stats based on this dataset. but how it is related to our ansible selectattr filter.
we are going to use ansible selectattr
function to create these assertions/stats.
Ansible Playbook with selectattr filter
Here is a playbook with ansible selectattr filter which creates these various stats for us.
we have used some nice formatting in the playbook using debug
module and msg
The complete playbook runs on localhost
and has only one task with some variable declaration and printing on the same place.
--- - name: selectattr example - Vaccination Report hosts: localhost tasks: - name: debug vars: - userdata: [ { "name": "Shanmugam", "gender": "male", "mobile": "9875643210", "dose1completed" : "yes", "dose2completed" : "yes", "age": "25", "city": "pudukottai", "state": "Tamilnadu" }, { "name": "Lakshmi", "gender": "female", "mobile": "9875623410", "dose1completed" : "yes", "dose2completed" : "no", "age": "32", "city": "Chennai", "state": "Tamilnadu" }, { "name": "Albert", "gender": "male", "mobile": "9875634510", "dose1completed" : "yes", "dose2completed" : "yes", "age": "65", "city": "Coimbatore", "state": "Tamilnadu" }, { "name": "Abdul", "gender": "male", "mobile": "9875632341", "dose1completed" : "no", "dose2completed" : "no", "age": "45", "city": "Hosur", "state": "Tamilnadu" }, ] - agegroup18to45: "{{ userdata | selectattr('age','>=','18') | selectattr('age','<=','45' ) }}" - agegroup45above: "{{ userdata | selectattr('age','gt','45') }}" - dose2pending: "{{ userdata | selectattr('dose2completed','==','no') | selectattr('dose1completed','eq','yes') }}" - nonvaccinated: "{{ userdata | selectattr('dose1completed','equalto','no')}}" - redzoneresidents: "{{ userdata | selectattr('city','in','Coimbatore,Chennai')}}" - greenzoneresidents: "{{ userdata | rejectattr('city','in','Coimbatore,Chennai')}}" - cityresidents: "{{ userdata | selectattr('city','in','Coimbatore,Chennai')}}" debug: msg: - "-------------------" - "Age Group 18 to 45" - "-------------------" - "{{agegroup18to45}}" - "-------------------" - "-------------------" - "Age Group 45 Above" - "-------------------" - "{{agegroup45above}}" - "-------------------" - "-------------------" - "Second dose pending" - "-------------------" - "{{dose2pending}}" - "-------------------" - "Yet to Vaccinate" - "-------------------" - "{{nonvaccinated}}" - "-------------------" - "Containment Zone" - "-------------------" - "{{redzoneresidents}}" - "-------------------" - "Non Containment Zone" - "-------------------" - "{{greenzoneresidents}}" - "-------------------" - "Urbanites" - "-------------------" - "{{greenzoneresidents}}"
Since the variables are created in the sequential order, we are able to do our all our data processing right in the vars
section itself
except the userdata
variable all other variables are used to create our stats reports.
- agegroup18to45: "{{ userdata | selectattr('age','>=','18') | selectattr('age','<=','45' ) }}" - agegroup45above: "{{ userdata | selectattr('age','gt','45') }}" - dose2pending: "{{ userdata | selectattr('dose2completed','==','no') | selectattr('dose1completed','eq','yes') }}" - nonvaccinated: "{{ userdata | selectattr('dose1completed','equalto','no')}}" - redzoneresidents: "{{ userdata | selectattr('city','in','Coimbatore,Chennai')}}" - greenzoneresidents: "{{ userdata | rejectattr('city','in','Coimbatore,Chennai')}}" - cityresidents: "{{ userdata | selectattr('city','in','Coimbatore,Chennai')}}"
In every single variable declaration we are using selectattr
except the second last greenzoneresidents
there we are using rejectattr
just to give you a perspective
The Syntax of Ansible selectattr filter consists of three elements
- attribute in an object or operand
- comparison operator or test
- value to compare with
selectattr('variable/attribute in an object','comparison operator / tests','Value to compare with')
Read more about comparison operators in Jinja2 here like ==, !=, >, <
etc
Read more about tests in Jinja2 here like eq, ne, ge, gt, in, not
etc
In most cases the test and comparison operator do the same operation i.e eq
and ==
We are printing all the variables we have created dynamically just now within the vars
section with msg
block with nice formatting
Execute and Validate the output
Here is the execution output of the playbook for your reference.
Ansible|⇒ ansible-playbook selectattr-ex1.yml [WARNING]: No inventory was parsed, only implicit localhost is available [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [selectattr example] *************************************************************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************************************************************** ok: [localhost] TASK [debug] **************************************************************************************************************************************************************** ok: [localhost] => { "msg": [ "-------------------", "Age Group 18 to 45", "-------------------", [ { "age": "25", "city": "pudukottai", "dose1completed": "yes", "dose2completed": "yes", "gender": "male", "mobile": "9875643210", "name": "Shanmugam", "state": "Tamilnadu" }, { "age": "32", "city": "Chennai", "dose1completed": "yes", "dose2completed": "no", "gender": "female", "mobile": "9875623410", "name": "Lakshmi", "state": "Tamilnadu" }, { "age": "45", "city": "Hosur", "dose1completed": "no", "dose2completed": "no", "gender": "male", "mobile": "9875632341", "name": "Abdul", "state": "Tamilnadu" } ], "-------------------", "-------------------", "Age Group 45 Above", "-------------------", [ { "age": "65", "city": "Coimbatore", "dose1completed": "yes", "dose2completed": "yes", "gender": "male", "mobile": "9875634510", "name": "Albert", "state": "Tamilnadu" } ], "-------------------", "-------------------", "Second dose pending", "-------------------", [ { "age": "32", "city": "Chennai", "dose1completed": "yes", "dose2completed": "no", "gender": "female", "mobile": "9875623410", "name": "Lakshmi", "state": "Tamilnadu" } ], "-------------------", "Yet to Vaccinate", "-------------------", [ { "age": "45", "city": "Hosur", "dose1completed": "no", "dose2completed": "no", "gender": "male", "mobile": "9875632341", "name": "Abdul", "state": "Tamilnadu" } ], "-------------------", "Containment Zone", "-------------------", [ { "age": "32", "city": "Chennai", "dose1completed": "yes", "dose2completed": "no", "gender": "female", "mobile": "9875623410", "name": "Lakshmi", "state": "Tamilnadu" }, { "age": "65", "city": "Coimbatore", "dose1completed": "yes", "dose2completed": "yes", "gender": "male", "mobile": "9875634510", "name": "Albert", "state": "Tamilnadu" } ], "-------------------", "Non Containment Zone", "-------------------", [ { "age": "25", "city": "pudukottai", "dose1completed": "yes", "dose2completed": "yes", "gender": "male", "mobile": "9875643210", "name": "Shanmugam", "state": "Tamilnadu" }, { "age": "45", "city": "Hosur", "dose1completed": "no", "dose2completed": "no", "gender": "male", "mobile": "9875632341", "name": "Abdul", "state": "Tamilnadu" } ], "-------------------", "Urbanites", "-------------------", [ { "age": "25", "city": "pudukottai", "dose1completed": "yes", "dose2completed": "yes", "gender": "male", "mobile": "9875643210", "name": "Shanmugam", "state": "Tamilnadu" }, { "age": "45", "city": "Hosur", "dose1completed": "no", "dose2completed": "no", "gender": "male", "mobile": "9875632341", "name": "Abdul", "state": "Tamilnadu" } ] ] } PLAY RECAP ****************************************************************************************************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Realtime Example for Ansible selectattr - AWS EFS report
The playbook we have designed earlier in this article, is designed to cover all the usage of selectattr
however we thought of giving one more realtime example.
This playbook we have written a while ago to create AWS EFS report can serve as a one best real time example of selectattr
along with map
filters. Do take a look.
Difference between Ansible Select and Selectattr (Additional)
Though this is not in the objective of this article, I wanted to go little deeper to give some clarity on this topic
As I have mentioned in the beginning, All Jinja2 filters can be used in Ansible.
Having said that, there are two filters named select
and selectattr
in jinja2 so does in ansible.
So how they are different and where to use them. ?
Both these filters helps to filter an object from a sequence or list
One difference is that
select
Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.
selectattr
Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.
the difference here is selectattr runs a test on a specific attribute of the object while the select does it on the object itself.
The elements inside the list/sequence would have attributes only when they are dictionary
or proper object.
numbers: ['10','20','30']
the preceding list numbers
does not ( cannot) have any attributes so here you can use select
to run any test on the elements directly
the following JINJA2 snippet would print numbers greater than or equal to 20
which is directly applied on the elements of list
"{{ numbers | select('ge','20') }}"
So the verdict here is that
select
is to filter elements/objects of a simple list[x,y,z,1,2,3]
selectattr
is to filter elements/objects of list with nested objects[{},{},{}]
Here is the quick playbook for you to understand this practically
--- - name: filter test hosts: localhost vars: numbers: ['10','20','30'] names: [ { "first": "Sarav", "last": "AK", "mobile": "+919876543210", "ctc": "200000", "address": { "city": "Chennai", "country": "India" } }] tasks: - name: Ansible Select vs SelectAttr debug: msg: - "===========================" - "With SelectAttr - Filter using Attribute name of Object" - "===========================" - '{{ names | selectattr("first", "eq", "Sarav")}}' - "" - "===========================" - "With Select - We are filtering using regex as the elements of list are treated as a normal string not as object/dict" - "===========================" - '{{ names | select("match", ".+first.+:.+Sarav.+")}}' - "" - "===========================" - "With Select - Rule is directly applied on the Object" - "===========================" - "{{ numbers | select('ge','20') }}"
Output of this playbook is given below as an image
Conclusion
Hope this article helps you understand the Ansible selectattr filter and how to use it along with few other subtopics like
- How to Pretty print or do formatting in Ansible Debug
- How to do inversive action with
rejectattr
- How to use Jinja2 Comparison operators and tests in Ansible filters
- What is Ansible Select and Selectattr and difference between them
- Realtime example of Ansible Selectattr with EFS
If you have any more questions or feed back please free to update on the comments section
If you are looking for any Professional Support in Devops/SRE/Cloud Consider Gritfy
Cheers
Sarav AK
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