Parsing complex BIG-IP json structures made easy with Ansible filters like json_query

JMESPath and json_query

JMESPath (JSON Matching Expression paths) is a query language for searching JSON documents. It allows you to declaratively extract elements from a JSON document. Have a look at this tutorial to learn more.

The json_query filter lets you query a complex JSON structure and iterate over it using a loop structure.This filter is built upon jmespath, and you can use the same syntax as jmespath. Click here to learn more about the json_query filter and how it is used in Ansible.

In this article we are going to use the bigip_device_info module to get various facts from the BIG-IP and then use the json_query filter to parse the output to extract relevant information.

Ansible bigip_device_info module

Playbook to query the BIG-IP and gather system based information.

- name: "Get BIG-IP Facts"
  hosts: bigip
  gather_facts: false
  connection: local

  tasks:
  - name: Query BIG-IP facts
    bigip_device_info:
     provider:
      validate_certs: False
      server: "xxx.xxx.xxx.xxx"
      user: "*****"
      password: "*****"
     gather_subset:
     - system-info
    register: bigip_facts

  - set_fact:
    facts: '{{bigip_facts.system_info}}'
   
  - name: debug
    debug: msg="{{facts}}"

To view the output on a different subset, below are a few examples to change the gather_subset and set_fact values in the above playbook from gather_subset: system-info, facts: bigip_facts.system_info to any of the below:

  • gather_subset: vlans , facts: bigip_facts.vlans
  • gather_subset: self-ips, facts: bigip_facts.self_ips
  • gather_subset: nodes. facts: bigip_facts.nodes
  • gather_subset: software-volumes, facts: bigip_facts.software_volumes
  • gather_subset: virtual-servers, facts: bigip_facts.virtual_servers
  • gather_subset: system-info, facts: bigip_facts.system_info
  • gather_subset: ltm-pools, facts: bigip_facts.ltm_pools

Click here to view all the information that can be obtained from the BIG-IP using this module.

Parse the JSON output

Once we have the output lets take a look at how to parse the output. As mentioned above the jmespath syntax can be used by the json_query filter.

Step 1: We will get the jmespath syntax for the information we want to extract

Step 2: We will see how the jmespath syntax and then be used with json_query in an Ansible playbook

The website used in this article to try out the below syntax: https://jmespath.org/

Some BIG-IP sample outputs are attached to this article as well (Check the attachments section after the References). The attachment file is a combined output of a few configuration subsets.Copy paste the relevant information from the attachment to test the below examples if you do not have a BIG-IP.

System information

The output for this section is obtained with above playbook using parameters: gather_subset: system-info, facts: bigip_facts.system_info

Once the above playbook is run against your BIG-IP or if you are using the sample configuration attached, copy the output and paste it in the relevant text box. Try different queries by placing them in the text box next to the magnifying glass as shown in image below

# Get MAC address, serial number, version information
msg.[base_mac_address,chassis_serial,platform,product_version]

# Get MAC address, serial number, version information and hardware information
msg.[base_mac_address,chassis_serial,platform,product_version,hardware_information[*].[name,type]]

Software volumes

The output for this section is obtained with above playbook using parameters:

  • gather_subset: software-volumes
  • facts: bigip_facts.software_volumes


# Get the name and version of the software volumes installed and its status
msg[*].[name,active,version]

# Get the name and version only for the software volume that is active
msg[?active=='yes'].[name,version]

VLANs and Self-Ips

The output for this section is obtained with above playbook using parameters

  • gather_subset: vlans and self-ips
  • facts: bigip_facts


Look at the following example to define more than one subset in the playbook

# Get all the self-ips addresses and vlans assigned to the self-ip
# Also get all the vlans and the interfaces assigned to the vlan
[msg.self_ips[*].[address,vlan], msg.vlans[*].[full_path,interfaces[*]]]

Nodes

The output for this section is obtained with above playbook using parameters

  • gather_subset: nodes,
  • facts: bigip_facts.nodes


# Get the address and availability status of all the nodes
msg[*].[address,availability_status]

# Get availability status and reason for a particular node
msg[?address=='192.0.1.101'].[full_path,availability_status,status_reason]

Pools

The output for this section is obtained with above playbook using parameters

  • gather_subset: ltm-pools
  • facts: bigip_facts.ltm_pools


# Get the name of all pools
msg[*].name

# Get the name of all pools and their associated members
msg[*].[name,members[*]]

# Get the name of all pools and only address of their associated members
msg[*].[name,members[*].address]

# Get the name of all pools along with address and status of their associated members
msg[*].[name,members[*].address,availability_status]

# Get status of pool members of a particular pool
msg[?name=='/Common/pool'].[members[*].address,availability_status]

# Get status of pool
# Get address, partition, state of pool members
msg[*].[name,members[*][address,partition,state],availability_status]

# Get status of a particular pool and particular member (multiple entries on a member)
msg[?full_name=='/Common/pool'].[members[?address=='192.0.1.101'].[address,partition],availability_status]

Virtual Servers

The output for this section is obtained with above playbook using parameters

  • gather_subset: virtual-servers
  • facts: bigip_facts.virtual_servers


# Get destination IP address of all virtual servers
msg[*].destination

# Get destination IP and default pool of all virtual servers
msg[*].[destination,default_pool]

# Get me all destination IP of all virtual servers that a particular pool as their default pool
msg[?default_pool=='/Common/pool'].destination

# Get me all profiles assigned to all virtual servers
msg[*].[destination,profiles[*].name]

Loop and display using Ansible

We have seen how to use the jmespath syntax and extract information, now lets see how to use it within an Ansible playbook

- name: Parse the output
  hosts: localhost
  connection: local
  gather_facts: false
  
  tasks:
  - name: Setup provider
    set_fact:
     provider:
     server: "xxx.xxx.xxx.xxx"
     user: "*****"
     password: "*****"
     server_port: "443"
     validate_certs: "no"

  - name: Query BIG-IP facts
    bigip_device_info:
     provider: "{{provider}}"
     gather_subset:
     - system_info
    register: bigip_facts

  - debug: msg="{{bigip_facts.system_info}}"

  # Use json query filter. The query_string will be the jmespath syntax
  # From the jmespath query remove the 'msg' expression and use it as it is 
  - name: "Show relevant information"
    set_fact:
     result: "{{bigip_facts.system_info | json_query(query_string)}}"
    vars:
     query_string: "[base_mac_address,chassis_serial,platform,product_version,hardware_information[*].[name,type]]"

  - debug: "msg={{result}}"

Another example of what would change if you use a different query (only highlighting the changes that need to made below from the entire playbook)

- name: Query BIG-IP facts
  bigip_device_info:
   provider: "{{provider}}"
   gather_subset:
   - ltm-pools
  register: bigip_facts

- debug: msg="{{bigip_facts.ltm_pools}}"

- name: "Show relevant information"
  set_fact:
   result: "{{bigip_facts.ltm_pools | json_query(query_string)}}"
  vars:
   query_string: "[*].[name,members[*][address,partition,state],availability_status]"

The key is to get the jmespath syntax for the information you are looking for and then its a simple step to incorporate it within your Ansible playbook

References

Published Aug 25, 2020
Version 1.0

Was this article helpful?

2 Comments

  • Thanks I haven't heard about jmespath. I used jq for my json parsing, it is another tool will parse long JSON documents, More info https://stedolan.github.io/jq/

  • Payal_S's avatar
    Payal_S
    Ret. Employee

    Yup jq is great as well. json_query is a filter supported by Ansilbe. Not sure if how jq would be used within ansible.