Merge pull request #7444 from carsongee/cg/nova_inventory_improvements

Improvements to OpenStack inventory script
pull/10705/head
Brian Coca 10 years ago
commit 8d871f9650

@ -1,30 +1,45 @@
# Ansible OpenStack external inventory script # Ansible OpenStack external inventory script
[openstack] [openstack]
#-------------------------------------------------------------------------
# Required settings
#-------------------------------------------------------------------------
# API version # API version
version = 2 version = 2
# OpenStack nova username # OpenStack nova username
username = username =
# OpenStack nova api_key # OpenStack nova api_key or password
api_key = api_key =
# OpenStack nova auth_url # OpenStack nova auth_url
auth_url = auth_url =
# Authentication system # OpenStack nova project_id or tenant name
auth_system =
# OpenStack nova project_id
project_id = project_id =
#-------------------------------------------------------------------------
# Optional settings
#-------------------------------------------------------------------------
# Authentication system
# auth_system = keystone
# Serverarm region name to use # Serverarm region name to use
region_name = # region_name =
# Specify a preference for public or private IPs (public is default)
# prefer_private = False
# What service type (required for newer nova client)
# service_type = compute
# TODO: Some other options # TODO: Some other options
# insecure = # insecure =
# endpoint_type = # endpoint_type =
# extensions = # extensions =
# service_type =
# service_name = # service_name =

