From 2bd927fd818c3cd645d5d21f4550a47b4ecb1dd2 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Wed, 22 Oct 2014 14:40:20 -0500 Subject: [PATCH] Support RackConnect v3 by allowing a network to be specified for use in determining ansible_ssh_host --- plugins/inventory/rax.py | 149 ++++++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 55 deletions(-) mode change 100755 => 100644 plugins/inventory/rax.py diff --git a/plugins/inventory/rax.py b/plugins/inventory/rax.py old mode 100755 new mode 100644 index 457c20962a..87b7f9cafc --- a/plugins/inventory/rax.py +++ b/plugins/inventory/rax.py @@ -1,8 +1,10 @@ #!/usr/bin/env python -# (c) 2013, Jesse Keating +# (c) 2013, Jesse Keating , +# Matt Martz # -# This file is part of Ansible, +# 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 @@ -17,16 +19,20 @@ # 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 Cloud Inventory + +Authors: + Jesse Keating , + Matt Martz + + +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: + + When run against a specific host, this script returns variables similar to: rax_os-ext-sts_task_state rax_addresses rax_links @@ -50,63 +56,67 @@ description: 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 - region: - description: - - An optional value to narrow inventory scope, i.e. DFW, ORD, IAD, LON - required: false - default: null -authors: - - Jesse Keating - - Paul Durivage - - Matt Martz -notes: - - RAX_CREDS_FILE is an optional environment variable that points to a +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. - - 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_ENV is an environment variable that will use an environment as + + If RAX_CREDS_FILE is not supplied, rax.py will look for a credentials file + at ~/.rackspace_cloud_credentials. It uses the Rackspace Python SDK, and + therefore requires a file formatted per the SDK's specifications. 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_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 + https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md + + 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 - 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 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 -''' + + RAX_ACCESS_NETWORK is an environment variable that will tell the inventory + script to use a specific server network to determine the ansible_ssh_host + value. If no address is found, ansible_ssh_host will not be set. + + RAX_ACCESS_IP_VERSION is an environment variable related to + RAX_ACCESS_NETWORK that will attempt to determine the ansible_ssh_host + value for either IPv4 or IPv6. If no address is found, ansible_ssh_host + will not be set. Acceptable values are: 4 or 6. Values other than 4 or 6 + will be ignored, and 4 will be used. + +Examples: + List server instances + $ RAX_CREDS_FILE=~/.raxpub rax.py --list + + List servers in ORD datacenter only + $ RAX_CREDS_FILE=~/.raxpub RAX_REGION=ORD rax.py --list + + List servers in ORD and DFW datacenters + $ RAX_CREDS_FILE=~/.raxpub RAX_REGION=ORD,DFW rax.py --list + + Get server details for server named "server.example.com" + $ RAX_CREDS_FILE=~/.raxpub rax.py --host server.example.com + + Use the instance private IP to connect (instead of public IP) + $ RAX_CREDS_FILE=~/.raxpub RAX_PRIVATE_IP=yes rax.py --list +""" import os import re import sys import argparse +import warnings import collections from types import NoneType try: import json -except: +except ImportError: import simplejson as json try: @@ -126,7 +136,7 @@ def to_dict(obj): instance = {} for key in dir(obj): value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): + if isinstance(value, NON_CALLABLES) and not key.startswith('_'): key = rax_slugify(key) instance[key] = value @@ -154,10 +164,25 @@ def _list(regions): hostvars = collections.defaultdict(dict) images = {} + network = os.getenv('RAX_ACCESS_NETWORK', 'public') + try: + ip_version = int(os.getenv('RAX_ACCESS_IP_VERSION', 4)) + except: + ip_version = 4 + else: + if ip_version not in [4, 6]: + ip_version = 4 + # Go through all the regions looking for servers for region in regions: # Connect to the region cs = pyrax.connect_to_cloudservers(region=region) + if isinstance(cs, NoneType): + warnings.warn( + 'Connecting to Rackspace region "%s" has caused Pyrax to ' + 'return a NoneType. Is this a valid region?' % region, + RuntimeWarning) + continue for server in cs.servers.list(): # Create a group on region groups[region].append(server.name) @@ -198,7 +223,21 @@ def _list(regions): groups['image-%s' % server.image['id']].append(server.name) # And finally, add an IP address - hostvars[server.name]['ansible_ssh_host'] = server.accessIPv4 + ansible_ssh_host = None + # use accessIPv[46] instead of looping address for 'public' + if network == 'public': + if ip_version == 6 and server.accessIPv6: + ansible_ssh_host = server.accessIPv6 + elif server.accessIPv4: + ansible_ssh_host = server.accessIPv4 + else: + addresses = server.addresses.get(network, []) + for address in addresses: + if address.get('version') == ip_version: + ansible_ssh_host = address.get('addr') + break + if ansible_ssh_host: + hostvars[server.name]['ansible_ssh_host'] = ansible_ssh_host if hostvars: groups['_meta'] = {'hostvars': hostvars}