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 | |
parent | 124ca40c134a40b2e6823ab3c4bfe329580d7eaa (diff) | |
parent | 42806b6745c747843b71eaf08b62aeee5e450ab1 (diff) | |
download | openshift-c650920bc7b0043e59fa3439f48f61d5fa211f2d.tar.gz openshift-c650920bc7b0043e59fa3439f48f61d5fa211f2d.tar.bz2 openshift-c650920bc7b0043e59fa3439f48f61d5fa211f2d.tar.xz openshift-c650920bc7b0043e59fa3439f48f61d5fa211f2d.zip |
Merge branch 'master' into prod
Diffstat (limited to 'inventory')
-rw-r--r-- | inventory/byo/hosts | 11 | ||||
-rwxr-xr-x | inventory/libvirt/hosts/libvirt_generic.py | 95 | ||||
-rwxr-xr-x | inventory/multi_ec2.py | 13 | ||||
-rw-r--r-- | inventory/openshift-ansible-inventory.spec | 13 | ||||
-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 |
7 files changed, 351 insertions, 51 deletions
diff --git a/inventory/byo/hosts b/inventory/byo/hosts index 728eec8aa..4d4da5468 100644 --- a/inventory/byo/hosts +++ b/inventory/byo/hosts @@ -17,20 +17,23 @@ ansible_ssh_user=root deployment_type=enterprise # Pre-release registry URL -openshift_registry_url=docker-buildvm-rhose.usersys.redhat.com:5000/openshift3_beta/ose-${component}:${version} +oreg_url=docker-buildvm-rhose.usersys.redhat.com:5000/openshift3_beta/ose-${component}:${version} # Pre-release additional repo -#openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterprise/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] -openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterpriseErrata/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] +openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterprise/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] +#openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterpriseErrata/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] # Origin copr repo #openshift_additional_repos=[{'id': 'openshift-origin-copr', 'name': 'OpenShift Origin COPR', 'baseurl': 'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/epel-7-$basearch/', 'enabled': 1, 'gpgcheck': 1, gpgkey: 'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/pubkey.gpg'}] +# htpasswd auth +#openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/openshift/htpasswd'}] + # host group for masters [masters] ose3-master-ansible.test.example.com # host group for nodes [nodes] -ose3-master-ansible.test.example.com openshift_node_labels="{'region': 'infra', 'zone': 'default'}" +#ose3-master-ansible.test.example.com openshift_node_labels="{'region': 'infra', 'zone': 'default'}" ose3-node[1:2]-ansible.test.example.com openshift_node_labels="{'region': 'primary', 'zone': 'default'}" diff --git a/inventory/libvirt/hosts/libvirt_generic.py b/inventory/libvirt/hosts/libvirt_generic.py index 4652f112e..1c9c17308 100755 --- a/inventory/libvirt/hosts/libvirt_generic.py +++ b/inventory/libvirt/hosts/libvirt_generic.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 -""" +''' libvirt external inventory script ================================= @@ -12,7 +12,7 @@ To use this, copy this file over /etc/ansible/hosts and chmod +x the file. This, more or less, allows you to keep one central database containing info about all of your managed instances. -""" +''' # (c) 2015, Jason DeTiberus <jdetiber@redhat.com> # @@ -36,9 +36,7 @@ info about all of your managed instances. import argparse import ConfigParser import os -import re import sys -from time import time import libvirt import xml.etree.ElementTree as ET @@ -49,8 +47,11 @@ except ImportError: class LibvirtInventory(object): + ''' libvirt dynamic inventory ''' def __init__(self): + ''' Main execution path ''' + self.inventory = dict() # A list of groups and the hosts in that group self.cache = dict() # Details about hosts in the inventory @@ -59,13 +60,15 @@ class LibvirtInventory(object): self.parse_cli_args() if self.args.host: - print self.json_format_dict(self.get_host_info(), self.args.pretty) + print _json_format_dict(self.get_host_info(), self.args.pretty) elif self.args.list: - print self.json_format_dict(self.get_inventory(), self.args.pretty) + print _json_format_dict(self.get_inventory(), self.args.pretty) else: # default action with no options - print self.json_format_dict(self.get_inventory(), self.args.pretty) + print _json_format_dict(self.get_inventory(), self.args.pretty) def read_settings(self): + ''' Reads the settings from the libvirt.ini file ''' + config = ConfigParser.SafeConfigParser() config.read( os.path.dirname(os.path.realpath(__file__)) + '/libvirt.ini' @@ -73,6 +76,8 @@ class LibvirtInventory(object): self.libvirt_uri = config.get('libvirt', 'uri') def parse_cli_args(self): + ''' Command line argument processing ''' + parser = argparse.ArgumentParser( description='Produce an Ansible Inventory file based on libvirt' ) @@ -96,25 +101,27 @@ class LibvirtInventory(object): self.args = parser.parse_args() def get_host_info(self): + ''' Get variables about a specific host ''' + inventory = self.get_inventory() if self.args.host in inventory['_meta']['hostvars']: return inventory['_meta']['hostvars'][self.args.host] def get_inventory(self): + ''' Construct the inventory ''' + inventory = dict(_meta=dict(hostvars=dict())) conn = libvirt.openReadOnly(self.libvirt_uri) if conn is None: - print "Failed to open connection to %s" % libvirt_uri + print "Failed to open connection to %s" % self.libvirt_uri sys.exit(1) domains = conn.listAllDomains() if domains is None: - print "Failed to list domains for connection %s" % libvirt_uri + print "Failed to list domains for connection %s" % self.libvirt_uri sys.exit(1) - arp_entries = self.parse_arp_entries() - for domain in domains: hostvars = dict(libvirt_name=domain.name(), libvirt_id=domain.ID(), @@ -130,21 +137,30 @@ class LibvirtInventory(object): hostvars['libvirt_status'] = 'running' root = ET.fromstring(domain.XMLDesc()) - ns = {'ansible': 'https://github.com/ansible/ansible'} - for tag_elem in root.findall('./metadata/ansible:tags/ansible:tag', ns): + ansible_ns = {'ansible': 'https://github.com/ansible/ansible'} + for tag_elem in root.findall('./metadata/ansible:tags/ansible:tag', ansible_ns): tag = tag_elem.text - self.push(inventory, "tag_%s" % tag, domain_name) - self.push(hostvars, 'libvirt_tags', tag) + _push(inventory, "tag_%s" % tag, domain_name) + _push(hostvars, 'libvirt_tags', tag) # TODO: support more than one network interface, also support # interface types other than 'network' interface = root.find("./devices/interface[@type='network']") if interface is not None: + source_elem = interface.find('source') mac_elem = interface.find('mac') - if mac_elem is not None: - mac = mac_elem.get('address') - if mac in arp_entries: - ip_address = arp_entries[mac]['ip_address'] + if source_elem is not None and \ + mac_elem is not None: + # Adding this to disable pylint check specifically + # ignoring libvirt-python versions that + # do not include DHCPLeases + # This is needed until we upgrade the build bot to + # RHEL7 (>= 1.2.6 libvirt) + # pylint: disable=no-member + dhcp_leases = conn.networkLookupByName(source_elem.get('network')) \ + .DHCPLeases(mac_elem.get('address')) + if len(dhcp_leases) > 0: + ip_address = dhcp_leases[0]['ipaddr'] hostvars['ansible_ssh_host'] = ip_address hostvars['libvirt_ip_address'] = ip_address @@ -152,28 +168,23 @@ class LibvirtInventory(object): return inventory - def parse_arp_entries(self): - arp_entries = dict() - with open('/proc/net/arp', 'r') as f: - # throw away the header - f.readline() - - for line in f: - ip_address, _, _, mac, _, device = line.strip().split() - arp_entries[mac] = dict(ip_address=ip_address, device=device) - - return arp_entries - - def push(self, my_dict, key, element): - if key in my_dict: - my_dict[key].append(element) - else: - my_dict[key] = [element] - - def json_format_dict(self, data, pretty=False): - if pretty: - return json.dumps(data, sort_keys=True, indent=2) - else: - return json.dumps(data) +def _push(my_dict, key, element): + ''' + Push element to the my_dict[key] list. + After having initialized my_dict[key] if it dosn't exist. + ''' + + if key in my_dict: + my_dict[key].append(element) + else: + my_dict[key] = [element] + +def _json_format_dict(data, pretty=False): + ''' Serialize data to a JSON formated str ''' + + if pretty: + return json.dumps(data, sort_keys=True, indent=2) + else: + return json.dumps(data) LibvirtInventory() diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index f8196aefd..b7ce9e5dc 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -82,7 +82,6 @@ class MultiEc2(object): else: raise RuntimeError("Could not find valid ec2 credentials in the environment.") - # Set the default cache path but if its defined we'll assign it. if self.config.has_key('cache_location'): self.cache_path = self.config['cache_location'] @@ -217,7 +216,12 @@ class MultiEc2(object): # For any non-zero, raise an error on it for result in provider_results: if result['code'] != 0: - raise RuntimeError(result['err']) + err_msg = ['\nProblem fetching account: {name}', + 'Error Code: {code}', + 'StdErr: {err}', + 'Stdout: {out}', + ] + raise RuntimeError('\n'.join(err_msg).format(**result)) else: self.all_ec2_results[result['name']] = json.loads(result['out']) @@ -248,8 +252,9 @@ class MultiEc2(object): data[str(host_property)] = str(value) # Add this group - results["%s_%s" % (host_property, value)] = \ - copy.copy(results[acc_config['all_group']]) + if results.has_key(acc_config['all_group']): + results["%s_%s" % (host_property, value)] = \ + copy.copy(results[acc_config['all_group']]) # store the results back into all_ec2_results self.all_ec2_results[acc_config['name']] = results diff --git a/inventory/openshift-ansible-inventory.spec b/inventory/openshift-ansible-inventory.spec index cd2332549..900a27f3a 100644 --- a/inventory/openshift-ansible-inventory.spec +++ b/inventory/openshift-ansible-inventory.spec @@ -1,6 +1,6 @@ Summary: OpenShift Ansible Inventories Name: openshift-ansible-inventory -Version: 0.0.7 +Version: 0.0.8 Release: 1%{?dist} License: ASL 2.0 URL: https://github.com/openshift/openshift-ansible @@ -36,6 +36,17 @@ cp -p gce/hosts/gce.py %{buildroot}/usr/share/ansible/inventory/gce /usr/share/ansible/inventory/gce/gce.py* %changelog +* Tue Jun 09 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.8-1 +- Added more verbosity when error happens. Also fixed a bug. + (kwoodson@redhat.com) +- Implement OpenStack provider (lhuard@amadeus.com) +- * rename openshift_registry_url oreg_url * rename option_images to + _{oreg|ortr}_images (jhonce@redhat.com) +- Fix the remaining pylint warnings (lhuard@amadeus.com) +- Fix some of the pylint warnings (lhuard@amadeus.com) +- [libvirt cluster] Use net-dhcp-leases to find VMs’ IPs (lhuard@amadeus.com) +- fixed the openshift-ansible-bin build (twiest@redhat.com) + * Fri May 15 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.7-1 - Making multi_ec2 into a library (kwoodson@redhat.com) 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) |