Ansible Dynamic Inventories

Mostly, any infrastructure can be managed with a custom inventory file, but there are many situations where more control is needed. Consider you are working with the 100 machines on AWS cloud. Now suppose you have to restart all these machines which will lead to change in its public addresses and hence we have to make changes in the host file as well. This is where Dynamic inventory comes very handy.

Ansible accepts any kind of executable file as an inventory file. Hence, you can build your own dynamic inventory the way you like, the only restriction is that you have to pass it to Ansible as JSON.

You could create an executable binary, a script, or anything else that can be run and will output JSON to stdout, and Ansible will call it with the argument --list when you run, as an example, ansible all -i my-inventory-script -m ping.

{
  "group": {
    "hosts": ["192.168.0.16", "192.168.0.17"],
    "vars": {
      "ansible_ssh_user": "gaurav",
      "ansible_ssh_private_key_file": "~/.ssh/key",
      "example_variable": "value"
    }
  },
  "_meta": {
    "hostvars": {
      "192.168.0.17": {
        "host_specific_var": "bar"
      },
      "192.168.0.18": {
        "host_specific_var": "foo"
      }
    }
  }
}

Ansible expects a dictionary of groups and a _meta dictionary that stores host variables for all hosts individually.

The dynamic inventory script can do anything to get the data, and Ansible will use it as an inventory source as long as it returns a JSON structure like the one above when the script is called with the --list.

Custom Dynamic Inventory in Python

#!/usr/bin/python
import json
import argparse
def get_inventory_data():
    data =  {
      "database": {
          "hosts": ["sqlserver1"],
          "vars" : {
              "ansible_ssh_pass": "password",
              "ansible_ssh_host": "192.168.25.15"
           }
       }
    }
    return data

if __name__ == "__main__":
    data = get_inventory_data()
    #print(json.dumps(data))
    parser = argparse.ArgumentParser()
    parser.add_argument('--list', action='store_true')
    parser.add_argument('--host', action='store')
    arg = parser.parse_args()
    if arg and arg.list:
        print(json.dumps(data))
    elif arg.host:
        print(json.dumps({'_meta': {'hostvars': {}}}))