2015/08/11

Use ansible to update host file on the servers

I had some time to play around with Ansible. Ansible is a great tool, which allows you to automate your environment.

I came to a problem, where I need to distribute host file to all machines in inventory and update this host file with host specific variables, which are located in inventory as well. Here is the guide that shows you how to create host file and distribute this file to all hosts that are located in the inventory.

To achieve the goal, I have created the ansible host file, with all hosts in my network. I have grouped the the servers based on server roles. It looks like this:

$cat ansible_hosts
[controller]
controller

[network]
network

[compute]
compute1
compute2

I have also created the subfolder, which is located in the same folder as ansible_hosts file. I have named this folder host_vars. Ansible automatically load files located in that folder and associate variables with the host in inventory file. The name of the file must be the same as name of the host in inventory. I put the following variables in the file:

$cat host_vars/controller
---
hostname: controller
ip_address: 10.0.0.101

You can use ansible template module, which takes file and update file with variables. Ansible uses Jinja2 templating system. I took the default ubuntu hosts file and updated file with the following lines:

127.0.0.1 localhost
127.0.1.1 {{ hostname }}

{% for host in groups['all'] %}
{{ hostvars[host]['ip_address']  }} {{ hostvars[host]['hostname']  }}
{% endfor %}

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

The Jinja2 templating system replace {{ hostname }} with the variable hostname of the current host. Another interesting block is for loop. The for loop goes through all hosts that are listed in ansible inventory file. You can also replace the 'all' with the specific group, which will be used to go only through hosts listed in that group. The hostvars is reserved dictionary, which holds all variables for all hosts. You can access specific variable with correct keys.

Now I have created the playbook which will use this template.

---
- hosts: all
  remote_user: ansible
  tasks:

   # Create hosts file from variables and copy file to remote destination /etc/hosts
   - template: src=./templates/hosts dest=/etc/hosts
     become: yes
     become_method: sudo

You should run this playbook with the command:

$ ansible-playbook openstack_install.yml
...
TASK [template dest=/etc/hosts src=./templates/hosts] **************************
changed: [compute1]
changed: [compute2]
changed: [controller]
changed: [network]
...

If you display the host file on one of the server, the hosts file is updated correctly.

ansible@controller:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 controller

10.0.0.131 compute1
10.0.0.132 compute2
10.0.0.101 controller
10.0.0.111 network

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

This is the example of the usage of the Jinja2 templating system with ansible. The templating system is very powerful which allows you to create complex template and updated these templates with correct variables.