Merge pull request #6603 from sivel/rax-inventory-improvements

rax.py inventory script improvements
This commit is contained in:
Michael DeHaan 2014-04-03 17:03:04 -04:00
commit df0a4b735a

View file

@ -22,9 +22,11 @@ DOCUMENTATION = '''
inventory: rax
short_description: Rackspace Public Cloud external inventory script
description:
- Generates inventory that Ansible can understand by making API request to Rackspace Public Cloud API
- Generates inventory that Ansible can understand by making API request to
Rackspace Public Cloud API
- |
When run against a specific host, this script returns the following variables:
When run against a specific host, this script returns the following
variables:
rax_os-ext-sts_task_state
rax_addresses
rax_links
@ -65,12 +67,23 @@ options:
authors:
- Jesse Keating <jesse.keating@rackspace.com>
- Paul Durivage <paul.durivage@rackspace.com>
- Matt Martz <matt@sivel.net>
notes:
- RAX_CREDS_FILE is an optional environment variable that points to a pyrax-compatible credentials file.
- If RAX_CREDS_FILE is not supplied, rax.py will look for a credentials file at ~/.rackspace_cloud_credentials.
- RAX_CREDS_FILE is an optional environment variable that points to a
pyrax-compatible credentials file.
- If RAX_CREDS_FILE is not supplied, rax.py will look for a credentials file
at ~/.rackspace_cloud_credentials.
- See https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating
- RAX_REGION is an optional environment variable to narrow inventory search scope
- RAX_REGION, if used, needs a value like ORD, DFW, SYD (a Rackspace datacenter) and optionally accepts a comma-separated list
- RAX_REGION is an optional environment variable to narrow inventory search
scope
- RAX_REGION, if used, needs a value like ORD, DFW, SYD (a Rackspace
datacenter) and optionally accepts a comma-separated list
- RAX_ENV is an environment variable that will use an environment as
configured in ~/.pyrax.cfg, see
https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#pyrax-configuration
- RAX_META_PREFIX is an environment variable that changes the prefix used
for meta key/value groups. For compatibility with ec2.py set to
RAX_META_PREFIX=tag
requirements: [ "pyrax" ]
examples:
- description: List server instances
@ -83,13 +96,14 @@ examples:
code: RAX_CREDS_FILE=~/.raxpub rax.py --host server.example.com
'''
import sys
import re
import os
import re
import sys
import argparse
import collections
from types import NoneType
try:
import json
except:
@ -98,9 +112,26 @@ except:
try:
import pyrax
except ImportError:
print('pyrax required for this module')
print('pyrax is required for this module')
sys.exit(1)
NON_CALLABLES = (basestring, bool, dict, int, list, NoneType)
def rax_slugify(value):
return 'rax_%s' % (re.sub('[^\w-]', '_', value).lower().lstrip('_'))
def to_dict(obj):
instance = {}
for key in dir(obj):
value = getattr(obj, key)
if (isinstance(value, NON_CALLABLES) and not key.startswith('_')):
key = rax_slugify(key)
instance[key] = value
return instance
def host(regions, hostname):
hostvars = {}
@ -110,15 +141,7 @@ def host(regions, hostname):
cs = pyrax.connect_to_cloudservers(region=region)
for server in cs.servers.list():
if server.name == hostname:
keys = [key for key in vars(server) if key not in ('manager', '_info')]
for key in keys:
# Extract value
value = getattr(server, key)
# Generate sanitized key
key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key)
.lower()
.lstrip("_"))
for key, value in to_dict(server).items():
hostvars[key] = value
# And finally, add an IP address
@ -129,6 +152,7 @@ def host(regions, hostname):
def _list(regions):
groups = collections.defaultdict(list)
hostvars = collections.defaultdict(dict)
images = {}
# Go through all the regions looking for servers
for region in regions:
@ -139,26 +163,39 @@ def _list(regions):
groups[region].append(server.name)
# Check if group metadata key in servers' metadata
try:
group = server.metadata['group']
except KeyError:
pass
else:
# Create group if not exist and add the server
group = server.metadata.get('group')
if group:
groups[group].append(server.name)
# Add host metadata
keys = [key for key in vars(server) if key not in ('manager', '_info')]
for key in keys:
# Extract value
value = getattr(server, key)
for extra_group in server.metadata.get('groups', '').split(','):
groups[extra_group].append(server.name)
# Generate sanitized key
key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key)
.lower()
.lstrip('_'))
# Add host metadata
for key, value in to_dict(server).items():
hostvars[server.name][key] = value
hostvars[server.name]['rax_region'] = region
for key, value in server.metadata.iteritems():
prefix = os.getenv('RAX_META_PREFIX', 'meta')
groups['%s_%s_%s' % (prefix, key, value)].append(server.name)
groups['instance-%s' % server.id].append(server.name)
groups['flavor-%s' % server.flavor['id']].append(server.name)
try:
imagegroup = 'image-%s' % images[server.image['id']]
groups[imagegroup].append(server.name)
groups['image-%s' % server.image['id']].append(server.name)
except KeyError:
try:
image = cs.images.get(server.image['id'])
except cs.exceptions.NotFound:
groups['image-%s' % server.image['id']].append(server.name)
else:
images[image.id] = image.human_id
groups['image-%s' % image.human_id].append(server.name)
groups['image-%s' % server.image['id']].append(server.name)
# And finally, add an IP address
hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4
@ -172,7 +209,7 @@ def parse_args():
'inventory module')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--list', action='store_true',
help='List active servers')
help='List active servers')
group.add_argument('--host', help='List details about the specific host')
return parser.parse_args()
@ -180,38 +217,54 @@ def parse_args():
def setup():
default_creds_file = os.path.expanduser('~/.rackspace_cloud_credentials')
env = os.getenv('RAX_ENV', None)
if env:
pyrax.set_environment(env)
keyring_username = pyrax.get_setting('keyring_username')
# Attempt to grab credentials from environment first
try:
creds_file = os.environ['RAX_CREDS_FILE']
creds_file = os.path.expanduser(os.environ['RAX_CREDS_FILE'])
except KeyError, e:
# But if that fails, use the default location of ~/.rackspace_cloud_credentials
# But if that fails, use the default location of
# ~/.rackspace_cloud_credentials
if os.path.isfile(default_creds_file):
creds_file = default_creds_file
else:
elif not keyring_username:
sys.stderr.write('No value in environment variable %s and/or no '
'credentials file at %s\n'
% (e.message, default_creds_file))
sys.exit(1)
pyrax.set_setting('identity_type', 'rackspace')
identity_type = pyrax.get_setting('identity_type')
pyrax.set_setting('identity_type', identity_type or 'rackspace')
region = pyrax.get_setting('region')
try:
pyrax.set_credential_file(os.path.expanduser(creds_file))
if keyring_username:
pyrax.keyring_auth(keyring_username, region=region)
else:
pyrax.set_credential_file(creds_file, region=region)
except Exception, e:
sys.stderr.write("%s: %s\n" % (e, e.message))
sys.exit(1)
regions = []
for region in os.getenv('RAX_REGION', 'all').split(','):
region = region.strip().upper()
if region == 'ALL':
regions = pyrax.regions
break
elif region not in pyrax.regions:
sys.stderr.write('Unsupported region %s' % region)
sys.exit(1)
elif region not in regions:
regions.append(region)
if region:
regions.append(region)
else:
for region in os.getenv('RAX_REGION', 'all').split(','):
region = region.strip().upper()
if region == 'ALL':
regions = pyrax.regions
break
elif region not in pyrax.regions:
sys.stderr.write('Unsupported region %s' % region)
sys.exit(1)
elif region not in regions:
regions.append(region)
return regions
@ -225,5 +278,6 @@ def main():
host(regions, args.host)
sys.exit(0)
if __name__ == '__main__':
main()
main()