Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Ansible Playbook JSON Configuration Strategies
Ansible playbooks are primarily written in YAML, a human-readable data serialization format. However, in modern automation workflows, you often need to interact with data in JSON format. This could be fetching data from APIs, processing output from commands, defining complex nested variables, or configuring applications that expect JSON input.
Integrating JSON effectively into your Ansible playbooks requires understanding how Ansible handles data transformation and manipulation. This article explores common strategies for working with JSON within your playbooks.
Handling JSON Data with Filters
Ansible provides built-in filters powered by Jinja2 to easily convert between YAML/Python objects and JSON strings. The two primary filters for this are to_json
and from_json
.
The to_json
Filter
The to_json
filter converts an Ansible variable (which is essentially a Python data structure like a dictionary or list) into a JSON formatted string. This is useful when you need to pass data to a command-line tool, an API call, or write it to a file in JSON format.
You can optionally pass arguments like indent
to make the output human-readable.
Example: Using to_json
--- - name: Demonstrate to_json filter hosts: localhost gather_facts: false vars: my_data: name: "Ansible User" roles: ["developer", "sysadmin"] settings: verbose: true level: 5 tasks: - name: Output data as a JSON string debug: msg: "{{ my_data | to_json }}" - name: Output data as a pretty-printed JSON string debug: msg: "{{ my_data | to_json(indent=2) }}" - name: Create a JSON file from the variable copy: content: "{{ my_data | to_json(indent=2) }}" dest: /tmp/my_config.json
The first debug
task will output a compact JSON string. The second will output a formatted, indented string, which is often easier to read. The copy
task demonstrates how to write this JSON string to a file.
The from_json
Filter
The from_json
filter (or its alias from_yaml
, as YAML is a superset of JSON) takes a JSON formatted string and converts it into an Ansible variable (a Python dictionary or list). This is essential when you read JSON from a file, receive it from an API response, or capture it from command output.
Example: Using from_json
--- - name: Demonstrate from_json filter hosts: localhost gather_facts: false tasks: - name: Simulate receiving JSON data from a command/API set_fact: json_output_string: '{"status": "success", "data": {"id": 123, "items": ["apple", "banana"]}}' - name: Convert JSON string to Ansible variable set_fact: parsed_data: "{{ json_output_string | from_json }}" - name: Access elements from the parsed JSON data debug: msg: "Status: {{ parsed_data.status }}, First item: {{ parsed_data.data.items[0] }}"
After applying from_json
, you can navigate the resulting Ansible variable using standard dot or bracket notation, just like any other variable in your playbook.
Storing JSON Data in Variables
While you can store JSON as a string and use from_json
, Ansible (being YAML-based) is perfectly capable of representing nested data structures directly.
Often, a JSON structure can be directly translated into equivalent YAML structure within a playbook's vars
section or a separate variable file. Ansible will handle this nested YAML as the corresponding Python dictionary or list, which is compatible with JSON structure.
Example: JSON-like structure in Ansible Vars
--- - name: JSON structure stored directly in vars hosts: localhost gather_facts: false vars: user_config: user: name: "Charlie" id: 456 preferences: theme: "dark" notifications: email: true sms: false permissions: - role: "editor" level: "high" - role: "viewer" level: "low" tasks: - name: Access nested data debug: msg: "User name: {{ user_config.user.name }}, Email notifications: {{ user_config.user.preferences.notifications.email }}" - name: Convert this structure to JSON string debug: msg: "{{ user_config | to_json(indent=2) }}"
This approach is generally cleaner and more readable for complex static configuration data than embedding large JSON strings.
Reading JSON from Files
You can store complex JSON configuration data in separate .json
files and read them into your playbook using the include_vars
or vars_files
keywords. Ansible will automatically parse the JSON content into a variable.
Example: Reading JSON from a file (config.json
)
Contents of config.json
:
{ "app": { "name": "WebApp", "version": "1.0.0", "enabled_features": ["auth", "logging"] }, "database": { "host": "db.example.com", "port": 5432 } }
Playbook snippet:
--- - name: Read config from JSON file hosts: localhost gather_facts: false vars_files: - config.json # Ansible automatically parses this as JSON/YAML tasks: - name: Access data read from the JSON file debug: msg: "App name: {{ app.name }}, DB Host: {{ database.host }}" - name: Convert the loaded data back to JSON (optional, for verification) debug: msg: "{{ vars | to_json(indent=2) }}" # 'vars' includes variables from vars_files
When using vars_files
or include_vars
, Ansible is smart enough to detect the file format (YAML or JSON) and load it accordingly, making this a straightforward way to manage external JSON configuration.
Querying JSON Data with json_query
For complex JSON data structures, navigating manually with dot/bracket notation can become cumbersome, especially when dealing with lists or needing to filter data. The json_query
filter, based on JMESPath, provides a powerful way to query JSON structures.
Example: Using json_query
--- - name: Demonstrate json_query filter hosts: localhost gather_facts: false vars: complex_data: users: - id: 1 name: "Alice" active: true roles: ["admin", "user"] - id: 2 name: "Bob" active: false roles: ["user"] - id: 3 name: "Charlie" active: true roles: ["editor", "user"] settings: default_role: "user" tasks: - name: Get names of all users debug: msg: "{{ complex_data | json_query('users[*].name') }}" # [ "Alice", "Bob", "Charlie" ] - name: Get users who are active debug: msg: "{{ complex_data | json_query('users[?active == `true`]') | to_json(indent=2) }}" # Outputs list of user objects where active is true - name: Get names of users who have the 'admin' role debug: msg: "{{ complex_data | json_query('users[?contains(roles, `'admin'`)].name') }}" # [ "Alice" ] - name: Get default setting debug: msg: "{{ complex_data | json_query('settings.default_role') }}" # "user"
JMESPath syntax takes some learning, but it's incredibly powerful for extracting exactly the data you need from complex JSON structures, making your playbooks cleaner and more robust.
Best Practices
- •Use
from_json
/from_yaml
for parsing: Always convert incoming JSON strings to Ansible variables using these filters before attempting to access their elements. - •Prefer YAML structure for static data: If your JSON data is part of your playbook's static configuration, define it directly using YAML's native nested structure instead of embedding JSON strings.
- •Store large/complex JSON in separate files: Use
vars_files
orinclude_vars
to keep your playbooks clean when dealing with substantial JSON configurations. - •Leverage
json_query
for complex data extraction: Invest time in learning JMESPath if you frequently work with nested or list-heavy JSON outputs. - •Handle potential errors: JSON operations can fail if the input string is invalid or the query path doesn't exist. Use conditional checks or error handling (e.g.,
failed_when
,ignore_errors
, usingdefault(omit)
or| d()
/| d([])
) where appropriate.
Common Pitfalls
- •Not parsing JSON strings: Trying to access elements of a JSON string directly (e.g.,
"{...}".status
) will fail. Always use| from_json
first. - •YAML vs. JSON syntax: While YAML can represent JSON, be mindful of indentation and special characters in YAML strings if manually embedding JSON strings. Using the
| to_json
filter is safer for generating JSON strings. - •Complex queries without
json_query
: Deeply nested access likevariable['key1']['key2'][0]['subkey']
becomes hard to read and maintain quickly. Usejson_query
for anything beyond basic access.
Conclusion
Effectively managing JSON data is a crucial skill for modern Ansible automation. By utilizing Ansible's built-in filters like to_json
, from_json
, and json_query
, and by structuring your variable data appropriately, you can seamlessly integrate JSON into your playbooks, making them capable of interacting with a wider range of systems and data sources.
Understanding these strategies allows you to build more flexible, powerful, and maintainable automation workflows that can handle complex configuration scenarios.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool