AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

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 the folder 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

The json_data variable represents the data to be queried. It’s a list of dictionaries with name and folder fields.

Query Syntax

The json_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

The debug 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: Replace lookup_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 comparedcreates and removes args with Ansible command

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home