diff --git a/plugins/inventory/openstack.py b/plugins/inventory/openstack.py new file mode 100755 index 00000000000..c49d3c1fc43 --- /dev/null +++ b/plugins/inventory/openstack.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python + +# Copyright (c) 2012, Marco Vito Moscaritolo +# Copyright (c) 2013, Jesse Keating +# Copyright (c) 2014, Hewlett-Packard Development Company, L.P. +# +# This module 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. +# +# This software 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 this software. If not, see . + +import argparse +import collections +import os +import sys +import time + +try: + import json +except: + import simplejson as json + +import os_client_config +import shade + + +class OpenStackInventory(object): + + def __init__(self, private=False, refresh=False): + self.openstack_config = os_client_config.config.OpenStackConfig( + os_client_config.config.CONFIG_FILES.append( + '/etc/ansible/openstack.yml'), + private) + self.clouds = shade.openstack_clouds(self.openstack_config) + self.refresh = refresh + + self.cache_max_age = self.openstack_config.get_cache_max_age() + cache_path = self.openstack_config.get_cache_path() + + # Cache related + if not os.path.exists(cache_path): + os.makedirs(cache_path) + self.cache_file = os.path.join(cache_path, "ansible-inventory.cache") + + def is_cache_stale(self): + ''' Determines if cache file has expired, or if it is still valid ''' + if os.path.isfile(self.cache_file): + mod_time = os.path.getmtime(self.cache_file) + current_time = time.time() + if (mod_time + self.cache_max_age) > current_time: + return False + return True + + def get_host_groups(self): + if self.refresh or self.is_cache_stale(): + groups = self.get_host_groups_from_cloud() + self.write_cache(groups) + else: + return json.load(open(self.cache_file, 'r')) + return groups + + def write_cache(self, groups): + with open(self.cache_file, 'w') as cache_file: + cache_file.write(self.json_format_dict(groups)) + + def get_host_groups_from_cloud(self): + groups = collections.defaultdict(list) + hostvars = collections.defaultdict(dict) + + for cloud in self.clouds: + + # Cycle on servers + for server in cloud.list_servers(): + + meta = cloud.get_server_meta(server) + + if 'interface_ip' not in meta['server_vars']: + # skip this host if it doesn't have a network address + continue + + server_vars = meta['server_vars'] + hostvars[server.name][ + 'ansible_ssh_host'] = server_vars['interface_ip'] + hostvars[server.name]['openstack'] = server_vars + + for group in meta['groups']: + groups[group].append(server.name) + + if hostvars: + groups['_meta'] = {'hostvars': hostvars} + return groups + + def json_format_dict(self, data): + return json.dumps(data, sort_keys=True, indent=2) + + def list_instances(self): + groups = self.get_host_groups() + # Return server list + print(self.json_format_dict(groups)) + + def get_host(self, hostname): + groups = self.get_host_groups() + hostvars = groups['_meta']['hostvars'] + if hostname in hostvars: + print(self.json_format_dict(hostvars[hostname])) + + +def parse_args(): + parser = argparse.ArgumentParser(description='OpenStack Inventory Module') + parser.add_argument('--private', + action='store_true', + help='Use private address for ansible host') + parser.add_argument('--refresh', action='store_true', + help='Refresh cached information') + 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 main(): + args = parse_args() + try: + inventory = OpenStackInventory(args.private, args.refresh) + if args.list: + inventory.list_instances() + elif args.host: + inventory.get_host(args.host) + except shade.OpenStackCloudException as e: + print(e.message) + sys.exit(1) + sys.exit(0) + + +if __name__ == '__main__': + main()