What if ansible_default_ipv4 is Empty?

A colleague was attempting to use ansible to install Kubernetes, but he hit an error that confused him:

TASK [etcd : Write etcd config file] *******************************************

task path: /root/k8s-20160803-vishpat-contrib-git/contrib/ansible/roles/etcd/tasks/main.yml:23

fatal: [k8s-master.vnslab.net]: FAILED! => {"changed": false, "failed": true,
 "invocation": {"module_args": {"dest": "/etc/etcd/etcd.conf", "src": "etcd.conf.j2"},
 "module_name": "template"}, "msg": "AnsibleUndefinedVariable:
 {{ etcd_peer_url_scheme }}://{{ etcd_machine_address }}:{{ etcd_peer_port }}:
 {{ hostvars[inventory_hostname]['ansible_' + etcd_interface].ipv4.address }}:
 {{ ansible_default_ipv4.interface }}: 'dict object' has no attribute 'interface'"}

I asked him for a copy of the setup module (gather facts) for the host in question:

ansible -i 'your_host_name,' -m setup

This portion of the output jumped out at me:

<snip>
       },
        "ansible_default_ipv4": {},
        "ansible_default_ipv6": {},
        "ansible_devices": {
</snip>

ansible_default_ipv4 was empty. This was the root cause of the problem. When ansible tries to deploy the etcd template from roles/etcd/templates/etcd.conf.j2 it hits the following lines and attempts to substitute values for the variables:

<snip>
{% for host in groups[etcd_peers_group] -%}
  {{ hostvars[host]['ansible_hostname'] }}={{ etcd_peer_url_scheme }}:
    //{{ hostvars[host]['ansible_' + etcd_interface].ipv4.address }}:
    {{ etcd_peer_port }}
  {%- if not loop.last -%},{%- endif -%}
{%- endfor -%}
</snip>

And the definition of etcd_interface depends on ansible_default_ipv4 being populated. From roles/etcd/defaults/main.yaml: 

<snip>
# Interface on which etcd listens.
# Useful on systems when default interface is not connected to other machines,
# for example as in Vagrant+VirtualBox configuration.
# Note that this variable can't be set in per-host manner with current implementation.
etcd_interface: "{{ ansible_default_ipv4.interface }}"
</snip>

The result: When ansible tries to deploy the etcd.config template, it discovers that ansible_default_ipv4.interface doesn’t exist. It throws up its hands.

The fix: Setup a default route on the host under consideration. Instructions can be found here:

http://linux-ip.net/html/basic-changing.html#basic-changing-default

Once the change to to the host was made, ansible_default_ipv4.interface was populated! Problem solved!

Advertisements