Skip to content

Instantly share code, notes, and snippets.

@sivel
Last active January 3, 2016 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sivel/8406271 to your computer and use it in GitHub Desktop.
Save sivel/8406271 to your computer and use it in GitHub Desktop.
My "improvements" on the Ansible rax.py inventory script
@@ -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