Ansible is a powerful tool for automating tasks, but when working with dynamically generated data, such as Ansible facts, it can sometimes be tricky to produce clean, well-formatted output. This article demonstrates how to use Jinja2 templating within an Ansible playbook to transform facts into clean YAML, ensuring proper indentation and formatting.
In this example, we’ll look at a different scenario: transforming networking data (like interfaces, IP addresses, and MAC addresses) into a nicely formatted YAML structure. We’ll cover how to loop through facts, control whitespace in Jinja2, and generate a neat YAML file.
Scenario: Formatting Network Interfaces
Imagine you are managing a fleet of servers and you need to produce a YAML report that lists each network interface’s details, including its name, IP address, MAC address, and the status of the connection.
Here’s an Ansible task that gathers network facts and formats them into clean YAML output.
Ansible Playbook Example
---
- name: Generate network interface report
hosts: localhost
gather_facts: yes
tasks:
- name: Transform network interfaces into YAML
set_fact:
network_yaml: |
interfaces:
{% for iface_name, iface_data in ansible_facts['ansible_interfaces'].items() %}
- name: {{ iface_name }}
mac_address: {{ iface_data.macaddress | default('unknown') }}
ip_address: {{ iface_data.ipv4.address | default('N/A') }}
status: {{ iface_data.active | ternary('up', 'down') }}
{% endfor %}
- name: Save the formatted network interfaces to a file
copy:
content: "{{ network_yaml }}"
dest: /tmp/network_interfaces.yaml
Breaking Down the Example
Gathering Facts: We start by setting
gather_facts: yes
, which collects information about the target machine. In this case, we focus on theansible_interfaces
fact, which contains data about each network interface on the machine.Looping Through Interfaces: Using Jinja2 templating, we iterate over the
ansible_interfaces
dictionary. For each interface, we access its name, MAC address, IP address, and status (whether it’s active or inactive).Whitespace Control: Proper indentation is crucial in YAML, so we ensure that the loop outputs are correctly aligned by adjusting the placement of the Jinja2 tags within the template.
Using Filters:
default
: If a MAC address or IP is not present, we use this filter to insert a default value ('unknown'
or'N/A'
).ternary
: This filter is used to convert theactive
boolean value into human-readable statuses ('up'
for true,'down'
for false).
Saving the Output: The
copy
module saves the generated YAML content to/tmp/network_interfaces.yaml
.
Sample Output
When this playbook is run on a machine, the output YAML file might look like this:
interfaces:
- name: eth0
mac_address: 02:42:ac:11:00:02
ip_address: 192.168.1.100
status: up
- name: eth1
mac_address: 02:42:ac:11:00:03
ip_address: N/A
status: down
- name: wlan0
mac_address: 3c:22:fb:4e:88:67
ip_address: 10.0.0.5
status: up
Understanding YAML Formatting in Ansible
Why Use YAML for Reporting?
YAML (YAML Ain’t Markup Language) is highly readable, human-friendly, and widely used in configuration management. With Ansible, generating YAML reports makes it easy for both humans and systems to process structured data. This format is perfect for representing complex data such as server configurations, network interfaces, disk details, etc.
Controlling Indentation with Jinja2
One of the key challenges in formatting YAML using Jinja2 is controlling indentation. If you’re unfamiliar with how loops and conditionals work in Jinja2 templates, you might end up with broken YAML due to extra spaces or newlines. Here’s how we ensure indentation is handled correctly:
Template Syntax: Make sure your
for
andendfor
statements are placed at the right level of indentation relative to the output. For example:{% for item in items %} - key: {{ item.key }} {% endfor %}
Avoid Extra Newlines: Jinja2 can add unwanted newlines. If you need more control, you can use whitespace control operators like
{{-
and-}}
to strip leading and trailing whitespace.
Simplifying the Task with the to_nice_yaml
Filter
Ansible also provides the to_nice_yaml
filter, which automatically converts a dictionary into well-formatted YAML. If your scenario doesn’t require complex transformations or loops, you can use this filter to simplify the process.
Here’s a simplified version of the same task using to_nice_yaml
:
- name: Transform network interfaces using to_nice_yaml
set_fact:
network_data: |
{{ ansible_facts['ansible_interfaces'] | to_nice_yaml }}
- name: Save the formatted YAML to a file
copy:
content: "{{ network_data }}"
dest: /tmp/network_interfaces.yaml
In this version, we let Ansible handle the formatting, and we skip the manual template building. This is particularly useful if you don’t need to apply custom logic (such as filtering or transforming values).
Conclusion
Generating well-formatted YAML from Ansible facts is a powerful way to extract and report on dynamic data in your infrastructure. By using Jinja2 templates or Ansible’s built-in filters like to_nice_yaml
, you can output clean and structured YAML files that can be easily read by both humans and machines.
This technique is highly flexible and can be adapted to various scenarios, whether you’re reporting on network interfaces, disk usage, or any other aspect of your systems. By understanding how to manage indentation and control whitespace in your templates, you can ensure that your YAML output is always clean and properly formatted.
Subscribe to the YouTube channel, Medium, and Website, X (formerly Twitter) to not miss the next episode of the Ansible Pilot.Academy
Learn the Ansible automation technology with some real-life examples in my Udemy 300+ Lessons Video Course.
My book Ansible By Examples: 200+ Automation Examples For Linux and Windows System Administrator and DevOps
Donate
Want to keep this project going? Please donate