@ -25,11 +25,9 @@ from novaclient import client as nova_client
try: try:
import json import json
except: except ImportError:
import simplejson as json import simplejson as json
from ansible.module_utils.openstack import *
################################################### ###################################################
# executed with no parameters, return the list of # executed with no parameters, return the list of
# all groups and hosts # all groups and hosts
@ -41,6 +39,7 @@ NOVA_CONFIG_FILES = [os.getcwd() + "/nova.ini",
NOVA_DEFAULTS = { NOVA_DEFAULTS = {
'auth_system': None, 'auth_system': None,
'region_name': None, 'region_name': None,
'service_type': 'compute',
} }
@ -54,45 +53,152 @@ def nova_load_config_file():
return None return None
def get_fallback(config, value, section="openstack"):
"""
Get value from config object and return the value
or false
"""
try:
return config.get(section, value)
except ConfigParser.NoOptionError:
return False
def push(data, key, element):
"""
Assist in items to a dictionary of lists
"""
if (not element) or (not key):
return
if key in data:
data[key].append(element)
else:
data[key] = [element]
def to_safe(word):
'''
Converts 'bad' characters in a string to underscores so they can
be used as Ansible groups
'''
return re.sub(r"[^A-Za-z0-9\-]", "_", word)
def get_ips(server, access_ip=True):
"""
Returns a list of the server's IPs, or the preferred
access IP
"""
private = []
public = []
address_list = []
# Iterate through each servers network(s), get addresses and get type
addresses = getattr(server, 'addresses', {})
if len(addresses) > 0:
for network in addresses.itervalues():
for address in network:
if address.get('OS-EXT-IPS:type', False) == 'fixed':
private.append(address['addr'])
elif address.get('OS-EXT-IPS:type', False) == 'floating':
public.append(address['addr'])
if not access_ip:
address_list.append(server.accessIPv4)
address_list.extend(private)
address_list.extend(public)
return address_list
access_ip = None
# Append group to list
if server.accessIPv4:
access_ip = server.accessIPv4
if (not access_ip) and public and not (private and prefer_private):
access_ip = public[0]
if private and not access_ip:
access_ip = private[0]
return access_ip
def get_metadata(server):
"""Returns dictionary of all host metadata"""
get_ips(server, False)
results = {}
for key in vars(server):
# Extract value
value = getattr(server, key)
# Generate sanitized key
key = 'os_' + re.sub(r"[^A-Za-z0-9\-]", "_", key).lower()
# Att value to instance result (exclude manager class)
#TODO: maybe use value.__class__ or similar inside of key_name
if key != 'os_manager':
results[key] = value
return results
config = nova_load_config_file() config = nova_load_config_file()
if not config: if not config:
sys.exit('Unable to find configfile in %s' % ', '.join(NOVA_CONFIG_FILES)) sys.exit('Unable to find configfile in %s' % ', '.join(NOVA_CONFIG_FILES))
# Load up connections info based on config and then environment
# variables
username = (get_fallback(config, 'username') or
os.environ.get('OS_USERNAME', None))
api_key = (get_fallback(config, 'api_key') or
os.environ.get('OS_PASSWORD', None))
auth_url = (get_fallback(config, 'auth_url') or
os.environ.get('OS_AUTH_URL', None))
project_id = (get_fallback(config, 'project_id') or
os.environ.get('OS_TENANT_NAME', None))
region_name = (get_fallback(config, 'region_name') or
os.environ.get('OS_REGION_NAME', None))
auth_system = (get_fallback(config, 'auth_system') or
os.environ.get('OS_AUTH_SYSTEM', None))
# Determine what type of IP is preferred to return
prefer_private = False
try:
prefer_private = config.getboolean('openstack', 'prefer_private')
except ConfigParser.NoOptionError:
pass
client = nova_client.Client( client = nova_client.Client(
config.get('openstack', 'version'), version=config.get('openstack', 'version'),
config.get('openstack', 'username'), username=username,
config.get('openstack', 'api_key'), api_key=api_key,
config.get('openstack', 'project_id'), auth_url=auth_url,
config.get('openstack', 'auth_url'), region_name=region_name,
region_name = config.get('openstack', 'region_name'), project_id=project_id,
auth_system = config.get('openstack', 'auth_system') auth_system=auth_system,
service_type=config.get('openstack', 'service_type'),
) )
if len(sys.argv) == 2 and (sys.argv[1] == '--list'): # Default or added list option
groups = {} if (len(sys.argv) == 2 and sys.argv[1] == '--list') or len(sys.argv) == 1:
groups = {'_meta': {'hostvars': {}}}
# Cycle on servers # Cycle on servers
for server in client.servers.list(): for server in client.servers.list():
private = openstack_find_nova_addresses(getattr(server, 'addresses'), 'fixed', 'private') access_ip = get_ips(server)
public = openstack_find_nova_addresses(getattr(server, 'addresses'), 'floating', 'public')
# Push to name group of 1
# Define group (or set to empty string) push(groups, server.name, access_ip)
group = server.metadata['group'] if server.metadata.has_key('group') else 'undefined'
# Run through each metadata item and add instance to it
# Create group if not exist for key, value in server.metadata.iteritems():
if group not in groups: composed_key = to_safe('tag_{0}_{1}'.format(key, value))
groups[group] = [] push(groups, composed_key, access_ip)
# Append group to list # Do special handling of group for backwards compat
if server.accessIPv4: # inventory groups
groups[group].append(server.accessIPv4) group = server.metadata['group'] if 'group' in server.metadata else 'undefined'
continue push(groups, group, access_ip)
if public:
groups[group].append(''.join(public)) # Add vars to _meta key for performance optimization in
continue # Ansible 1.3+
if private: groups['_meta']['hostvars'][access_ip] = get_metadata(server)
groups[group].append(''.join(private))
continue
# Return server list # Return server list
print(json.dumps(groups, sort_keys=True, indent=2)) print(json.dumps(groups, sort_keys=True, indent=2))
@ -105,25 +211,9 @@ if len(sys.argv) == 2 and (sys.argv[1] == '--list'):
elif len(sys.argv) == 3 and (sys.argv[1] == '--host'): elif len(sys.argv) == 3 and (sys.argv[1] == '--host'):
results = {} results = {}
ips = [] ips = []
for instance in client.servers.list(): for server in client.servers.list():
private = openstack_find_nova_addresses(getattr(instance, 'addresses'), 'fixed', 'private') if sys.argv[2] in (get_ips(server) or []):
public = openstack_find_nova_addresses(getattr(instance, 'addresses'), 'floating', 'public') results = get_metadata(server)
ips.append( instance.accessIPv4)
ips.append(''.join(private))
ips.append(''.join(public))
if sys.argv[2] in ips:
for key in vars(instance):
# Extract value
value = getattr(instance, key)
# Generate sanitized key
key = 'os_' + re.sub("[^A-Za-z0-9\-]", "_", key).lower()
# Att value to instance result (exclude manager class)
#TODO: maybe use value.__class__ or similar inside of key_name
if key != 'os_manager':
results[key] = value
print(json.dumps(results, sort_keys=True, indent=2)) print(json.dumps(results, sort_keys=True, indent=2))
sys.exit(0) sys.exit(0)

Loading…
Cancel
Save