Ansible Extract JSON Data: Parse & Query JSON (Complete Guide)
By Luca Berton · Published 2024-01-01 · Category: installation
How to extract and parse JSON data in Ansible. Use json_query, from_json, selectattr, and JMESPath to query APIs and command output with examples.
Introduction
JSON (JavaScript Object Notation) is a common data format for APIs and configuration management. In modern IT operations, querying JSON data is essential for automation. Ansible, a powerful tool for automating IT tasks, offers a robust json_query filter that simplifies querying and extracting data. In this article, we will demonstrate how to use Ansible to extract a folder value from a JSON structure based on a specific name.
---
See also: Ansible JSON Query: Search & Extract Data with json_query
1. Why Automate JSON Queries?
JSON queries can become repetitive and error-prone when done manually. Automating this process with Ansible provides several advantages: • Consistency: Avoid manual errors by standardizing queries. • Efficiency: Save time with automated data extraction. • Flexibility: Adapt quickly to changes in JSON structures.
---
2. Example Use Case: Extracting Folder Value by Name
Let’s consider a scenario where you need to extract the folder value for a specific name from JSON data.
The JSON Data
Here’s an example JSON structure:[
{ "name": "foo", "folder": "foo_folder" },
{ "name": "bar", "folder": "bar_folder" }
]
The Goal
Retrieve thefolder value for name: foo using Ansible.
---
See also: Mastering Ansible-Creator: Simplify Your Ansible Collection Development
3. The Playbook
Below is the Ansible playbook for this task:
---
- name: Extract folder value based on name
hosts: localhost
gather_facts: no
vars:
# Sample JSON data
json_data:
- { "name": "foo", "folder": "foo_folder" }
- { "name": "bar", "folder": "bar_folder" }
# Query to extract the folder value for the given name
query: "[?name=='{{ lookup_name }}'].folder | [0]"
# Variable to hold the name for which the folder value is queried
lookup_name: foo
tasks:
- name: Extract folder value for name={{ lookup_name }}
set_fact:
folder_value: "{{ json_data | json_query(query) }}"
- name: Display extracted folder value
debug:
msg: "The folder value for '{{ lookup_name }}' is '{{ folder_value }}'"
---
4. Understanding the Playbook
JSON Data
Thejson_data variable represents the data to be queried. It’s a list of dictionaries with name and folder fields.
Query Syntax
Thejson_query filter uses JMESPath syntax for querying:
• ?name=='{{ lookup_name }}': Filters objects with name matching lookup_name.
• .folder: Retrieves the folder field from the matched objects.
• [0]: Selects the first match.
set_fact
The set_fact module dynamically sets the folder_value variable with the query result.
Debugging
Thedebug module displays the extracted folder value, verifying the playbook's success.
---
See also: Ansible Debugger: Interactive Debug & Troubleshoot Playbooks
5. Running the Playbook
Save the playbook as extract_folder.yml and execute it with:
ansible-playbook extract_folder.yml
Example Output
TASK [Display extracted folder value] ******************************************
ok: [localhost] => {
"msg": "The folder value for 'foo' is 'foo_folder'"
}
---
6. Extending the Playbook
• Dynamic Input: Replacelookup_name with an external variable for flexibility:
ansible-playbook extract_folder.yml -e "lookup_name=bar"
• Handling Multiple Results: To retrieve all matching values, remove [0] from the query:
query: "[?name=='{{ lookup_name }}'].folder"
---
Conclusion
Ansible’s json_query filter simplifies working with JSON data, enabling administrators to extract critical values with precision. By automating this process, you can streamline workflows, minimize errors, and handle complex JSON structures effortlessly.
Integrate this playbook into your automation toolkit to unlock new efficiencies in JSON data management!
json_query (JMESPath)
- vars:
servers:
- { name: web1, env: prod, cpu: 4 }
- { name: web2, env: prod, cpu: 2 }
- { name: dev1, env: dev, cpu: 1 }
debug:
msg:
- "Names: {{ servers | json_query('[].name') }}"
# ['web1', 'web2', 'dev1']
- "Prod: {{ servers | json_query('[?env==`prod`].name') }}"
# ['web1', 'web2']
- "Total CPU: {{ servers | json_query('sum([].cpu)') }}"
# 7
Install JMESPath
pip install jmespath
# Or in requirements:
# jmespath>=1.0.0
Parse API Response
- name: Get data from API
ansible.builtin.uri:
url: https://api.example.com/servers
return_content: true
register: api
- name: Extract server names
set_fact:
server_names: "{{ api.json | json_query('data[].hostname') }}"
active_servers: "{{ api.json | json_query('data[?status==`active`]') }}"
from_json Filter
- name: Parse JSON string
set_fact:
data: "{{ json_string | from_json }}"
- debug:
msg: "{{ data.servers[0].name }}"
Jinja2 Expressions (No JMESPath)
- vars:
users:
- { name: alice, role: admin }
- { name: bob, role: user }
- { name: charlie, role: admin }
debug:
msg:
# selectattr filter
- "Admins: {{ users | selectattr('role', 'eq', 'admin') | map(attribute='name') | list }}"
# ['alice', 'charlie']
# Direct access
- "First: {{ users[0].name }}"
# alice
# map attribute
- "All names: {{ users | map(attribute='name') | list }}"
# ['alice', 'bob', 'charlie']
Nested JSON
- vars:
response:
data:
clusters:
- name: prod
nodes: [node1, node2, node3]
- name: dev
nodes: [dev1]
debug:
msg:
- "{{ response | json_query('data.clusters[?name==`prod`].nodes[]') }}"
# ['node1', 'node2', 'node3']
- "{{ response.data.clusters | selectattr('name', 'eq', 'prod') | map(attribute='nodes') | first }}"
# ['node1', 'node2', 'node3']
Extract from Command Output
- name: Get Docker info
command: docker inspect mycontainer
register: docker_info
- set_fact:
container_ip: "{{ (docker_info.stdout | from_json)[0].NetworkSettings.IPAddress }}"
json_query vs Jinja2 Filters
| Approach | Best For |
|----------|----------|
| json_query | Complex queries, nested filtering |
| selectattr/map | Simple attribute filtering |
| from_json + direct | Known structure, simple access |
| regex_search | Pattern matching in strings |
FAQ
"JMESPath requires jmespath library" error?
Install it: pip install jmespath
How do I handle missing keys?
# Default value if key missing
msg: "{{ data.optional_key | default('N/A') }}"
# json_query returns empty list if no match
servers: "{{ data | json_query('[?missing==`true`]') | default([]) }}"
Can I use json_query in when conditions?
when: (servers | json_query('[?env==`prod`]') | length) > 0
Parse JSON from Command Output
- command: cat /etc/myapp/config.json
register: config_raw
- set_fact:
config: "{{ config_raw.stdout | from_json }}"
- debug:
msg: "DB host: {{ config.database.host }}"
Parse JSON from API
- uri:
url: https://api.example.com/servers
return_content: true
register: api_response
- debug:
msg: "{{ api_response.json }}"
Access Nested Fields
- vars:
data:
server:
hostname: web1
network:
ip: 10.0.1.10
gateway: 10.0.1.1
disks:
- name: sda
size: 100G
- name: sdb
size: 500G
tasks:
- debug: msg="{{ data.server.network.ip }}"
- debug: msg="{{ data.server.disks[0].name }}"
- debug: msg="{{ data.server.disks | map(attribute='size') | list }}"
json_query Filter (JMESPath)
- vars:
users:
- { name: alice, role: admin, active: true }
- { name: bob, role: user, active: true }
- { name: charlie, role: admin, active: false }
tasks:
# Get all admin names
- debug:
msg: "{{ users | json_query('[?role==`admin`].name') }}"
# ["alice", "charlie"]
# Get active users
- debug:
msg: "{{ users | json_query('[?active].name') }}"
# ["alice", "bob"]
selectattr (Alternative to json_query)
# Filter without JMESPath
- debug:
msg: "{{ users | selectattr('role', 'eq', 'admin') | map(attribute='name') | list }}"
Extract from API List
- uri:
url: https://api.example.com/instances
return_content: true
register: instances
- set_fact:
running: "{{ instances.json | json_query('[?state==`running`]') }}"
instance_ids: "{{ instances.json | json_query('[*].id') }}"
Read JSON File with Lookup
- vars:
config: "{{ lookup('file', 'config.json') | from_json }}"
debug:
msg: "Port: {{ config.port }}"
Transform JSON
# JSON to YAML
- copy:
content: "{{ data | to_nice_yaml }}"
dest: /etc/myapp/config.yml
# JSON to pretty JSON
- copy:
content: "{{ data | to_nice_json }}"
dest: /etc/myapp/config.json
# Flatten nested structure
- set_fact:
flat: "{{ nested_list | flatten }}"
Practical: Parse Docker Inspect
- command: docker inspect mycontainer
register: docker_info
- set_fact:
container: "{{ docker_info.stdout | from_json | first }}"
- debug:
msg: |
IP: {{ container.NetworkSettings.IPAddress }}
Status: {{ container.State.Status }}
Image: {{ container.Config.Image }}
FAQ
json_query vs selectattr?
json_query uses JMESPath (powerful, complex queries). selectattr is simpler Jinja2 (filter by attribute). Use selectattr for simple filters, json_query for complex nested queries.
"json_query requires jmespath" error?
Install it: pip install jmespath on the Ansible controller.
How to handle missing keys?
msg: "{{ data.optional_key | default('not set') }}"
Related Articles
• Ansible become methods compared • creates and removes args with Ansible commandCategory: installation