Last active
January 3, 2016 03:59
-
-
Save sivel/8406271 to your computer and use it in GitHub Desktop.
My "improvements" on the Ansible rax.py inventory script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -22,9 +22,11 @@ | |
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 | |
@@ -66,11 +68,15 @@ | |
- Jesse Keating <jesse.keating@rackspace.com> | |
- Paul Durivage <paul.durivage@rackspace.com> | |
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 | |
requirements: [ "pyrax" ] | |
examples: | |
- description: List server instances | |
@@ -83,12 +89,14 @@ | |
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 | |
+import ConfigParser | |
+ | |
+from types import NoneType | |
try: | |
import json | |
@@ -98,9 +106,26 @@ | |
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 +135,7 @@ | |
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 +146,7 @@ | |
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,29 +157,44 @@ | |
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) | |
+ for extra_group in server.metadata.get('groups', '').split(','): | |
+ groups[extra_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) | |
- | |
- # Generate sanitized key | |
- key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key) | |
- .lower() | |
- .lstrip('_')) | |
+ for key, value in to_dict(server).items(): | |
hostvars[server.name][key] = value | |
+ for key, value in server.metadata.iteritems(): | |
+ groups['meta_%s_%s' % (key, value)].append(server.name) | |
+ | |
+ groups[server.id].append(server.name) | |
+ groups[server.flavor['id']].append(server.name) | |
+ try: | |
+ groups[images[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.human_id].append(server.name) | |
+ | |
# And finally, add an IP address | |
hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4 | |
+ # localhost hack | |
+ groups['local'].append('localhost') | |
+ groups['localhost'].append('localhost') | |
+ hostvars['localhost'] = { | |
+ 'ansible_python_interpreter': sys.executable, | |
+ 'ansible_connection': 'local' | |
+ } | |
+ | |
if hostvars: | |
groups['_meta'] = {'hostvars': hostvars} | |
print(json.dumps(groups, sort_keys=True, indent=4)) | |
@@ -172,7 +205,7 @@ | |
'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() | |
@@ -184,7 +217,8 @@ | |
try: | |
creds_file = 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: | |
@@ -195,6 +229,11 @@ | |
pyrax.set_setting('identity_type', 'rackspace') | |
+ cfg = ConfigParser.SafeConfigParser(defaults=dict(regions='all')) | |
+ cfg.read(creds_file) | |
+ cfg_regions = os.getenv('RAX_REGION', | |
+ cfg.get('rackspace_cloud', 'regions')) | |
+ | |
try: | |
pyrax.set_credential_file(os.path.expanduser(creds_file)) | |
except Exception, e: | |
@@ -202,7 +241,7 @@ | |
sys.exit(1) | |
regions = [] | |
- for region in os.getenv('RAX_REGION', 'all').split(','): | |
+ for region in cfg_regions.split(','): | |
region = region.strip().upper() | |
if region == 'ALL': | |
regions = pyrax.regions | |
@@ -225,5 +264,6 @@ | |
host(regions, args.host) | |
sys.exit(0) | |
+ | |
if __name__ == '__main__': | |
- main() | |
\ No newline at end of file | |
+ main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment