How to write more advanced Ansible inventory files?

Previously we took a look at creating a basic plain text file inventory for our Ansible automation project, but we will need more functionality when we start using it seriously. Luckily Ansible provides us some other ways to create groups of hosts and handle them. Let’s investigate what else can we do in an Ansible inventory!

We have already created the simplest possible inventory, a file with a host entry. The possible simplest inventory file is an INI file containing our Ansible control node.

Ansible looks for the /etc/ansible/hosts file for an inventory by default. We can provide the command line tools any inventory file with using the -i option, like ansible-playbook -i hosts/inventory.ini or any other file.

Let’s stay with the file-based inventories for now! We will take a look at the INI and YAML format.

Now it is time to understand how are the Ansible managed hosts grouped by default.

Default groups in Ansible inventories

Every host in an Ansible inventory will belong to two groups by default: all and ungrouped or a custom group.

The ansible-inventory command will be in our help for exploring the groups.

$ ansible-inventory -i inventory --graph    
@all:
  |--@ungrouped:
  |  |--ansible-control
  |--@vmware:
  |  |--@lab:
  |  |  |--juiceshop
  |  |--@production:
  |  |  |--kali
  |  |  |--zoneminder

We can see from the example that every Ansible managed host is member of the all group.

The ansible-control host is not member of other custom groups, so this is automatically a member of the ungrouped group too.

The vmware is a non-default group, it was created by us in the INI file.

Inventory groups

We can create our own custom inventory groups:

[vmware]
test.vmware.host

In the INI format example we create a group called vmware and it contains the test.vmware.host host.

In YAML format it would look like this:

---
all:
  children:
    vmware:
      hosts:
        test.vmware.host:

An Ansible inventory can contain multiple groups, and a group can contain multiple hosts:

[vmware]
test.vmware
prod.vmware
staging.vmware

[hyperv]
test.hyperv
prod.hyperv

This INI inventory contains two groups (vmware and hyperv) and both contain multiple host entries.

The YAML format looks like this:

---
all:
  children:
    hyperv:
      hosts:
        prod.hyperv:
        test.hyperv:
    vmware:
      hosts:
        prod.vmware:
        staging.vmware:
        test.vmware:

Normally we want to group our hosts by some logic like function or location.

Groups of groups

Sometimes we want to handle groups in other groups. For example our vmware and hyperv groups are both virtualized host groups. We may want to create a parent group called virtual.

In this case the INI format will create the parent group with the :children keyword after we created the child entries.

[vmware]
test.vmware
prod.vmware
staging.vmware

[hyperv]
test.hyperv
prod.hyperv

[virtual:children]
vmware
hyperv

Both groups are members of the virtual group now.

We can confirm it with the ansible-inventory command:

$ ansible-inventory -i test.inventory.ini --graph  
@all:
  |--@ungrouped:
  |--@virtual:
  |  |--@vmware:
  |  |  |--test.vmware
  |  |  |--prod.vmware
  |  |  |--staging.vmware
  |  |--@hyperv:
  |  |  |--test.hyperv
  |  |  |--prod.hyperv

The YAML version of the same inventory looks like this:

---
all:
  children:
    virtual:
      children:
        hyperv:
          hosts:
            prod.hyperv:
            test.hyperv:
        vmware:
          hosts:
            prod.vmware:
            staging.vmware:
            test.vmware:

There are some things to remember about groups of groups in the Ansible documenation:

  • Any host that is member of a child group is automatically a member of the parent group.
  • Groups can have multiple parents and children, but not circular relationships.
  • Hosts can also be in multiple groups, but there will only be one instance of a host at runtime. Ansible merges the data from the multiple groups.
Ansible Documentation

Converting the INI format to YAML

We can convert our INI format Ansible inventories to YAML with the ansible-inventory command:

$ ansible-inventory -i test.inventory.ini --list --yaml
all:
  children:
    ungrouped: {}
    virtual:
      children:
        hyperv:
          hosts:
            prod.hyperv: {}
            test.hyperv: {}
        vmware:
          hosts:
            prod.vmware: {}
            staging.vmware: {}
            test.vmware: {}

Listing the INI inventory and using the --yaml option will print out the inventory in YAML format.

Behavioral inventory parameters

There are some behavioral parameters we can use in our inventory. They help us to fine-tune the connection and user settings for different hosts.

---
all:
  children:
    ansible:
      hosts:
        ansible-control:
          ansible_become_method: sudo
          ansible_connection: local
          ansible_host: 192.168.3.130
    vmware:
      children:
        lab:
          hosts:
            juiceshop:
              ansible_become_method: su
              ansible_become_user: root
              ansible_host: 192.168.3.129
        production:
          hosts:
            kali:
              ansible_become_method: sudo
              ansible_become_user: kali
              ansible_host: 192.168.3.128
            zoneminder:
              ansible_become_method: su
              ansible_become_user: root
              ansible_host: 192.168.3.133

or

[ansible]
ansible-control ansible_host=192.168.3.130 ansible_become_method=sudo  ansible_connection=local

[lab]
juiceshop       ansible_host=192.168.3.129 ansible_become_method=su    ansible_become_user=root

[production]
kali            ansible_host=192.168.3.128 ansible_become_method=sudo  ansible_become_user=kali
zoneminder      ansible_host=192.168.3.133 ansible_become_method=su    ansible_become_user=root

[vmware:children]
lab
production

Here is an example of the behavioral parameters we can use to control the connection, the users and so on. These options can be used in INI and YAML as well.

Here is a list of the parameters we can use in our inventory: https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html#connecting-to-hosts-behavioral-inventory-parameters

Other thoughts

We can pass variables or set host variables in our Ansible inventory though I found it problematic in big environments with a lot of hosts. It is even more difficult to track with dynamic inventory scripts mixed with static inventories.

When we want to run a playbook on an inventory of hosts, we can check the hosts beforehand with the ansible-playbook command.

$ ansible-playbook -i inventory play-test.yml --list-hosts 

playbook: play-test.yml

  play #1 (all): Test playbook for playing with Ansible TAGS: []
    pattern: ['all']
    hosts (4):
      kali
      zoneminder
      ansible-control
      juiceshop

With the --list-hosts option will show our host pattern in the playbook, and it lists the matched hosts.

It is also possible to narrow down the target hosts for a playbook with the --limit option.

$ ansible-playbook -i inventory play-test.yml --limit ansible --list-hosts

playbook: play-test.yml

  play #1 (all): Test playbook for playing with Ansible TAGS: []
    pattern: ['all']
    hosts (1):
      ansible-control

It opens up a full world of possibilities for running Ansible of different target hosts and groups. Happy automating!

If you have anything to share then please visit my Tom’s IT Cafe Discord Server!

Leave a comment