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!