Using dynamic inventory
We have talked about dynamic inventory a little bit in this chapter. Throughout this book, in every chapter, we are going to talk about and use dynamic inventory. So let us explore the concept in a bit more depth.
Reiterating what we wrote earlier, dynamic inventory is useful for infrastructures that are dynamic in nature or for cases where we do not want to or cannot maintain a static inventory. Dynamic inventory queries a datasource and builds the inventory in real time. For the sake of this book, we will query cloud providers to get data and build the inventory. Ansible provides dynamic inventory scripts for most of the popular cloud providers.
However, it is simple to create a dynamic inventory script by ourselves. Any executable script that can return a JSON with a list of inventory host groups and hosts in a predetermined format, when passed with a parameter --list
can be used as an inventory script. A very simple inventory would output something like this:
{ "application": ["10.0.0.11", "10.0.0.12"], "database": ["10.0.1.11"] }
More elaborate inventory scripts would output much more information like instance tags, names, operating systems, geographical locations, and, also known as host facts.
How to do it…
To present a realistic example, we have created a simple inventory script for Amazon Web Service in Python. The code is available on GitHub (https://github.com/ansible-cookbook/ec2_tags_inventory):
#!/usr/bin/env python import boto3 import json import ConfigParser import os def get_address(instance): if "PublicIpAddress" in instance: address = instance["PublicIpAddress"] else: address = instance["PrivateIpAddress"] return address if os.path.isfile('ec2.ini'): config_path = 'ec2.ini' elif os.path.isfile(os.path.expanduser('~/ec2.ini')): config_path = os.path.expanduser('~/ec2.ini') config = ConfigParser.ConfigParser() config.read(config_path) id = config.get("credentials", "aws_access_key_id", raw=True) key = config.get("credentials", "aws_secret_access_key", raw=True) client = boto3.client('ec2', aws_access_key_id = id, aws_secret_access_key = key, region_name="us-east-1") inventory = {} reservations = client.describe_instances()['Reservations'] for reservation in reservations: for instance in reservation['Instances']: address = get_address(instance) for tag in instance['Tags']: if tag['Key'] == "ansible_role": roles = tag['Value'].split(",") for role in roles: if role in inventory: inventory[role].append(address) else: inventory[role] = [address] print json.dumps(inventory)
This script reads a file called ec2.ini
for AWS access and secret key. For the sake of simplicity, we have hardcoded the region to us-east-1
but this can be changed easily. The script goes through AWS EC2 in the us-east-1
region and looks for any instance that has a tag with the name ansible_role
and any valid value like webserver
or database
. It will add the IP addresses of those instances to the Python dictionary variable called inventory. In the end, this variable is dumped as JSON as output.
We can test this by executing:
$ python ec2_tags_inventory.py --list {"application": ["10.0.0.11", "10.0.0.12"], "database": ["10.0.1.11"]}
Note that output may vary depending on the instances that are tagged in EC2. To use this in an Ansible command, we need to make it executable and just pass the script instead of inventory file to -i
flag like this:
$ chmod +x ec2_tags_inventory.py $ ansible -i ec2_tags_inventory.py database -m ping database | SUCCESS => { "changed": false, "failed": false, "ping": "pong" }
Needless to say, this is a very simple example and the actual dynamic inventory script provided by Ansible is much more comprehensive and it looks beyond EC2 to other services, such as RDS.