If you have a complex JSON data structure or perhaps an array of rich data structures as the result of module output, you may want to extract this into a workable list or dictionary you can take action on.
For this article, I will emulate the resulting output from the ‘stat‘ module when it checks for file existence using ‘with_fileglob’. What is returned is an array of deeply nested values that simplified can be represented like below:
vars:
my_json_structure:
results:
- item: /tmp/a.txt
stat:
exists: true
- item: /tmp/b.txt
stat:
exists: false
- item: /tmp/c.txt
stat:
exists: true
Use ‘map’ to extract just the paths as an array.
- set_fact:
exist_list: "{{ ( my_json_structure.results | map(attribute='item') ) }}"
- debug: msg="{{ exist_list }}"
# output looks like
"msg": [
"/tmp/a.txt",
"/tmp/b.txt",
"/tmp/c.txt"
]
Use ‘dict’ and ‘zip’ to create a simple map where the key and value are the same.
- set_fact:
exist_map_simple: "{{ dict( exist_list | zip(exist_list) ) }}"
- debug: msg="{{ exist_map_simple }}"
# output looks like
"msg": {
"/tmp/a.txt": "/tmp/a.txt",
"/tmp/b.txt": "/tmp/b.txt",
"/tmp/c.txt": "/tmp/c.txt"
}
Use ‘json_query’ and ‘combine’ to create a map where they key is the path and the value is whether the file existed.
- set_fact:
exist_map: "{{ exist_map|default({}) | combine( {item.item : item.stat.exists} ) }}"
with_items: "{{ my_json_structure | json_query('results[*]') }}"
- debug: msg="{{ exist_map }}"
# output looks like
"msg": {
"/tmp/a.txt": true,
"/tmp/b.txt": false,
"/tmp/c.txt": true
}
The full playbook can be found on my github, datastructure-to-dict.yml
The use of json_query requires the ‘jmespath’ python module and ‘community.general’ Ansible Galaxy module.
# required pip module pip3 install jmespath # 'community.general' ansible-galaxy collection install community.general
Or via Ansible like below.
- name: ensure jmespath is installed to support json_query filter
become: yes
pip:
name: jmespath
- name: install community.general collection from ansible galaxy
command:
cmd: ansible-galaxy collection install community.general
REFERENCES
middlewareinventory, json_query combine and with_items technique
tailored.cloud, ansible filter and map
toroid.org, using combine to merge hashes
NOTES
Here is the ouput that ‘my_json_structure’ emulates
- stat:
path: "{{item}}"
register: complex_results
with_fileglob: "/tmp/*"
- debug: msg="{{complex_results}}"