Skip to main content

Extract Ansible Fields with selectattr

· 3 min read
Sang, Nguyen Nhat
Infrastructure Engineer at VNG

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"
]
}