diff options
| author | Troy Dawson <tdawson@redhat.com> | 2015-06-12 12:49:37 -0500 | 
|---|---|---|
| committer | Troy Dawson <tdawson@redhat.com> | 2015-06-12 12:49:37 -0500 | 
| commit | c650920bc7b0043e59fa3439f48f61d5fa211f2d (patch) | |
| tree | 3e1f882f5bc7fe419f13a134a71927cb6484fa86 /inventory/openstack | |
| parent | 124ca40c134a40b2e6823ab3c4bfe329580d7eaa (diff) | |
| parent | 42806b6745c747843b71eaf08b62aeee5e450ab1 (diff) | |
Merge branch 'master' into prod
Diffstat (limited to 'inventory/openstack')
| -rw-r--r-- | inventory/openstack/hosts/hosts | 1 | ||||
| -rw-r--r-- | inventory/openstack/hosts/nova.ini | 45 | ||||
| -rwxr-xr-x | inventory/openstack/hosts/nova.py | 224 | 
3 files changed, 270 insertions, 0 deletions
| diff --git a/inventory/openstack/hosts/hosts b/inventory/openstack/hosts/hosts new file mode 100644 index 000000000..9cdc31449 --- /dev/null +++ b/inventory/openstack/hosts/hosts @@ -0,0 +1 @@ +localhost ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 connection=local diff --git a/inventory/openstack/hosts/nova.ini b/inventory/openstack/hosts/nova.ini new file mode 100644 index 000000000..4900c4965 --- /dev/null +++ b/inventory/openstack/hosts/nova.ini @@ -0,0 +1,45 @@ +# Ansible OpenStack external inventory script + +[openstack] + +#------------------------------------------------------------------------- +#  Required settings +#------------------------------------------------------------------------- + +# API version +version       = 2 + +# OpenStack nova username +username      = + +# OpenStack nova api_key or password +api_key       = + +# OpenStack nova auth_url +auth_url      = + +# OpenStack nova project_id or tenant name +project_id    = + +#------------------------------------------------------------------------- +#  Optional settings +#------------------------------------------------------------------------- + +# Authentication system +# auth_system = keystone + +# Serverarm region name to use +# region_name   = + +# Specify a preference for public or private IPs (public is default) +# prefer_private = False + +# What service type (required for newer nova client) +# service_type = compute + + +# TODO: Some other options +# insecure      = +# endpoint_type = +# extensions    = +# service_name  = diff --git a/inventory/openstack/hosts/nova.py b/inventory/openstack/hosts/nova.py new file mode 100755 index 000000000..d5bd8d1ee --- /dev/null +++ b/inventory/openstack/hosts/nova.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python2 + +# pylint: skip-file + +# (c) 2012, Marco Vito Moscaritolo <marco@agavee.com> +# +# 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 <http://www.gnu.org/licenses/>. + +import sys +import re +import os +import ConfigParser +from novaclient import client as nova_client + +try: +    import json +except ImportError: +    import simplejson as json + +################################################### +# executed with no parameters, return the list of +# all groups and hosts + +NOVA_CONFIG_FILES = [os.getcwd() + "/nova.ini", +                     os.path.expanduser(os.environ.get('ANSIBLE_CONFIG', "~/nova.ini")), +                     "/etc/ansible/nova.ini"] + +NOVA_DEFAULTS = { +    'auth_system': None, +    'region_name': None, +    'service_type': 'compute', +} + + +def nova_load_config_file(): +    p = ConfigParser.SafeConfigParser(NOVA_DEFAULTS) + +    for path in NOVA_CONFIG_FILES: +        if os.path.exists(path): +            p.read(path) +            return p + +    return None + + +def get_fallback(config, value, section="openstack"): +    """ +    Get value from config object and return the value +    or false +    """ +    try: +        return config.get(section, value) +    except ConfigParser.NoOptionError: +        return False + + +def push(data, key, element): +    """ +    Assist in items to a dictionary of lists +    """ +    if (not element) or (not key): +        return + +    if key in data: +        data[key].append(element) +    else: +        data[key] = [element] + + +def to_safe(word): +    ''' +    Converts 'bad' characters in a string to underscores so they can +    be used as Ansible groups +    ''' +    return re.sub(r"[^A-Za-z0-9\-]", "_", word) + + +def get_ips(server, access_ip=True): +    """ +    Returns a list of the server's IPs, or the preferred +    access IP +    """ +    private = [] +    public = [] +    address_list = [] +    # Iterate through each servers network(s), get addresses and get type +    addresses = getattr(server, 'addresses', {}) +    if len(addresses) > 0: +        for network in addresses.itervalues(): +            for address in network: +                if address.get('OS-EXT-IPS:type', False) == 'fixed': +                    private.append(address['addr']) +                elif address.get('OS-EXT-IPS:type', False) == 'floating': +                    public.append(address['addr']) + +    if not access_ip: +        address_list.append(server.accessIPv4) +        address_list.extend(private) +        address_list.extend(public) +        return address_list + +    access_ip = None +    # Append group to list +    if server.accessIPv4: +        access_ip = server.accessIPv4 +    if (not access_ip) and public and not (private and prefer_private): +        access_ip = public[0] +    if private and not access_ip: +        access_ip = private[0] + +    return access_ip + + +def get_metadata(server): +    """Returns dictionary of all host metadata""" +    get_ips(server, False) +    results = {} +    for key in vars(server): +        # Extract value +        value = getattr(server, key) + +        # Generate sanitized key +        key = 'os_' + re.sub(r"[^A-Za-z0-9\-]", "_", key).lower() + +        # Att value to instance result (exclude manager class) +        #TODO: maybe use value.__class__ or similar inside of key_name +        if key != 'os_manager': +            results[key] = value +    return results + +config = nova_load_config_file() +if not config: +    sys.exit('Unable to find configfile in %s' % ', '.join(NOVA_CONFIG_FILES)) + +# Load up connections info based on config and then environment +# variables +username = (get_fallback(config, 'username') or +            os.environ.get('OS_USERNAME', None)) +api_key = (get_fallback(config, 'api_key') or +           os.environ.get('OS_PASSWORD', None)) +auth_url = (get_fallback(config, 'auth_url') or +            os.environ.get('OS_AUTH_URL', None)) +project_id = (get_fallback(config, 'project_id') or +              os.environ.get('OS_TENANT_NAME', None)) +region_name = (get_fallback(config, 'region_name') or +               os.environ.get('OS_REGION_NAME', None)) +auth_system = (get_fallback(config, 'auth_system') or +               os.environ.get('OS_AUTH_SYSTEM', None)) + +# Determine what type of IP is preferred to return +prefer_private = False +try: +    prefer_private = config.getboolean('openstack', 'prefer_private') +except ConfigParser.NoOptionError: +    pass + +client = nova_client.Client( +    version=config.get('openstack', 'version'), +    username=username, +    api_key=api_key, +    auth_url=auth_url, +    region_name=region_name, +    project_id=project_id, +    auth_system=auth_system, +    service_type=config.get('openstack', 'service_type'), +) + +# Default or added list option +if (len(sys.argv) == 2 and sys.argv[1] == '--list') or len(sys.argv) == 1: +    groups = {'_meta': {'hostvars': {}}} +    # Cycle on servers +    for server in client.servers.list(): +        access_ip = get_ips(server) + +        # Push to name group of 1 +        push(groups, server.name, access_ip) + +        # Run through each metadata item and add instance to it +        for key, value in server.metadata.iteritems(): +            composed_key = to_safe('tag_{0}_{1}'.format(key, value)) +            push(groups, composed_key, access_ip) + +        # Do special handling of group for backwards compat +        # inventory groups +        group = server.metadata['group'] if 'group' in server.metadata else 'undefined' +        push(groups, group, access_ip) + +        # Add vars to _meta key for performance optimization in +        # Ansible 1.3+ +        groups['_meta']['hostvars'][access_ip] = get_metadata(server) + +    # Return server list +    print(json.dumps(groups, sort_keys=True, indent=2)) +    sys.exit(0) + +##################################################### +# executed with a hostname as a parameter, return the +# variables for that host + +elif len(sys.argv) == 3 and (sys.argv[1] == '--host'): +    results = {} +    ips = [] +    for server in client.servers.list(): +        if sys.argv[2] in (get_ips(server) or []): +            results = get_metadata(server) +    print(json.dumps(results, sort_keys=True, indent=2)) +    sys.exit(0) + +else: +    print "usage: --list  ..OR.. --host <hostname>" +    sys.exit(1) | 
