Create a tree-like structure with ansible

Solution 1:


I guess what you're looking for is combine with recursive=True in a set_fact task:

This playboook, for example, gathers hostname => ip relations for each of my nodes which helps me to ensure /etc/hosts or dns configurations are consistent accross my cluster.

- hosts: all
  tasks:
    - name: Gather hosts ips
      shell: "dig {{ item }} +short"
      register: hosts_ips
      loop: "{{ ansible_play_batch }}"

    - name: dbg
      ansible.builtin.debug:
        var: hosts_ips

    - name: Storing ips as fact
      set_fact:
        hosts_status:
          "{{ hosts_status|default([]) | combine({
              item.item : {
                'ip': item.stdout,
              }
            }, recursive=True)
          }}"
      loop: "{{ hosts_ips.results | default([]) }}"

    - name: dbg hosts_status
      ansible.builtin.debug:
        var: hosts_status

Result on each server (They're the same so i'm good):

ok: [amsh-1] => {
    "hosts_status": {
        "amsh-1": {
            "ip": "192.168.121.28"
        },
        "amsh-2": {
            "ip": "192.168.121.109"
        },
        "amsh-3": {
            "ip": "192.168.121.229"
        },
        "amsh-4": {
            "ip": "192.168.121.92"
        }
    }
}
ok: [amsh-2] => {
    "hosts_status": {
        "amsh-1": {
            "ip": "192.168.121.28"
        },
        "amsh-2": {
            "ip": "192.168.121.109"
        },
        "amsh-3": {
            "ip": "192.168.121.229"
        },
        "amsh-4": {
            "ip": "192.168.121.92"
        }
    }
}
ok: [amsh-3] => {
    "hosts_status": {
        "amsh-1": {
            "ip": "192.168.121.28"
        },
        "amsh-2": {
            "ip": "192.168.121.109"
        },
        "amsh-3": {
            "ip": "192.168.121.229"
        },
        "amsh-4": {
            "ip": "192.168.121.92"
        }
    }
}
ok: [amsh-4] => {
    "hosts_status": {
        "amsh-1": {
            "ip": "192.168.121.28"
        },
        "amsh-2": {
            "ip": "192.168.121.109"
        },
        "amsh-3": {
            "ip": "192.168.121.229"
        },
        "amsh-4": {
            "ip": "192.168.121.92"
        }
    }
}

I guess you'll be able to make your data structure with it.

PS: btw, this script inline in an Ansible playbook is written in jinja2 if you look for docs: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#combining-and-selecting-data