diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 62872ee1d1..85490ea911 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -810,7 +810,7 @@ class RunInventoryUpdate(BaseTask): ec2_path = self.get_path_to('..', 'plugins', 'inventory', 'ec2.py') args.append(ec2_path) elif inventory_source.source == 'rackspace': - rax_path = self.get_path_to('..', 'plugins', 'inventory', 'rax2.py') + rax_path = self.get_path_to('..', 'plugins', 'inventory', 'rax.py') args.append(rax_path) elif inventory_source.source == 'file': args.append(inventory_source.source_path) diff --git a/awx/plugins/inventory/rax.py b/awx/plugins/inventory/rax.py index a3787f154a..745def7720 100755 --- a/awx/plugins/inventory/rax.py +++ b/awx/plugins/inventory/rax.py @@ -46,7 +46,7 @@ description: rax_name rax_created rax_tenant_id - rax__loaded + rax_loaded where some item can have nested structure. - credentials are set in a credentials file @@ -57,28 +57,38 @@ options: - File to find the Rackspace Public Cloud credentials in required: true default: null - region_name: + region: description: - - Region name to use in request - required: false - default: DFW -author: Jesse Keating + - An optional value to narrow inventory scope, i.e. DFW, ORD, IAD, LON + required: false + default: null +authors: + - Jesse Keating + - Paul Durivage notes: - - Two environment variables need to be set, RAX_CREDS_FILE and RAX_REGION. - - RAX_CREDS_FILE points to a credentials file appropriate for pyrax - - RAX_REGION defines a Rackspace Public Cloud region (DFW, ORD, LON, ...) + - 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 requirements: [ "pyrax" ] examples: - description: List server instances + code: RAX_CREDS_FILE=~/.raxpub rax.py --list + - description: List servers in ORD datacenter only code: RAX_CREDS_FILE=~/.raxpub RAX_REGION=ORD rax.py --list - - description: List server instance properties - code: RAX_CREDS_FILE=~/.raxpub RAX_REGION=ORD rax.py --host + - description: List servers in ORD and DFW datacenters + code: RAX_CREDS_FILE=~/.raxpub RAX_REGION=ORD,DFW rax.py --list + - description: Get server details for server named "server.example.com" + code: RAX_CREDS_FILE=~/.raxpub rax.py --host server.example.com ''' import sys import re import os + import argparse +import collections try: import json @@ -91,68 +101,129 @@ except ImportError: print('pyrax required for this module') sys.exit(1) -# Setup the parser -parser = argparse.ArgumentParser(description='List active instances', - epilog='List by itself will list all the active \ - instances. Listing a specific instance will show \ - all the details about the instance.') -parser.add_argument('--list', action='store_true', default=True, - help='List active servers') -parser.add_argument('--host', - help='List details about the specific host (IP address)') +def host(regions, hostname): + hostvars = {} -args = parser.parse_args() + for region in regions: + # Connect to the region + 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) -# setup the auth -try: - creds_file = os.environ['RAX_CREDS_FILE'] - region = os.environ['RAX_REGION'] -except KeyError, e: - sys.stderr.write('Unable to load %s\n' % e.message) - sys.exit(1) + # Generate sanitized key + key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key) + .lower() + .lstrip("_")) + hostvars[key] = value -pyrax.set_setting('identity_type', 'rackspace') + # And finally, add an IP address + hostvars['ansible_ssh_host'] = server.accessIPv4 + print(json.dumps(hostvars, sort_keys=True, indent=4)) -try: - pyrax.set_credential_file(os.path.expanduser(creds_file), - region=region) -except Exception, e: - sys.stderr.write("%s: %s\n" % (e, e.message)) - sys.exit(1) -# Execute the right stuff -if not args.host: - groups = {} +def _list(regions): + groups = collections.defaultdict(list) + hostvars = collections.defaultdict(dict) - # Cycle on servers - for server in pyrax.cloudservers.list(): - # Define group (or set to empty string) - try: - group = server.metadata['group'] - except KeyError: - group = 'undefined' + # Go through all the regions looking for servers + for region in regions: + # Connect to the region + cs = pyrax.connect_to_cloudservers(region=region) + for server in cs.servers.list(): + # Create a group on region + groups[region].append(server.name) - # Create group if not exist and add the server - groups.setdefault(group, []).append(server.accessIPv4) + # 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 + groups[group].append(server.name) - # Return server list - print(json.dumps(groups)) + # 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('_')) + hostvars[server.name][key] = value + + # And finally, add an IP address + hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4 + + if hostvars: + groups['_meta'] = {'hostvars': hostvars} + print(json.dumps(groups, sort_keys=True, indent=4)) + + +def parse_args(): + parser = argparse.ArgumentParser(description='Ansible Rackspace Cloud ' + 'inventory module') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--list', action='store_true', + help='List active servers') + group.add_argument('--host', help='List details about the specific host') + return parser.parse_args() + + +def setup(): + default_creds_file = os.path.expanduser('~/.rackspace_cloud_credentials') + + # Attempt to grab credentials from environment first + try: + creds_file = os.environ['RAX_CREDS_FILE'] + except KeyError, e: + # 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: + 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') + + try: + pyrax.set_credential_file(os.path.expanduser(creds_file)) + 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) + + return regions + + +def main(): + args = parse_args() + regions = setup() + if args.list: + _list(regions) + elif args.host: + host(regions, args.host) sys.exit(0) -# Get the deets for the instance asked for -results = {} -# This should be only one, but loop anyway -for server in pyrax.cloudservers.list(): - if server.accessIPv4 == args.host: - for key in [key for key in vars(server) if - key not in ('manager', '_info')]: - # Extract value - value = getattr(server, key) - - # Generate sanitized key - key = 'rax_' + re.sub("[^A-Za-z0-9\-]", "_", key).lower() - results[key] = value - -print(json.dumps(results)) -sys.exit(0) +if __name__ == '__main__': + main() diff --git a/awx/plugins/inventory/rax2.py b/awx/plugins/inventory/rax2.py deleted file mode 100755 index cc23d0de73..0000000000 --- a/awx/plugins/inventory/rax2.py +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env python - -# (c) 2013, Jesse Keating -# -# This file is part of Ansible, -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -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 - - | - When run against a specific host, this script returns the following variables: - rax_os-ext-sts_task_state - rax_addresses - rax_links - rax_image - rax_os-ext-sts_vm_state - rax_flavor - rax_id - rax_rax-bandwidth_bandwidth - rax_user_id - rax_os-dcf_diskconfig - rax_accessipv4 - rax_accessipv6 - rax_progress - rax_os-ext-sts_power_state - rax_metadata - rax_status - rax_updated - rax_hostid - rax_name - rax_created - rax_tenant_id - rax__loaded - - where some item can have nested structure. - - credentials are set in a credentials file -version_added: None -options: - creds_file: - description: - - File to find the Rackspace Public Cloud credentials in - required: true - default: null -authors: - - Jesse Keating - - Paul Durivage -notes: - - One environment variable needs to be set: RAX_CREDS_FILE. - - RAX_CREDS_FILE points to a credentials file appropriate for pyrax. - - Another optional environment variable may be set: RAX_REGION. - - RAX_REGION defines one or more Rackspace Public Cloud regions (DFW, ORD, LON, ...) - as a comma-separated list of region names. If set to "all" or omitted, all - regions in pyrax.regions will be used. - - See https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating -requirements: [ "pyrax" ] -examples: - - description: List server instances - code: RAX_CREDS_FILE=~/.raxpub rax.py --list - - description: List server instances only in DFW and ORD regions - code: RAX_CREDS_FILE=~/.raxpub RAX_REGION=DFW,ORD rax.py --list -''' - -import sys -import re -import os -import argparse -import collections - -try: - import json -except: - import simplejson as json - -try: - import pyrax -except ImportError: - print('pyrax required for this module') - sys.exit(1) - - -def host(regions, hostname): - hostvars = {} - - for region in regions: - # Connect to the region - 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("_")) - hostvars[key] = value - - # And finally, add an IP address - hostvars['ansible_ssh_host'] = server.accessIPv4 - print(json.dumps(hostvars, sort_keys=True, indent=4)) - - -def _list(regions): - groups = collections.defaultdict(list) - hostvars = collections.defaultdict(dict) - - # Go through all the regions looking for servers - for region in regions: - # Connect to the region - cs = pyrax.connect_to_cloudservers(region=region) - for server in cs.servers.list(): - # Create a group on region - groups[region].append(server.name) - - # Anything we can discern from the hostname? - try: - subdom = server.name.split('.')[0] - except IndexError: - pass - else: - for name in ('web', 'db', 'sql', 'lb', 'app'): - if name in subdom: - groups[name].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 - 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) - - # Generate sanitized key - key = 'rax_' + (re.sub("[^A-Za-z0-9\-]", "_", key) - .lower() - .lstrip('_')) - hostvars[server.name][key] = value - - # And finally, add an IP address - hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4 - - if hostvars: - groups['_meta'] = {'hostvars': hostvars} - print(json.dumps(groups, sort_keys=True, indent=4)) - - -def parse_args(): - parser = argparse.ArgumentParser(description='Ansible Rackspace Cloud ' - 'inventory module') - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('--list', action='store_true', - help='List active servers') - group.add_argument('--host', help='List details about the specific host') - return parser.parse_args() - - -def setup(): - try: - creds_file = os.environ['RAX_CREDS_FILE'] - region = os.getenv('RAX_REGION') or 'all' - except KeyError, e: - sys.stderr.write('Unable to load environment ' - 'variable %s\n' % e.message) - sys.exit(1) - - pyrax.set_setting('identity_type', 'rackspace') - - try: - pyrax.set_credential_file(os.path.expanduser(creds_file)) - except Exception, e: - sys.stderr.write("%s: %s\n" % (e, e.message)) - sys.exit(1) - - regions = [] - for region in region.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 - - -def main(): - args = parse_args() - regions = setup() - if args.list: - _list(regions) - elif args.host: - host(regions, args.host) - sys.exit(0) - -if __name__ == '__main__': - main()