Ansible: Use hostvars to Generate Hosts File

There are cases when you need to access variables for another host, including facts that have been gathered about that host.

The Problem

I have 5 Ansible managed hosts in my homelab that I use for testing. I want to use a template to generate the /etc/hosts file for each managed node. The content of the file that I want to end up with is below:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

10.11.1.62 ansible2.hl.local ansible2
10.11.1.63 ansible3.hl.local ansible3
10.11.1.64 ansible4.hl.local ansible4
10.11.1.65 ansible5.hl.local ansible5
10.11.1.66 ansible6.hl.local ansible6

While I can easily retrieve facts about the host the playbook is run on, I need a way of accessing facts that have been gathered about other hosts as well.

The Solution: Magic Variables

The hostvars magic variable allows you access variables for another host, including facts that have been gathered about that host. You can access host variables at any point in a playbook.

If a server needs to use the value of a “fact” from another node, it’s easy to do so within a template templates/hosts.j2:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

{{ hostvars['ansible2.hl.local']['ansible_default_ipv4']['address'] }} {{ hostvars['ansible2.hl.local']['ansible_fqdn'] }} {{ hostvars['ansible2.hl.local']['ansible_hostname'] }}
{{ hostvars['ansible3.hl.local']['ansible_default_ipv4']['address'] }} {{ hostvars['ansible3.hl.local']['ansible_fqdn'] }} {{ hostvars['ansible3.hl.local']['ansible_hostname'] }}
{{ hostvars['ansible4.hl.local']['ansible_default_ipv4']['address'] }} {{ hostvars['ansible4.hl.local']['ansible_fqdn'] }} {{ hostvars['ansible4.hl.local']['ansible_hostname'] }}
{{ hostvars['ansible5.hl.local']['ansible_default_ipv4']['address'] }} {{ hostvars['ansible5.hl.local']['ansible_fqdn'] }} {{ hostvars['ansible5.hl.local']['ansible_hostname'] }}
{{ hostvars['ansible6.hl.local']['ansible_default_ipv4']['address'] }} {{ hostvars['ansible6.hl.local']['ansible_fqdn'] }} {{ hostvars['ansible6.hl.local']['ansible_hostname'] }}

The playbook:

---
- name: Generate Hosts File
  hosts: all
  become: true
  gather_facts: true
  vars:
    my_file: /etc/hosts
    my_template: templates/hosts.j2
  tasks:
    - name: Create "{{ my_file }}"
      template:
        src: "{{ my_template }}"
        dest: "{{ my_file }}"
        owner: root
        group: root
        mode: "0644"

14 thoughts on “Ansible: Use hostvars to Generate Hosts File

    • you are assuming that all readers are at a higher level of understanding. There are students also learning from your posts. So it is very naive to assume that all readers are at the same level.

    • Thanks for your feedback, much appreciated. I am indeed making an assumption that a person leaving a comment has some understanding about the topic, however, we are all different and obviously have different experience when it comes to technology. If you are using my material to study and learn then that’s terrific, I’m really glad, and thank you for that! However, in all honesty, I don’t personally think that it’s the best place to start if you’re new to the subject. There are better guides/training materials online that will cover the basics, explain the subject in more details and even provide you with step-by-step instructions. I can tell from experience because I used some of them myself when learning Ansible.

  1. Hi Tomas,

    Thanks for sharing this tutorial, it really helped me. However, allow me to do a suggestion?

    On my inventory file (/etc/ansible/hosts), I have 3 groups:

    —————–
    [lb]
    lb01

    [www]
    www01
    www02

    [db]
    db01
    —————–

    And on the template file templates/hosts.j2, I did a for loop, which is quite handy… specially for a real world situation where many times I have more groups and more hosts. Adding host line by line on the template kinda of annoys me, sorry! :X

    ——————
    templates/hosts.j2
    #
    # Managed by Ansible. DO NOT edit it by hand!
    #

    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

    # Load Balancer Server
    {% for host in groups[‘lb’] -%}
    {{ hostvars[host][‘ansible_default_ipv4’][‘address’] }} {{ hostvars[host][‘ansible_fqdn’] }} {{ hostvars[host][‘ansible_hostname’] }}
    {% endfor %}

    # Web Server
    {% for host in groups[‘www’] -%}
    {{ hostvars[host][‘ansible_default_ipv4’][‘address’] }} {{ hostvars[host][‘ansible_fqdn’] }} {{ hostvars[host][‘ansible_hostname’] }}
    {% endfor %}

    # Database Server
    {% for host in groups[‘db’] -%}
    {{ hostvars[host][‘ansible_default_ipv4’][‘address’] }} {{ hostvars[host][‘ansible_fqdn’] }} {{ hostvars[host][‘ansible_hostname’] }}
    {% endfor %}

    ——————

    Hope it may help someone! :)

    Cheers,
    Jhonatan Rampin

    • Thanks! Yea, you can easily use a loop. I found several examples on docs.ansible.com, they are really handy in real life situations, but a bit overkill for my 5 node homelab. And it’s less typing (copy/paste)!

  2. Here is my jinja2 template:
    {% for host in groups.all %}
    {{ hostvars[host].ansible_default_ipv4.address }} {{ hostvars[host].ansible_fqdn }} {{ hostvars[host].ansible_hostname }}
    {% endfor %}

  3. Hi sir,
    I got a fatal error while running . yml file,
    hostvars[‘host’] is undefined

    Can you please tell me the reason for this error.
    There is no syntax errors

    • Hi please remove ‘ ‘ from host
      hostvar[host]
      Mention the group in the yml file you mentioned in the jinja2 file

  4. Hi everyone – How can I put configuration to Catalyst 9300 which connected to my laptop via COM3 port. ThanksS

  5. This is my’s jinja2 templates for vagrant virtual machine.

    {% for host in groups.all %}
    {{ hostvars[host].ansible_all_ipv4_addresses | difference([“10.0.2.15”]) | ipaddr | first }} {{ hostvars[host].ansible_fqdn }} {{ hostvars[host].ansible_hostname }}
    {% endfor %}

Leave a Reply

Your email address will not be published. Required fields are marked *