While there are lots of tools in Ansible for generating an inventory file dynamically, in a system like this, you might want to be able to perform additional operations against the same cluster. For example, once the cluster has been running for a few months, you might want to do a Yum update. Eventually, you want to de-provision. Thus, having a remote record of what machines make up a particular cluster can be very useful. Dynamic inventories can be OK, but often it takes time to regenerate the inventory, and that may slow down an already long process, especially during iterated development.
So, I like to generate inventory files. These are fairly simple files, but they are not one of the supported file types in Ansible. Ansible does support ini files, but the inventory files have maybe lines that are not in key=value format.
Instead, I use Jinja formatting to generate inventory files, and they are pretty simple to work with.
UPDATE: I jumped the gun on the inventory file I was generating. The template and completed inventory have been corrected.
To create the set of hosts, I use the OpenStack server (os_server) task, like this:
- name: create servers os_server: cloud: "{{ cloudname }}" state: present name: "{{ item }}.{{ clustername }}" image: rhel-guest-image-7.4-0 key_name: ayoung-pubkey timeout: 200 flavor: 2 security_groups: - "{{ securitygroupname }}" nics: - net-id: "{{ osnetwork.network.id }}" net-name: "{{ netname }}_network" meta: hostname: "{{ netname }}" with_items: "{{ cluster_hosts }}" register: osservers - file: path: "{{ config_dir }}" state: directory mode: 0755 - file: path: "{{ config_dir }}/deployments" state: directory mode: 0755 - file: path: "{{ cluster_dir }}" state: directory mode: 0755 - template: src: inventory.ini.j2 dest: "{{ cluster_dir }}/inventory.ini" force: yes backup: yes |
A nice thing about this task is, whether it is creating new server or not, it produces the same output, which is a json object that has the server data in an array.
The following template is my current fragment.
[all] {% for item in osservers.results %} {{ item.server.interface_ip }} {% endfor %} {% for item in osservers.results %} [{{ item.server.name }}] {{ item.server.interface_ip }} {% endfor %} [ipa] {% for item in osservers.results %} {% if item.server.name.startswith('idm') %} {{ item.server.interface_ip }} {% endif %} {% endfor %} [all:vars] ipa_server_password={{ ipa_server_password }} ipa_domain={{ clustername }} deployment_dir={{ cluster_dir }} ipa_realm={{ clustername|upper }} cloud_user=cloud-user ipa_admin_user_password={{ ipa_admin_password }} ipa_forwarder={{ ipa_forwarder }} lab_nameserver1={{ lab_nameserver1 }} lab_nameserver2={{ lab_nameserver2 }} |
I keep the variable definitions in a separate file. This produces an inventory file that looks like this:
[all] 10.11.95.161 10.11.95.149 10.11.95.152 10.11.95.159 [idm.ayoung.rdusalab] 10.11.95.161 [master.ayoung.rdusalab] 10.11.95.149 [node0.ayoung.rdusalab] 10.11.95.152 [node1.ayoung.rdusalab] 10.11.95.159 [ipa] 10.11.95.161 [all:vars] ipa_server_password=FreeIPA4All ipa_domain=ayoung.rdusalab deployment_dir=/home/ayoung/rippowam/deployments/ayoung.rdusalab ipa_realm=AYOUNG.RDUSALAB cloud_user=cloud-user ipa_admin_user_password=FreeIPA4All ipa_forwarder=192.168.52.3 lab_nameserver1=8.8.8.8 lab_nameserver2=8.8.8.7 |
My next step is to create a host group for all of the nodes (node0 node1) based on a shared attribute. I probably will do that by converting the list of hosts to a dictionary keyed by hostname, and have the name of the groups as the value.
Hi Adam,
Great Post. Very helpful and very useful. This saved a day of work for me 🙂
Another quick question :
This is my host file :
[dev]
server1
server2
server3
server4
server5
[dev-z]
server1
server2
server3
[dev-bus]
server1
server2
[dev-bus_ui]
server1
[dev-super]
server4
server5
Using the host file, How to create a template to get the resultant something like this ?
z.servers:
– “server1”
– “server2”
– “server3”
n.servers: [“server1″,”server2”]
Any help/suggestion ?
Hi,
Thanks for the post! It helped a lot.
This works fine if I am using two playbooks; one for generating inventory and second one where I use this inventory and run my tasks. But I am getting stuck when I am trying incorporate all this in one playbook as ansible parses the inventory at the start of the first play. Since the inventory is only generated after first play, this method is giving me an error.
Please let me know if it is possible or what I am doing wrong here. Thanks again!
For those cases, you would want to use a dynamic inventory approach. If you want to use the templating approach along with it, perhaps a task that reads in an inventory.ini file and adds the hosts to dynamic inventory? You could make a custom script like this: https://www.jeffgeerling.com/blog/creating-custom-dynamic-inventories-ansible . I often use the OpenStack based dynamic inventory script.