diff options
| author | Wesley Hearn <wesley.s.hearn@gmail.com> | 2015-04-24 14:06:12 -0400 | 
|---|---|---|
| committer | Wesley Hearn <wesley.s.hearn@gmail.com> | 2015-04-24 14:06:12 -0400 | 
| commit | 519e097df31e2148ac520ab273d0bd2fb2f7bb43 (patch) | |
| tree | 4c5413c72a2dd2ec732730b6994a104cca6a9798 /inventory | |
| parent | db9cf8ef4f030f30391e021f360fe0c3db1dce74 (diff) | |
| parent | 8ce5e1de898d2fd2c4aa4620f31b57b62ed0c5d6 (diff) | |
| download | openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.tar.gz openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.tar.bz2 openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.tar.xz openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.zip  | |
Merge pull request #188 from openshift/master
Merge master into stage
Diffstat (limited to 'inventory')
| -rw-r--r-- | inventory/aws/hosts/ec2.ini (renamed from inventory/aws/ec2.ini) | 0 | ||||
| -rwxr-xr-x | inventory/aws/hosts/ec2.py (renamed from inventory/aws/ec2.py) | 0 | ||||
| -rw-r--r-- | inventory/aws/hosts/hosts | 1 | ||||
| -rw-r--r-- | inventory/byo/hosts | 34 | ||||
| -rwxr-xr-x | inventory/gce/hosts/gce.py (renamed from inventory/gce/gce.py) | 0 | ||||
| -rw-r--r-- | inventory/gce/hosts/hosts | 1 | ||||
| -rw-r--r-- | inventory/libvirt/hosts/hosts | 1 | ||||
| -rw-r--r-- | inventory/libvirt/hosts/libvirt.ini | 20 | ||||
| -rwxr-xr-x | inventory/libvirt/hosts/libvirt_generic.py | 179 | ||||
| -rwxr-xr-x | inventory/multi_ec2.py | 110 | ||||
| -rw-r--r-- | inventory/multi_ec2.yaml.example | 4 | ||||
| -rw-r--r-- | inventory/openshift-ansible-inventory.spec | 50 | 
12 files changed, 353 insertions, 47 deletions
diff --git a/inventory/aws/ec2.ini b/inventory/aws/hosts/ec2.ini index eaab0a410..eaab0a410 100644 --- a/inventory/aws/ec2.ini +++ b/inventory/aws/hosts/ec2.ini diff --git a/inventory/aws/ec2.py b/inventory/aws/hosts/ec2.py index f231ff4c2..f231ff4c2 100755 --- a/inventory/aws/ec2.py +++ b/inventory/aws/hosts/ec2.py diff --git a/inventory/aws/hosts/hosts b/inventory/aws/hosts/hosts new file mode 100644 index 000000000..34a4396bd --- /dev/null +++ b/inventory/aws/hosts/hosts @@ -0,0 +1 @@ +localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 diff --git a/inventory/byo/hosts b/inventory/byo/hosts new file mode 100644 index 000000000..98dbb4fd8 --- /dev/null +++ b/inventory/byo/hosts @@ -0,0 +1,34 @@ +# This is an example of a bring your own (byo) host inventory + +# Create an OSEv3 group that contains the masters and nodes groups +[OSEv3:children] +masters +nodes + +# Set variables common for all OSEv3 hosts +[OSEv3:vars] +# SSH user, this user should allow ssh based auth without requiring a password +ansible_ssh_user=root + +# If ansible_ssh_user is not root, ansible_sudo must be set to true +#ansible_sudo=true + +# To deploy origin, change deployment_type to origin +deployment_type=enterprise + +# Pre-release registry URL +openshift_registry_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}] + +# 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'}] + +# host group for masters +[masters] +ose3-master-ansible.test.example.com + +# host group for nodes +[nodes] +ose3-node[1:2]-ansible.test.example.com diff --git a/inventory/gce/gce.py b/inventory/gce/hosts/gce.py index 3403f735e..3403f735e 100755 --- a/inventory/gce/gce.py +++ b/inventory/gce/hosts/gce.py diff --git a/inventory/gce/hosts/hosts b/inventory/gce/hosts/hosts new file mode 100644 index 000000000..34a4396bd --- /dev/null +++ b/inventory/gce/hosts/hosts @@ -0,0 +1 @@ +localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 diff --git a/inventory/libvirt/hosts/hosts b/inventory/libvirt/hosts/hosts new file mode 100644 index 000000000..34a4396bd --- /dev/null +++ b/inventory/libvirt/hosts/hosts @@ -0,0 +1 @@ +localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 diff --git a/inventory/libvirt/hosts/libvirt.ini b/inventory/libvirt/hosts/libvirt.ini new file mode 100644 index 000000000..62ff204dd --- /dev/null +++ b/inventory/libvirt/hosts/libvirt.ini @@ -0,0 +1,20 @@ +# Ansible libvirt external inventory script settings +# + +[libvirt] + +uri = qemu:///system + +# API calls to libvirt can be slow. For this reason, we cache the results of an API +# call. Set this to the path you want cache files to be written to. Two files +# will be written to this directory: +#   - ansible-libvirt.cache +#   - ansible-libvirt.index +cache_path = /tmp + +# The number of seconds a cache file is considered valid. After this many +# seconds, a new API call will be made, and the cache file will be updated. +cache_max_age = 900 + + + diff --git a/inventory/libvirt/hosts/libvirt_generic.py b/inventory/libvirt/hosts/libvirt_generic.py new file mode 100755 index 000000000..4652f112e --- /dev/null +++ b/inventory/libvirt/hosts/libvirt_generic.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python2 + +""" +libvirt external inventory script +================================= + +Ansible has a feature where instead of reading from /etc/ansible/hosts +as a text file, it can query external programs to obtain the list +of hosts, groups the hosts are in, and even variables to assign to each host. + +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> +# +# 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 argparse +import ConfigParser +import os +import re +import sys +from time import time +import libvirt +import xml.etree.ElementTree as ET + +try: +    import json +except ImportError: +    import simplejson as json + + +class LibvirtInventory(object): + +    def __init__(self): +        self.inventory = dict()  # A list of groups and the hosts in that group +        self.cache = dict()  # Details about hosts in the inventory + +        # Read settings and parse CLI arguments +        self.read_settings() +        self.parse_cli_args() + +        if self.args.host: +            print self.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) +        else:  # default action with no options +            print self.json_format_dict(self.get_inventory(), self.args.pretty) + +    def read_settings(self): +        config = ConfigParser.SafeConfigParser() +        config.read( +            os.path.dirname(os.path.realpath(__file__)) + '/libvirt.ini' +        ) +        self.libvirt_uri = config.get('libvirt', 'uri') + +    def parse_cli_args(self): +        parser = argparse.ArgumentParser( +            description='Produce an Ansible Inventory file based on libvirt' +        ) +        parser.add_argument( +            '--list', +            action='store_true', +            default=True, +            help='List instances (default: True)' +        ) +        parser.add_argument( +            '--host', +            action='store', +            help='Get all the variables about a specific instance' +        ) +        parser.add_argument( +            '--pretty', +            action='store_true', +            default=False, +            help='Pretty format (default: False)' +        ) +        self.args = parser.parse_args() + +    def get_host_info(self): +        inventory = self.get_inventory() +        if self.args.host in inventory['_meta']['hostvars']: +            return inventory['_meta']['hostvars'][self.args.host] + +    def get_inventory(self): +        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 +            sys.exit(1) + +        domains = conn.listAllDomains() +        if domains is None: +            print "Failed to list domains for connection %s" % 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(), +                            libvirt_uuid=domain.UUIDString()) +            domain_name = domain.name() + +            # TODO: add support for guests that are not in a running state +            state, _ = domain.state() +            # 2 is the state for a running guest +            if state != 1: +                continue + +            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): +                tag = tag_elem.text +                self.push(inventory, "tag_%s" % tag, domain_name) +                self.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: +                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'] +                        hostvars['ansible_ssh_host'] = ip_address +                        hostvars['libvirt_ip_address'] = ip_address + +            inventory['_meta']['hostvars'][domain_name] = hostvars + +        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) + +LibvirtInventory() diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index 5dee7972b..b839a33ea 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -1,37 +1,58 @@  #!/usr/bin/env python2 +''' +    Fetch and combine multiple ec2 account settings into a single +    json hash. +'''  # vim: expandtab:tabstop=4:shiftwidth=4  from time import time  import argparse  import yaml  import os -import sys -import pdb  import subprocess  import json -import pprint +CONFIG_FILE_NAME = 'multi_ec2.yaml' +  class MultiEc2(object): +    ''' +       MultiEc2 class: +            Opens a yaml config file and reads aws credentials. +            Stores a json hash of resources in result. +    '''      def __init__(self): +        self.args = None          self.config = None          self.all_ec2_results = {}          self.result = {}          self.cache_path = os.path.expanduser('~/.ansible/tmp/multi_ec2_inventory.cache')          self.file_path = os.path.join(os.path.dirname(os.path.realpath(__file__))) -        self.config_file = os.path.join(self.file_path,"multi_ec2.yaml") + +        same_dir_config_file = os.path.join(self.file_path, CONFIG_FILE_NAME) +        etc_dir_config_file = os.path.join(os.path.sep, 'etc', 'ansible', CONFIG_FILE_NAME) + +        # Prefer a file in the same directory, fall back to a file in etc +        if os.path.isfile(same_dir_config_file): +            self.config_file = same_dir_config_file +        elif os.path.isfile(etc_dir_config_file): +            self.config_file = etc_dir_config_file +        else: +            self.config_file = None # expect env vars +          self.parse_cli_args()          # load yaml -        if os.path.isfile(self.config_file): +        if self.config_file and os.path.isfile(self.config_file):              self.config = self.load_yaml_config() -        elif os.environ.has_key("AWS_ACCESS_KEY_ID") and os.environ.has_key("AWS_SECRET_ACCESS_KEY"): +        elif os.environ.has_key("AWS_ACCESS_KEY_ID") and \ +             os.environ.has_key("AWS_SECRET_ACCESS_KEY"):              self.config = {}              self.config['accounts'] = [                  {                      'name': 'default', -                    'provider': 'aws/ec2.py', +                    'provider': 'aws/hosts/ec2.py',                      'env_vars': {                          'AWS_ACCESS_KEY_ID':     os.environ["AWS_ACCESS_KEY_ID"],                          'AWS_SECRET_ACCESS_KEY': os.environ["AWS_SECRET_ACCESS_KEY"], @@ -43,13 +64,9 @@ class MultiEc2(object):          else:              raise RuntimeError("Could not find valid ec2 credentials in the environment.") -        if self.args.cache_only: -            # get data from disk -            result = self.get_inventory_from_cache() - -            if not result: -                self.get_inventory() -                self.write_to_cache() +        if self.args.refresh_cache: +            self.get_inventory() +            self.write_to_cache()          # if its a host query, fetch and do not cache          elif self.args.host:              self.get_inventory() @@ -61,7 +78,7 @@ class MultiEc2(object):              # get data from disk              self.get_inventory_from_cache() -    def load_yaml_config(self,conf_file=None): +    def load_yaml_config(self, conf_file=None):          """Load a yaml config file with credentials to query the          respective cloud for inventory.          """ @@ -75,7 +92,7 @@ class MultiEc2(object):          return config -    def get_provider_tags(self,provider, env={}): +    def get_provider_tags(self, provider, env=None):          """Call <provider> and query all of the tags that are usuable          by ansible.  If environment is empty use the default env.          """ @@ -140,7 +157,8 @@ class MultiEc2(object):                      self.all_ec2_results[result['name']] = json.loads(result['out'])              values = self.all_ec2_results.values()              values.insert(0, self.result) -            [MultiEc2.merge_destructively(self.result, x) for x in  values] +            for result in  values: +                MultiEc2.merge_destructively(self.result, result)          else:              # For any 0 result, return it              count = 0 @@ -152,30 +170,30 @@ class MultiEc2(object):                      raise RuntimeError("Found > 1 results for --host %s. \                                         This is an invalid state." % self.args.host)      @staticmethod -    def merge_destructively(a, b): -        "merges b into a" -        for key in b: -            if key in a: -                if isinstance(a[key], dict) and isinstance(b[key], dict): -                    MultiEc2.merge_destructively(a[key], b[key]) -                elif a[key] == b[key]: +    def merge_destructively(input_a, input_b): +        "merges b into input_a" +        for key in input_b: +            if key in input_a: +                if isinstance(input_a[key], dict) and isinstance(input_b[key], dict): +                    MultiEc2.merge_destructively(input_a[key], input_b[key]) +                elif input_a[key] == input_b[key]:                      pass # same leaf value                  # both lists so add each element in b to a if it does ! exist -                elif isinstance(a[key], list) and isinstance(b[key],list): -                    for x in b[key]: -                        if x not in a[key]: -                            a[key].append(x) +                elif isinstance(input_a[key], list) and isinstance(input_b[key], list): +                    for result in input_b[key]: +                        if result not in input_a[key]: +                            input_a[key].input_append(result)                  # a is a list and not b -                elif isinstance(a[key], list): -                    if b[key] not in a[key]: -                        a[key].append(b[key]) -                elif isinstance(b[key], list): -                    a[key] = [a[key]] + [k for k in b[key] if k != a[key]] +                elif isinstance(input_a[key], list): +                    if input_b[key] not in input_a[key]: +                        input_a[key].append(input_b[key]) +                elif isinstance(input_b[key], list): +                    input_a[key] = [input_a[key]] + [k for k in input_b[key] if k != input_a[key]]                  else: -                    a[key] = [a[key],b[key]] +                    input_a[key] = [input_a[key], input_b[key]]              else: -                a[key] = b[key] -        return a +                input_a[key] = input_b[key] +        return input_a      def is_cache_valid(self):          ''' Determines if the cache files have expired, or if it is still valid ''' @@ -191,19 +209,20 @@ class MultiEc2(object):      def parse_cli_args(self):          ''' Command line argument processing ''' -        parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on a provider') -        parser.add_argument('--cache-only', action='store_true', default=False, -                           help='Fetch cached only instances (default: False)') +        parser = argparse.ArgumentParser( +            description='Produce an Ansible Inventory file based on a provider') +        parser.add_argument('--refresh-cache', action='store_true', default=False, +                            help='Fetch cached only instances (default: False)')          parser.add_argument('--list', action='store_true', default=True, -                           help='List instances (default: True)') +                            help='List instances (default: True)')          parser.add_argument('--host', action='store', default=False, -                           help='Get all the variables about a specific instance') +                            help='Get all the variables about a specific instance')          self.args = parser.parse_args()      def write_to_cache(self):          ''' Writes data in JSON format to a file ''' -        json_data = self.json_format_dict(self.result, True) +        json_data = MultiEc2.json_format_dict(self.result, True)          with open(self.cache_path, 'w') as cache:              cache.write(json_data) @@ -219,7 +238,8 @@ class MultiEc2(object):          return True -    def json_format_dict(self, data, pretty=False): +    @classmethod +    def json_format_dict(cls, data, pretty=False):          ''' Converts a dict to a JSON object and dumps it as a formatted          string ''' @@ -229,9 +249,9 @@ class MultiEc2(object):              return json.dumps(data)      def result_str(self): +        '''Return cache string stored in self.result'''          return self.json_format_dict(self.result, True)  if __name__ == "__main__": -    mi = MultiEc2() -    print mi.result_str() +    print MultiEc2().result_str() diff --git a/inventory/multi_ec2.yaml.example b/inventory/multi_ec2.yaml.example index 0bd505816..91e7c7970 100644 --- a/inventory/multi_ec2.yaml.example +++ b/inventory/multi_ec2.yaml.example @@ -1,13 +1,13 @@  # multi ec2 inventory configs  accounts:    - name: aws1 -    provider: aws/ec2.py +    provider: aws/hosts/ec2.py      env_vars:        AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX        AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    - name: aws2 -    provider: aws/ec2.py +    provider: aws/hosts/ec2.py      env_vars:        AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX        AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/inventory/openshift-ansible-inventory.spec b/inventory/openshift-ansible-inventory.spec new file mode 100644 index 000000000..8267e16f6 --- /dev/null +++ b/inventory/openshift-ansible-inventory.spec @@ -0,0 +1,50 @@ +Summary:       OpenShift Ansible Inventories +Name:          openshift-ansible-inventory +Version:       0.0.2 +Release:       1%{?dist} +License:       ASL 2.0 +URL:           https://github.com/openshift/openshift-ansible +Source0:       %{name}-%{version}.tar.gz +Requires:      python2 +BuildRequires: python2-devel +BuildArch:     noarch + +%description +Ansible Inventories used with the openshift-ansible scripts and playbooks. + +%prep +%setup -q + +%build + +%install +mkdir -p %{buildroot}/etc/ansible +mkdir -p %{buildroot}/usr/share/ansible/inventory +mkdir -p %{buildroot}/usr/share/ansible/inventory/aws +mkdir -p %{buildroot}/usr/share/ansible/inventory/gce + +cp -p multi_ec2.py %{buildroot}/usr/share/ansible/inventory +cp -p multi_ec2.yaml.example %{buildroot}/etc/ansible/multi_ec2.yaml +cp -p aws/ec2.py aws/ec2.ini %{buildroot}/usr/share/ansible/inventory/aws +cp -p gce/gce.py %{buildroot}/usr/share/ansible/inventory/gce + +%files +%config(noreplace) /etc/ansible/* +%dir /usr/share/ansible/inventory +/usr/share/ansible/inventory/multi_ec2.py* +/usr/share/ansible/inventory/aws/ec2.py* +%config(noreplace) /usr/share/ansible/inventory/aws/ec2.ini +/usr/share/ansible/inventory/gce/gce.py* + +%changelog +* Thu Mar 26 2015 Thomas Wiest <twiest@redhat.com> 0.0.2-1 +- added the ability to have a config file in /etc/openshift_ansible to +  multi_ec2.py. (twiest@redhat.com) +- Merge pull request #97 from jwhonce/wip/cluster (jhonce@redhat.com) +- gce inventory/playbook updates for node registration changes +  (jdetiber@redhat.com) +- Various fixes (jdetiber@redhat.com) + +* Tue Mar 24 2015 Thomas Wiest <twiest@redhat.com> 0.0.1-1 +- new package built with tito +  | 
