mirror of https://github.com/ansible/ansible.git
First pass of the Ansible EC2 inventory script
parent
444c02ac82
commit
43eb3214a6
@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/python -tt
|
||||||
|
|
||||||
|
"""
|
||||||
|
EC2 external inventory script
|
||||||
|
=================================
|
||||||
|
|
||||||
|
NOTE: This script assumes Ansible is being executed where the environment
|
||||||
|
variables needed for Boto have been set:
|
||||||
|
export AWS_ACCESS_KEY_ID=''
|
||||||
|
export AWS_SECRET_ACCESS_KEY=''
|
||||||
|
For more details, see: http://docs.pythonboto.org/en/latest/boto_config_tut.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
from time import time
|
||||||
|
from boto import ec2
|
||||||
|
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
except ImportError:
|
||||||
|
import simplejson as json
|
||||||
|
|
||||||
|
|
||||||
|
### Settings
|
||||||
|
|
||||||
|
# I can see other uses where this variable is something else, say if someone
|
||||||
|
# is running Ansible within EC2, these might be internal IP addresses
|
||||||
|
destinationVariable = "public_dns_name"
|
||||||
|
vpcDestinationVariable = "ip_address"
|
||||||
|
|
||||||
|
cachePath = "/tmp/ansible-ec2.cache"
|
||||||
|
cacheMaxAge = 300 # seconds
|
||||||
|
|
||||||
|
|
||||||
|
# Command line argument processing
|
||||||
|
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on EC2')
|
||||||
|
parser.add_argument('--list', action='store_true', default=True,
|
||||||
|
help='list instances (default: True)')
|
||||||
|
parser.add_argument('--refresh-cache', action='store_true', default=False,
|
||||||
|
help='refreshes the cache by making API requests to EC2 (default: False, use cache)')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Instance IDs, tags, security groups, regions, availability zones
|
||||||
|
inventory = {}
|
||||||
|
|
||||||
|
|
||||||
|
def doApiCall(regionInfo):
|
||||||
|
# Loop over all regions
|
||||||
|
region = regionInfo.name
|
||||||
|
conn = ec2.connect_to_region(region)
|
||||||
|
|
||||||
|
inventory[region] = []
|
||||||
|
|
||||||
|
reservations = conn.get_all_instances()
|
||||||
|
for reservation in reservations:
|
||||||
|
for instance in reservation.instances:
|
||||||
|
if instance.state == 'terminated':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Select the best destination address
|
||||||
|
if instance.subnet_id:
|
||||||
|
dest = getattr(instance, vpcDestinationVariable)
|
||||||
|
else:
|
||||||
|
dest = getattr(instance, destinationVariable)
|
||||||
|
|
||||||
|
if dest == None:
|
||||||
|
# Skip instances we cannot address (e.g. VPC private subnet)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Group by instance ID (always a group of 1)
|
||||||
|
inventory[instance.id] = [dest]
|
||||||
|
|
||||||
|
# Group by region
|
||||||
|
inventory[region].append(dest);
|
||||||
|
|
||||||
|
# Group by availability zone
|
||||||
|
if instance.placement in inventory:
|
||||||
|
inventory[instance.placement].append(dest);
|
||||||
|
else:
|
||||||
|
inventory[instance.placement] = [dest]
|
||||||
|
|
||||||
|
# Group by security group
|
||||||
|
for group in instance.groups:
|
||||||
|
key = toSafe("security-group_" + group.name)
|
||||||
|
if key in inventory:
|
||||||
|
inventory[key].append(dest);
|
||||||
|
else:
|
||||||
|
inventory[key] = [dest]
|
||||||
|
|
||||||
|
# Group by tag keys
|
||||||
|
for k, v in instance.tags.iteritems():
|
||||||
|
key = toSafe("tag_" + k + "=" + v)
|
||||||
|
if key in inventory:
|
||||||
|
inventory[key].append(dest);
|
||||||
|
else:
|
||||||
|
inventory[key] = [dest]
|
||||||
|
|
||||||
|
return formatInventory(True)
|
||||||
|
|
||||||
|
def getInventoryFromCache():
|
||||||
|
cache = open(cachePath, 'r')
|
||||||
|
jsonInventory = cache.read()
|
||||||
|
return jsonInventory
|
||||||
|
|
||||||
|
def getInventoryFromApiUpdateCache():
|
||||||
|
for region in ec2.regions():
|
||||||
|
doApiCall(region)
|
||||||
|
|
||||||
|
jsonInventory = formatInventory(True)
|
||||||
|
cache = open(cachePath, 'w')
|
||||||
|
cache.write(jsonInventory)
|
||||||
|
cache.close()
|
||||||
|
return jsonInventory
|
||||||
|
|
||||||
|
def toSafe(word):
|
||||||
|
return re.sub("[^A-Za-z0-9\-]", "_", word)
|
||||||
|
|
||||||
|
def formatInventory(pretty=False):
|
||||||
|
if pretty:
|
||||||
|
return json.dumps(inventory, sort_keys=True, indent=2)
|
||||||
|
else:
|
||||||
|
return json.dumps(inventory)
|
||||||
|
|
||||||
|
|
||||||
|
# Do work here
|
||||||
|
if args.refresh_cache:
|
||||||
|
jsonInventory = getInventoryFromApiUpdateCache()
|
||||||
|
|
||||||
|
elif os.path.isfile(cachePath):
|
||||||
|
modTime = os.path.getmtime(cachePath)
|
||||||
|
currentTime = time()
|
||||||
|
if (modTime + cacheMaxAge) > currentTime:
|
||||||
|
# Use cache
|
||||||
|
jsonInventory = getInventoryFromCache()
|
||||||
|
else:
|
||||||
|
jsonInventory = getInventoryFromApiUpdateCache()
|
||||||
|
|
||||||
|
else:
|
||||||
|
jsonInventory = getInventoryFromApiUpdateCache()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print jsonInventory
|
||||||
|
|
Loading…
Reference in New Issue