How can I debug this playbook so that I can properly loop over the hostvars?

120 views
Skip to first unread message

Abe Voelker

unread,
Aug 28, 2014, 1:19:24 PM8/28/14
to ansible...@googlegroups.com
I have an inventory file like this:

[redisservers]
72.14.178.81

[webservers]
198.58.107.247

I'm trying to run this playbook against the redisservers group to allow access to port 6379 for the webservers:

---
- name: Allow port 6379 (Redis) access to Web servers
  ufw
: rule=allow interface=eth0 direction=in port=6379 proto=tcp src="{{ hostvars[item]['ansible_eth0']['ipv4']['address'] }}"
  with_items
: groups['webservers']

But I'm getting this error:

TASK: [redis | Allow port 6379 (Redis) access to Web servers] ***************** 
fatal: [72.14.178.81] => One or more undefined variables: 'dict object' has no attribute 'ansible_eth0'

FATAL: all hosts have already failed -- aborting

I'm not sure what's going on as all servers definitely have an eth0 interface.  When I run ansible all -m setup -i inventory, the output seems to confirm that there is an ansible_eth0 fact available for all servers: https://gist.github.com/abevoelker/7a3c18f10793a744e6da

I've tried simplifying the playbook to refer to the exact server in question to remove the looping:

---
- name: Allow port 6379 (Redis) access to Web servers
  ufw
: rule=allow interface=eth0 direction=in port=6379 proto=tcp src="{{ hostvars[groups['webservers'][0]]['ansible_eth0']['ipv4']['address'] }}"

and also

---
- name: Allow port 6379 (Redis) access to Web servers
  ufw
: rule=allow interface=eth0 direction=in port=6379 proto=tcp src="{{ hostvars['198.58.107.247']['ansible_eth0']['ipv4']['address'] }}"

But I'm still getting the same error.

Any hints as to what I'm doing wrong or how I can continue to debug this?  I'm using Ansible 1.7.1.

Abe Voelker

unread,
Aug 28, 2014, 3:25:05 PM8/28/14
to ansible...@googlegroups.com
So I wrote a template task that populates this jinja template:

{{ hostvars['198.58.107.247'] }}

And this is the output I got:

{'ansible_ssh_user': 'root', 'inventory_hostname_short': '198', 'group_names': ['webservers'], 'inventory_hostname': '198.58.107.247'}

So hostvars['198.58.107.247'] doesn't seem to be filled with all the facts for that host.  Then I realized that the root playbook I'm running (provision.yml) looks like this:

---
- include: redisservers.yml
- include: webservers.yml

And the redisservers.yml playbook it includes looks like this:

---
- hosts: redisservers
  roles
:
   
- redis

And the full output I'm seeing from running the playbook looks like this (my emphasis):

PLAY [redisservers] *********************************************************** 

GATHERING FACTS *************************************************************** 
ok: [72.14.178.81]

TASK: [redis | Allow port 6379 (Redis) access to Web servers] ***************** 
fatal: [72.14.178.81] => One or more undefined variables: 'dict object' has no attribute 'ansible_eth0'

FATAL: all hosts have already failed -- aborting

So from the output it looks like it has only gathered facts for 72.14.178.81 by the time the redisservers playbook runs.  Therefore I fixed my issue by changing the order of provision.yml, which runs the webservers playbook first and populates the facts for 198.58.107.247 before the redisservers playbook runs:

---
- include: webservers.yml
- include: redisservers.yml

Then I figured out that if I add a hosts: all line to provision.yml, it will gather facts for all hosts before running the included playbooks:

---
- hosts: all
- include: webservers.yml
- include: redisservers.yml

PLAY [all] ******************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [72.14.178.81]
ok: [198.58.107.247]

PLAY [webservers] *************************************************************
... 

So that way I don't have worry about the order of playbook inclusion.  But this still seems kind of hacky... wouldn't it be better if there were a way to access hostvars in a manner that will just populate it for a host if it hasn't been populated yet?  Sort of a lazy evaluation?

Michael DeHaan

unread,
Aug 28, 2014, 5:07:51 PM8/28/14
to ansible...@googlegroups.com
In Ansible to use facts about a host you must have either:

already gathered facts from that host in that play (just gathering facts would be enough, no tasks needed)

- hosts: webservers:dbservers
  tasks: []

- hosts: webservers  # that need to know facts about dbservers
  tasks:
    - ...


OR

enabled fact caching and previously talked to that host within the cache timeout 





--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/792ddf1e-fdbf-430e-bb60-7647a554bbcb%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages