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

  1. Gathering Facts: We start by setting gather_facts: yes, which collects information about the target machine. In this case, we focus on the ansible_interfaces fact, which contains data about each network interface on the machine.

  2. 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).

  3. 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.

  4. 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 the active boolean value into human-readable statuses ('up' for true, 'down' for false).
  5. 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 and endfor 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.

BUY the Complete Udemy 300+ Lessons Video Course

My book Ansible By Examples: 200+ Automation Examples For Linux and Windows System Administrator and DevOps

BUY the Complete PDF BOOK to easily Copy and Paste the 250+ Ansible code

Want to keep this project going? Please donate

Patreon Buy me a Pizza