-
-
Save rothgar/8793800 to your computer and use it in GitHub Desktop.
# Idempotent way to build a /etc/hosts file with Ansible using your Ansible hosts inventory for a source. | |
# Will include all hosts the playbook is run on. | |
# Inspired from http://xmeblog.blogspot.com/2013/06/ansible-dynamicaly-update-etchosts.html | |
- name: "Build hosts file" | |
lineinfile: dest=/etc/hosts regexp='.*{{ item }}$' line="{{ hostvars[item].ansible_default_ipv4.address }} {{item}}" state=present | |
when: hostvars[item].ansible_default_ipv4.address is defined | |
with_items: groups['all'] |
@tiendungitd I got the same error using a 2.5 version of Ansible, not sure what happened to these variables. I just got around by using hostvars[item].ip
instead.
@rhinoceros, @tiendungitd, @haridsv
Ansible requires that facts have been gathered before 'hostvars' can be used to obtain the desired data. So be careful with 'gather_facts: False'.
Ansible 2.5, at least, seems to require that the 'hostvars' values be referenced like this:
{{ hostvars[item].ansible_facts.default_ipv4.address }}
Notice the 'ansible_facts' reference. It was a bit painful, but I started with only 'hostvars[item]' in the template. Then in the generated 'hosts' file I 'walked' into the resultant text to find the appropriate nested fields. There are other reference paths to the desired ip address that could be followed.
etc_hosts.yml:
---
- hosts: all
become: yes
become_user: root
tasks:
- name: update /etc/hosts file
blockinfile:
dest: /etc/hosts
content: "{{ lookup('template', 'hosts.j2') }}"
state: present
template/hosts.j2:
{% for item in ansible_play_batch %}
{%- if item != 'localhost' %}
{{ hostvars[item].ansible_facts.default_ipv4.address }} {{ item }}
{% endif %}
{% endfor %}
To solve this I initially tried:
---
- hosts: localhost
become: yes
become_user: root
tasks:
- debug: var=inventory_hostname
- debug: var=hostvars[inventory_hostname]
to decipher the reference path to the desired ip address, but that does not show that the 'ansible_facts' reference is required in the template.
There may be someplace that documents current references to the values available in 'hostvars' and current appropriate methods to access them. But I haven't found it yet.
It works in Ansible 2.7.6:
- name: Add the inventory into /etc/hosts
lineinfile:
dest: /etc/hosts
regexp: '.*{{ item }}$'
line: "{{ hostvars[item]['ansible_default_ipv4']['address'] }} {{item}}"
state: present
when: hostvars[item]['ansible_facts']['default_ipv4'] is defined
with_items:
- "{{ groups['all'] }}"
I got:
"msg": "The conditional check 'hostvars[item].ansible_default_ipv4.address is defined' failed.
The error was:
error while evaluating conditional (hostvars[item].ansible_default_ipv4.address is defined):
u\"hostvars['groups['all']']\" is undefined\n\n
The error appears to be in '/var/lib/awx/projects/_16__openpoint_ansible/playbooks/hostname.yml': line 12, column 7,
but may\n
be elsewhere in the file depending on the exact syntax problem.
\n\n
The offending line appears to be:
\n\n
post_tasks:
\n - name: Build hosts file
\n ^ here
\n",
And I fix it with @rwngallego 's codes.
https://serverfault.com/questions/832799/ansible-add-ip-of-all-hosts-to-etc-hosts-of-all-other-hosts
this works for ansible 2.2.1
tasks:
- name: "generate hosts file from inventory "
copy:
src: "{{inventory_for_bastion}}"
dest: /etc/ansible/hosts
mode: 766
- name: "Build hosts file"
lineinfile: dest=/etc/hosts regexp='.*{{ item }}$' line="{{ hostvars[item].ansible_host}} {{item}}" state=present
with_items: "{{ groups['internal'] }}"
make sur that the group internal
is defined in your inventory located in /etc/ansible/hosts
and looks like that :
[internal]
terraform-controller-0 ansible_host=10.240.0.4
Hi there, sorry for refloating. I'm sharing my update just in the case helps someone else.
Based on the solutions already posted, I've got the issue where I had hosts with multiple NICs/IPs that I wanted to add to the /etc/hosts.
e.g.:
192.168.10.11 10.0.2.15 10.10.10.11 ha-1 ha-1
192.168.10.12 10.0.2.15 10.10.10.12 ha-2 ha-2
So I changed the variable {{ hostvars[item].ansible_facts.default_ipv4.address }}
for {{ hostvars[item].ansible_facts.all_ipv4_addresses | join(" ") }}
that is basically the list of IP address in the host gather from the ansible facts, converted to a list of strings separated by space.
Thank you guys for adding your solutions. Were extremely helpful for me.
Hi, I was wondering if anybody was able to test this solution using Molecule?
@dywanik After some research, I could confirm there's no way to manipulate /etc/hosts with Molecule using docker platform. The /etc/hosts file is crucial for Docker's linking system and it should only be manipulated manually at the image level, rather than the container level.
See:
https://docs.docker.com/network/links/#updating-the-etchosts-file
Anyway the solution proposed here works fine.
I have simply added this code in my molecule.yml
...
provisioner:
name: ansible
inventory:
group_vars:
all:
run_not_in_container: False
...
and then modified my tasks/main.yml
- name: Generate /etc/hosts file
template:
src: etc/hosts.j2
dest: /etc/hosts
owner: root
group: root
mode: 0644
when: run_not_in_container
when you test your role remember to set the variable
[all:vars]
run_not_in_container=True
@enr0s, you can also use the tag/variable molecule-notest
that's already set by molecule, so you don't have to define your own.
tasks/main.yml
---
- name: Generate /etc/hosts file
template:
src: etc/hosts.j2
dest: /etc/hosts
owner: root
group: root
mode: 0644
tags:
- molecule-notest
or
tasks/main.yml
---
- name: Generate /etc/hosts file
template:
src: etc/hosts.j2
dest: /etc/hosts
owner: root
group: root
mode: 0644
when: molecule-notest not in ansible_skip_tags
Another solution to this issue would be to use a "dummy" hosts file with molecule, which is not a perfect solution but is better than skipping the task in my opinion because you can then confirm that the hosts file is generated correctly.
The way to achieve that would be something like:
defaults/main.yml
---
etc_hosts_file: /etc/hosts
molecule.yml
provisioner:
name: ansible
inventory:
group_vars:
all:
etc_hosts_file: /tmp/molecule_etc_hosts
tasks/main.yml
---
- name: Generate /etc/hosts file
template:
src: etc/hosts.j2
dest: "{{ etc_hosts_file }}"
owner: root
group: root
mode: 0644
@dywanik , I am not sure if that is what you are searching for... in my case, I wanted simply to add an entry to /etc/hosts.
The following worked for me:
molecule.yml:
---
...
platforms:
- name: "myplatformname"
etc_hosts:
"repo": "8.8.8.8"
I got issue when using this way, try with ansible version 2.4 and 2.5, any idea?
try to debug