#!/usr/bin/env python ################################################################################ # Dynamic inventory generation for Ansible # In orignal version found here: https://github.com/lukaspustina/dynamic-inventory-for-ansible-with-openstack # Author lukas.pustina@codecentric.de # With additions from Johan Dahlberg - johan.dahlberg@medsci.uu.se # # This Python script generates a dynamic inventory based on OpenStack instances. # # The script is passed via -i <script name> to ansible-playbook. Ansible # recognizes the execute bit of the file and executes the script. It then # queries nova via the novaclient module and credentials passed via environment # variables -- see below. # # The script iterates over all instances of the given tenant and checks if the # instances' metadata have set keys OS_METADATA_KEY -- see below. These keys shall # contain all Ansible host groups comma separated an instance shall be part of, # e.g., u'ansible_host_groups': u'admin_v_infrastructure,apt_repos'. # It is also possible to set Ansible host variables, e.g., # u'ansible_host_vars': u'dns_server_for_domains->domain1,domain2;key2->value2' # Values with a comma will be transformed into a list. # # Metadata of an instance may be set during boot, e.g., # > nova boot --meta <key=value> # , or to a running instance, e.g., # nova meta <instance name> set <key=value> # # *** Requirements *** # * Python: novaclient module be installed which is part of the nova ubuntu # package. # * The environment variables OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME, # OS_AUTH_URL and OS_NETWORK_NAME must be set according to nova. # ################################################################################ from __future__ import print_function from novaclient.v2 import client import os, sys, json OS_METADATA_KEY = { 'host_groups': 'ansible_host_groups', 'host_vars': 'ansible_host_vars' } try: OS_NETWORK_NAME = os.environ['OS_NETWORK_NAME'] except KeyError as e: print("ERROR: environment variable %s is not defined" % e, file=sys.stderr) sys.exit(-1) def main(args): credentials = getOsCredentialsFromEnvironment() nt = client.Client(credentials['USERNAME'], credentials['PASSWORD'], credentials['TENANT_NAME'], credentials['AUTH_URL'], service_type="compute") inventory = {} inventory['_meta'] = { 'hostvars': {} } for server in nt.servers.list(): floatingIp = getFloatingIpFromServerForNetwork(server, OS_NETWORK_NAME) if floatingIp: for group in getAnsibleHostGroupsFromServer(nt, server.id): addServerToHostGroup(group, floatingIp, inventory) host_vars = getAnsibleHostVarsFromServer(nt, server.id) if host_vars: addServerHostVarsToHostVars(host_vars, floatingIp, inventory) dumpInventoryAsJson(inventory) def getOsCredentialsFromEnvironment(): credentials = {} try: credentials['USERNAME'] = os.environ['OS_USERNAME'] credentials['PASSWORD'] = os.environ['OS_PASSWORD'] credentials['TENANT_NAME'] = os.environ['OS_TENANT_NAME'] credentials['AUTH_URL'] = os.environ['OS_AUTH_URL'] except KeyError as e: print("ERROR: environment variable %s is not defined" % e, file=sys.stderr) sys.exit(-1) return credentials def getAnsibleHostGroupsFromServer(novaClient, serverId): metadata = getMetaDataFromServer(novaClient, serverId, OS_METADATA_KEY['host_groups']) if metadata: return metadata.split(',') else: return [] def getMetaDataFromServer(novaClient, serverId, key): return novaClient.servers.get(serverId).metadata.get(key, None) def getAnsibleHostVarsFromServer(novaClient, serverId): metadata = getMetaDataFromServer(novaClient, serverId, OS_METADATA_KEY['host_vars']) if metadata: host_vars = {} for kv in metadata.split(';'): key, values = kv.split('->') values = values.split(',') host_vars[key] = values return host_vars else: return None def getFloatingIpFromServerForNetwork(server, network): for addr in server.addresses.get(network): if addr.get('OS-EXT-IPS:type') == 'floating': return addr['addr'] if addr.get('OS-EXT-IPS:type') == 'fixed': return addr['addr'] return None def addServerToHostGroup(group, floatingIp, inventory): host_group = inventory.get(group, {}) hosts = host_group.get('hosts', []) hosts.append(floatingIp) host_group['hosts'] = hosts inventory[group] = host_group def addServerHostVarsToHostVars(host_vars, floatingIp, inventory): inventory_host_vars = inventory['_meta']['hostvars'].get(floatingIp, {}) inventory_host_vars.update(host_vars) inventory['_meta']['hostvars'][floatingIp] = inventory_host_vars def dumpInventoryAsJson(inventory): print(json.dumps(inventory, indent=4)) if __name__ == "__main__": main(sys.argv)