Extract Ansible Fields with selectattr
When working with Ansible, processing task results to extract meaningful information is often necessary. This article demonstrates how to filter attributes and extract a field from any Ansible variables / outputs.
Intro
Let's imagine we have a registered Ansible variable called output
, the structure might look like this:
ok: [localhost] => {
"output": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
<< truncated >>
"item": {
"key": "nova-api",
"value": null
},
"rc": 1,
},
{
<< truncated >>
"item": {
"key": "nova-scheduler",
"value": null
},
"rc": 0,
},
{
<< truncated >>
"item": {
"key": "nova-conductor",
"value": null
},
"rc": 0,
}
]
}
}
Our goal is to create a list of service names where rc is 1
. Simply enough we can:
- name: Set fact for services rc == 1
debug:
msg: "{{ output.results | selectattr('rc', 'equalto', 1) | map(attribute='item.key') | list }}"
# output.results : will get the list value of results
# selectattr('rc', 'equalto', 1) : for each element, selects one which has rc == 1
# beside `equalto` we have:
# match: use for regex
# contains: check if keyword is inside a list or a string
# map(attribute='item.key') : get the value in item.key of that element
# list: :form a new list of it
If we run the output will be like this:
ok: [localhost] => {
"msg": [
"nova-api"
]
}
In this example, only the nova-api
service had a return code of 1, indicating an issue with this service.
Multi-condition - list active
users in group
docker
Suppose we have a variable with this data structure:
users:
- name: Alice
active: true
groups: alice, docker
- name: Bob
active: false
groups: bob, sudo
- name: Charlie
active: true
groups: charlie
Now we want to filter not only active
status is true
but also the groups
name of the users contain docker
. All we need is add one more selectattr
:
- name: Get list of active users in docker group
debug:
msg: "{{ users | selectattr('active', 'equalto', true) | selectattr('groups', 'match', '.*docker.*') | map(attribute='name') | list }}"
The output will look like this:
ok: [localhost] => {
"msg": [
"Alice"
]
}