HomeBlogFilter JSON Data in Ansible Using json_query
Parsing structured JSON data in Ansible playbooks is a common task. Nowadays, the JSON format is heavily used by equipment vendors to represent complex objects in a structured way to allow programmatic interaction with devices. JSON utilizes two main data structures:
object – an unordered collection of key/value pairs (like Python dict)
array – an ordered sequence of objects (like Python list)
Ansible provides many built-in capabilities to consume JSON using Ansible specific filters or the Jinja2 built-in filters. The extensive filters available, and what to use and when, can be overwhelming at first and the desired result can often require multiple filters chained together. This can lead to complex task definition, making playbook maintenance more difficult.
The built-in json_query filter provides the functionality for filtering, shaping, and transforming JSON data. It uses the third-party jmespath library, a powerful JSON query language supporting the parsing of complex structured data.
Setup
The jmespath third-party library must be installed on the host for the json_query filter to operate.
pip install jmespath
Data
Those familiar with Palo Alto firewalls will recognize a modified version of an application content update query. This result dataset will be used to demonstrate how to manipulate JSON data using the json_query filter.
On Palo Alto devices the default stdout response is returned as a JSON encoded string. This string can be passed into the from_json filter to provide a valid JSON data structure. A result variable was set to simplify the readability of the following examples. The json_query filter expects valid JSON as an input, so the Jinja2 expression below can also be passed directly into the json_query filter.
-name:"SET FACT FOR DEVICE STDOUT RESPONSE"set_fact:result:"{{ (content_info['stdout'] | from_json)['response']['result'] }}"
The yaml callback plugin is configured in ansible.cfg for the following examples. This will render output to the console terminal in YAML format, which can be slightly easier to read. See references at the end for Ansible callback usage.
# Use the YAML callback plugin for outputstdout_callback = yaml
Practical Examples
The JMESPath Operators table below summarizes some of the most common operators used in the jmespath query language. See references at the end for the jmespath specification.
JMESPath Operators
Operator
Description
@
The current node being evaluated.
*
Wildcard. All elements.
.key
Dot-notation to access a value of the given key.
[index0, index1, ..]
Indexing array elements, like a list.
[?expression]
Filter expression. Boolean evaluation.
&&
AND expression.
|
Pipe expression, like unix pipe.
&expression
Using an expression evaluation as a data type.
Basic Filter
Using the result data, the filter is applied to the valid JSON result with an additional query string argument. The query string provides the expression that is evaluated against the data to return filtered output. The default data type returned by json_query filter is a list.
In the Basic Filter example below, the query string selects the version key for each element in the entry array.
A pipe expression can be used to select the value of an array by declaring the desired index location. This operates in much the same way as the unix pipe, within the query string.
In the Array Index example below, the first element is selected. Array indexing begins at zero.
-name:"ARRAY INDEX VALUE"debug:msg:"{{ result['content-updates'] | json_query('entry[*].version | [0]') }}"
The response output is a string value for the first element in the array.
TASK [ARRAY INDEX VALUE] *********************************************************ok: [demo-fw01] =>msg:8368-6520
Filter
Using a filter expression within the json_query string, the query result can be filtered using standard comparison operators. A filter expression allows each element of the array to be evaluated against the expression. If the result evaluates to true, the element is included in the returned result.
The equality comparision operator is used in the following example to retrieve the filename(s) of the software version(s) downloaded on the device. Elements in the array that have downloaded=='yes' will have the filename included in the returned result. This provides the ability to use certain keys for the selection criteria, and return the value(s) of other keys for the result.
The jmespath library provides built-in functions to assist in transformation and filtering tasks, for example the max_by function that returns the maximum element in an array. The following task selects the filename of the maximum app-version value from the entry array. The & provides the ability to define an expression which will be evaluated as a data type value when processed by the function.
Using an Ansible variable for the query string can be a cleaner approach to the query definition. It also helps with string quotations that are necessary when the key name is hyphenated. When using an expression data type, the jmespath library requires the key name within quotation marks, e.g., &"key-name". Where key names are not hyphenated, quotation marks are not required, e.g., &keyname.
-name:"MAX BY APP-VERSION"set_fact:content_file:"{{ result['content-updates'] | json_query(querystr) }}"vars:querystr:'max_by(entry, &"app-version").filename'
TASK [MAX BY APP-VERSION] *******************************************************ok: [demo-fw01] =>msg: panupv2-all-apps-8368-6520
Query String with Dynamic Variable
Ansible facts can be substituted into the query string. Again, quotation marks are relevant, so it is preferable to define a separate string as a variable within the task.
In this example the filter expression is used with a built-in function, contains. This function provides a boolean result, based on a match with a search string, on any element within the version array. The search string in this case is an Ansible variable passed into the query using a Jinja2 template.
Again, the first filename, within the returned list using the indexing capability, has been selected.
TASK [FUNCTION WITH VARIABLE] **************************************************ok: [demo-fw01] =>msg: panupv2-all-apps-8368-6520
Multiple Expressions
Multiple expressions can be evaluated using the logical AND operation, following the normal truth table rules. Along with the filter operator, two expressions are provided to be evaluated. This will filter the resulting data based on two selection criteria and provide a list of version values.
Here are some general tips that could be useful while developing a playbook using json_query.
Get familiar with basic jmespath expressions using the interactive tutorial.
Ensure the data provided as input to the json_query filter is a valid JSON object.
Use a test playbook, using the same data as your original playbook, with tasks dedicated to printing query string evaluation output to the console.
Be mindful of quotes within a query string, especially when using linters that specify a standard that may conflict with the jmespath specification.
Conclusion
The jmespath specification has good documentation and support for numerous languages. It requires learning a new query language, but hopefully this guide will help you get started with some common use cases.
The json_query filter is a powerful tool to have at your disposal. It can solve many JSON parsing tasks within your playbook, avoiding the need to write custom filters. If you’d like to see more, please let us know.
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies. In case of sale of your personal information, you may opt out by using the link Do not sell my personal information. Privacy | Cookies
This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
__hssc
30 minutes
HubSpot sets this cookie to keep track of sessions and to determine if HubSpot should increment the session number and timestamps in the __hstc cookie.
__hssrc
session
This cookie is set by Hubspot whenever it changes the session cookie. The __hssrc cookie set to 1 indicates that the user has restarted the browser, and if the cookie does not exist, it is assumed to be a new session.
cookielawinfo-checkbox-advertisement
1 year
Set by the GDPR Cookie Consent plugin, this cookie records the user consent for the cookies in the "Advertisement" category.
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
CookieLawInfoConsent
1 year
CookieYes sets this cookie to record the default button state of the corresponding category and the status of CCPA. It works only in coordination with the primary cookie.
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Cookie
Duration
Description
__cf_bm
30 minutes
Cloudflare set the cookie to support Cloudflare Bot Management.
li_gc
5 months 27 days
Linkedin set this cookie for storing visitor's consent regarding using cookies for non-essential purposes.
lidc
1 day
LinkedIn sets the lidc cookie to facilitate data center selection.
UserMatchHistory
1 month
LinkedIn sets this cookie for LinkedIn Ads ID syncing.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Cookie
Duration
Description
__hstc
5 months 27 days
Hubspot set this main cookie for tracking visitors. It contains the domain, initial timestamp (first visit), last timestamp (last visit), current timestamp (this visit), and session number (increments for each subsequent session).
_ga
1 year 1 month 4 days
Google Analytics sets this cookie to calculate visitor, session and campaign data and track site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognise unique visitors.
_gat_gtag_UA_*
1 minute
Google Analytics sets this cookie to store a unique user ID.
_gid
1 day
Google Analytics sets this cookie to store information on how visitors use a website while also creating an analytics report of the website's performance. Some of the collected data includes the number of visitors, their source, and the pages they visit anonymously.
AnalyticsSyncHistory
1 month
Linkedin set this cookie to store information about the time a sync took place with the lms_analytics cookie.
CONSENT
2 years
YouTube sets this cookie via embedded YouTube videos and registers anonymous statistical data.
hubspotutk
5 months 27 days
HubSpot sets this cookie to keep track of the visitors to the website. This cookie is passed to HubSpot on form submission and used when deduplicating contacts.
ln_or
1 day
Linkedin sets this cookie to registers statistical data on users' behaviour on the website for internal analytics.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
Cookie
Duration
Description
bcookie
1 year
LinkedIn sets this cookie from LinkedIn share buttons and ad tags to recognize browser IDs.
bscookie
1 year
LinkedIn sets this cookie to store performed actions on the website.
li_sugr
3 months
LinkedIn sets this cookie to collect user behaviour data to optimise the website and make advertisements on the website more relevant.
VISITOR_INFO1_LIVE
5 months 27 days
YouTube sets this cookie to measure bandwidth, determining whether the user gets the new or old player interface.
YSC
session
Youtube sets this cookie to track the views of embedded videos on Youtube pages.
yt-remote-connected-devices
never
YouTube sets this cookie to store the user's video preferences using embedded YouTube videos.
yt-remote-device-id
never
YouTube sets this cookie to store the user's video preferences using embedded YouTube videos.
yt.innertube::nextId
never
YouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.
yt.innertube::requests
never
YouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.