Improvements to the rax inventory script
This commit is contained in:
parent
67517e96d3
commit
5142297076
1 changed files with 105 additions and 51 deletions
|
@ -22,9 +22,11 @@ DOCUMENTATION = '''
|
||||||
inventory: rax
|
inventory: rax
|
||||||
short_description: Rackspace Public Cloud external inventory script
|
short_description: Rackspace Public Cloud external inventory script
|
||||||
description:
|
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_os-ext-sts_task_state
|
||||||
rax_addresses
|
rax_addresses
|
||||||
rax_links
|
rax_links
|
||||||
|
@ -65,12 +67,23 @@ options:
|
||||||
authors:
|
authors:
|
||||||
- Jesse Keating <jesse.keating@rackspace.com>
|
- Jesse Keating <jesse.keating@rackspace.com>
|
||||||
- Paul Durivage <paul.durivage@rackspace.com>
|
- Paul Durivage <paul.durivage@rackspace.com>
|
||||||
|
- Matt Martz <matt@sivel.net>
|
||||||
notes:
|
notes:
|
||||||
- RAX_CREDS_FILE is an optional environment variable that points to a pyrax-compatible credentials file.
|
- RAX_CREDS_FILE is an optional environment variable that points to a
|
||||||
- If RAX_CREDS_FILE is not supplied, rax.py will look for a credentials file at ~/.rackspace_cloud_credentials.
|
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
|
- 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 is an optional environment variable to narrow inventory search
|
||||||
- RAX_REGION, if used, needs a value like ORD, DFW, SYD (a Rackspace datacenter) and optionally accepts a comma-separated list
|
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" ]
|
requirements: [ "pyrax" ]
|
||||||
examples:
|
examples:
|
||||||
- description: List server instances
|
- description: List server instances
|
||||||
|
@ -83,13 +96,14 @@ examples:
|
||||||
code: RAX_CREDS_FILE=~/.raxpub rax.py --host server.example.com
|
code: RAX_CREDS_FILE=~/.raxpub rax.py --host server.example.com
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
from types import NoneType
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
except:
|
except:
|
||||||
|
@ -98,9 +112,26 @@ except:
|
||||||
try:
|
try:
|
||||||
import pyrax
|
import pyrax
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print('pyrax required for this module')
|
print('pyrax is required for this module')
|
||||||
sys.exit(1)
|
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):
|
def host(regions, hostname):
|
||||||
hostvars = {}
|
hostvars = {}
|
||||||
|
@ -110,15 +141,7 @@ def host(regions, hostname):
|
||||||
cs = pyrax.connect_to_cloudservers(region=region)
|
cs = pyrax.connect_to_cloudservers(region=region)
|
||||||
for server in cs.servers.list():
|
for server in cs.servers.list():
|
||||||
if server.name == hostname:
|
if server.name == hostname:
|
||||||
keys = [key for key in vars(server) if key not in ('manager', '_info')]
|
for key, value in to_dict(server).items():
|
||||||
for key in keys:
|
|
||||||
# Extract value
|
|
||||||
value = getattr(server, key)
|
|
||||||
|
|
||||||
# Generate sanitized key
|
|
||||||
key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key)
|
|
||||||
.lower()
|
|
||||||
.lstrip("_"))
|
|
||||||
hostvars[key] = value
|
hostvars[key] = value
|
||||||
|
|
||||||
# And finally, add an IP address
|
# And finally, add an IP address
|
||||||
|
@ -129,6 +152,7 @@ def host(regions, hostname):
|
||||||
def _list(regions):
|
def _list(regions):
|
||||||
groups = collections.defaultdict(list)
|
groups = collections.defaultdict(list)
|
||||||
hostvars = collections.defaultdict(dict)
|
hostvars = collections.defaultdict(dict)
|
||||||
|
images = {}
|
||||||
|
|
||||||
# Go through all the regions looking for servers
|
# Go through all the regions looking for servers
|
||||||
for region in regions:
|
for region in regions:
|
||||||
|
@ -139,26 +163,39 @@ def _list(regions):
|
||||||
groups[region].append(server.name)
|
groups[region].append(server.name)
|
||||||
|
|
||||||
# Check if group metadata key in servers' metadata
|
# Check if group metadata key in servers' metadata
|
||||||
try:
|
group = server.metadata.get('group')
|
||||||
group = server.metadata['group']
|
if group:
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
# Create group if not exist and add the server
|
|
||||||
groups[group].append(server.name)
|
groups[group].append(server.name)
|
||||||
|
|
||||||
# Add host metadata
|
for extra_group in server.metadata.get('groups', '').split(','):
|
||||||
keys = [key for key in vars(server) if key not in ('manager', '_info')]
|
groups[extra_group].append(server.name)
|
||||||
for key in keys:
|
|
||||||
# Extract value
|
|
||||||
value = getattr(server, key)
|
|
||||||
|
|
||||||
# Generate sanitized key
|
# Add host metadata
|
||||||
key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key)
|
for key, value in to_dict(server).items():
|
||||||
.lower()
|
|
||||||
.lstrip('_'))
|
|
||||||
hostvars[server.name][key] = value
|
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
|
# And finally, add an IP address
|
||||||
hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4
|
hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4
|
||||||
|
|
||||||
|
@ -180,28 +217,44 @@ def parse_args():
|
||||||
def setup():
|
def setup():
|
||||||
default_creds_file = os.path.expanduser('~/.rackspace_cloud_credentials')
|
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
|
# Attempt to grab credentials from environment first
|
||||||
try:
|
try:
|
||||||
creds_file = os.environ['RAX_CREDS_FILE']
|
creds_file = os.path.expanduser(os.environ['RAX_CREDS_FILE'])
|
||||||
except KeyError, e:
|
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):
|
if os.path.isfile(default_creds_file):
|
||||||
creds_file = 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 '
|
sys.stderr.write('No value in environment variable %s and/or no '
|
||||||
'credentials file at %s\n'
|
'credentials file at %s\n'
|
||||||
% (e.message, default_creds_file))
|
% (e.message, default_creds_file))
|
||||||
sys.exit(1)
|
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:
|
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:
|
except Exception, e:
|
||||||
sys.stderr.write("%s: %s\n" % (e, e.message))
|
sys.stderr.write("%s: %s\n" % (e, e.message))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
regions = []
|
regions = []
|
||||||
|
if region:
|
||||||
|
regions.append(region)
|
||||||
|
else:
|
||||||
for region in os.getenv('RAX_REGION', 'all').split(','):
|
for region in os.getenv('RAX_REGION', 'all').split(','):
|
||||||
region = region.strip().upper()
|
region = region.strip().upper()
|
||||||
if region == 'ALL':
|
if region == 'ALL':
|
||||||
|
@ -225,5 +278,6 @@ def main():
|
||||||
host(regions, args.host)
|
host(regions, args.host)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
Loading…
Reference in a new issue