4

I have a jinja2 template, and I'm trying to loop through a host group, and insert the ipv4 address of all the hosts in my template. But I'm getting an error when I do it, even though the way I'm doing it is the way every post and article suggest it should be done.

Here's the template that's producing the error:

{% if groups['linux-hosts'] %}
{% for item in groups['linux-hosts'] %}
define host {
    use                     generic-host-normal
    host_name               {{ item }}
    alias                   {{ item }}
    address                 {{ hostvars[item].ansible_default_ipv4.address }}
}
{% endfor %}
{% endif %}

And the error I'm getting is:

failed: [server] (item=servers.cfg) => {"changed": false, "item": "servers.cfg", "msg": "AnsibleUndefinedVariable: 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'ansible_default_ipv4'"}

If I don't use the variable 'item' in the square brackets, but instead specify a specific host from the inventory, Ansible is able to get the ipv4 address. Example ('server' is the name of a host from my inventory):

{{ hostvars['server'].ansible_default_ipv4.address }}
Harald
  • 65
  • 1
  • 1
  • 8
  • 1
    also, as a friendly FYI, you can shorten that `if` business by just defaulting the groups to empty: `{% for item in groups.get('linux-hosts', []) %}` – mdaniel Dec 02 '18 at 23:54

4 Answers4

6

I came across this problem with a similar use case. My problem turned out to be that I included hosts in a group which were not the target of the play. Therefore gather facts had not run against all the hosts in the group. I fixed this by running setup against all the hosts I needed like this

- name: get cluster facts
  hosts: k8s-cluster
  tags:
    - always
  tasks:
    - name:
      setup:
      become: true

- name: deploy HA Proxy
  hosts: kube-master
  become: yes
  roles:
    - { role: ansible-role-haproxy }

Note: kube-master is a subset of k8s-cluster

awalker125
  • 61
  • 1
  • 2
5

It's because you are missing the gather_facts: yes or an equivalent - setup: task in your playbook; those facts don't magically appear unless requested, which happens by default, but one can certainly switch off through gather_facts: no

A simple test will show what I mean:

- hosts: all
  gather_facts: yes
  tasks:
  - debug: var=ansible_default_ipv4 verbosity=0

and then change gather_facts: no and observe the kaboom

mdaniel
  • 31,240
  • 5
  • 55
  • 58
  • Thank you! That was indeed the probblem. It turns out that I have another problem too though. I'm now able to get the IP-address of a linux host, but I'm not able to get it from my Windows hosts. When I run a play with only the debug task, like you suggestested, I'm getting this from my windows hosts: ok: [windows1.domain.no] => { "ansible_facts.env.ip_addresses": "VARIABLE IS NOT DEFINED!" } – Harald Dec 03 '18 at 08:28
  • 8
    It does not work for me even using ```gather_facts: yes``` – Robert Mar 16 '19 at 06:58
0

The solution described here worked for me.

Add an empty play at the top of your playbook to gather facts for all hosts. Ansible hostvars has no attribute 'ansible_nodename'

lhc130
  • 9
  • 1
-1

I had the same issue.

For me that problem has been that I have run my playbook with the --tags flag.
This lead to the effect that Ansible does not gather any facts!

secustor
  • 3,001
  • 2
  • 14
  • 20