From cac00add8d63bdbe129b6f74afa04d744adbb4ec Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Sun, 1 Mar 2015 11:56:10 -0500 Subject: [PATCH] Update to final shade inventory interface shade has an inventory interface that is cleaner. We should use it. --- contrib/inventory/openstack.py | 163 +++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/contrib/inventory/openstack.py b/contrib/inventory/openstack.py index 103be1bee01..46b43e92212 100755 --- a/contrib/inventory/openstack.py +++ b/contrib/inventory/openstack.py @@ -2,7 +2,7 @@ # Copyright (c) 2012, Marco Vito Moscaritolo # Copyright (c) 2013, Jesse Keating -# Copyright (c) 2014, Hewlett-Packard Development Company, L.P. +# Copyright (c) 2015, 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 @@ -46,89 +46,105 @@ except: import os_client_config import shade +import shade.inventory +CONFIG_FILES = ['/etc/ansible/openstack.yaml'] -class OpenStackInventory(object): - def __init__(self, private=False, refresh=False): - config_files = os_client_config.config.CONFIG_FILES - config_files.append('/etc/ansible/openstack.yml') - self.openstack_config = os_client_config.config.OpenStackConfig( - config_files) - self.clouds = shade.openstack_clouds(self.openstack_config) - self.private = private - self.refresh = refresh +def get_groups_from_server(server_vars): + groups = [] - self.cache_max_age = self.openstack_config.get_cache_max_age() - cache_path = self.openstack_config.get_cache_path() + region = server_vars['region'] + cloud = server_vars['cloud'] + metadata = server_vars.get('metadata', {}) - # Cache related - if not os.path.exists(cache_path): - os.makedirs(cache_path) - self.cache_file = os.path.join(cache_path, "ansible-inventory.cache") + # Create a group for the cloud + groups.append(cloud) - 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 + # Create a group on region + groups.append(region) - 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 + # And one by cloud_region + groups.append("%s_%s" % (cloud, region)) - def write_cache(self, groups): - with open(self.cache_file, 'w') as cache_file: - cache_file.write(self.json_format_dict(groups)) + # Check if group metadata key in servers' metadata + if 'group' in metadata: + groups.append(metadata['group']) - def get_host_groups_from_cloud(self): - groups = collections.defaultdict(list) - hostvars = collections.defaultdict(dict) + for extra_group in metadata.get('groups', '').split(','): + if extra_group: + groups.append(extra_group) - for cloud in self.clouds: - cloud.private = cloud.private or self.private + groups.append('instance-%s' % server_vars['id']) + groups.append(server_vars['name']) - # Cycle on servers - for server in cloud.list_servers(): + for key in ('flavor', 'image'): + if 'name' in server_vars[key]: + groups.append('%s-%s' % (key, server_vars[key]['name'])) - meta = cloud.get_server_meta(server) + for key, value in iter(metadata.items()): + groups.append('meta-%s_%s' % (key, value)) - if 'interface_ip' not in meta['server_vars']: - # skip this host if it doesn't have a network address - continue + az = server_vars.get('az', None) + if az: + # Make groups for az, region_az and cloud_region_az + groups.append(az) + groups.append('%s_%s' % (region, az)) + groups.append('%s_%s_%s' % (cloud, region, az)) + return groups - 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) +def get_host_groups(inventory): + (cache_file, cache_expiration_time) = get_cache_settings() + if is_cache_stale(cache_file, cache_expiration_time): + groups = to_json(get_host_groups_from_cloud(inventory)) + open(cache_file, 'w').write(groups) + else: + groups = open(cache_file, 'r').read() + return groups - if hostvars: - groups['_meta'] = {'hostvars': hostvars} - return groups - def json_format_dict(self, data): - return json.dumps(data, sort_keys=True, indent=2) +def get_host_groups_from_cloud(inventory): + groups = collections.defaultdict(list) + hostvars = {} + for server in inventory.list_hosts(): - def list_instances(self): - groups = self.get_host_groups() - # Return server list - print(self.json_format_dict(groups)) + if 'interface_ip' not in server: + continue + for group in get_groups_from_server(server): + groups[group].append(server['id']) + hostvars[server['id']] = dict( + ansible_ssh_host=server['interface_ip'], + openstack=server, + ) + groups['_meta'] = {'hostvars': hostvars} + return 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 is_cache_stale(cache_file, cache_expiration_time): + ''' Determines if cache file has expired, or if it is still valid ''' + if os.path.isfile(cache_file): + mod_time = os.path.getmtime(cache_file) + current_time = time.time() + if (mod_time + cache_expiration_time) > current_time: + return False + return True + + +def get_cache_settings(): + config = os_client_config.config.OpenStackConfig( + config_files=os_client_config.config.CONFIG_FILES + CONFIG_FILES) + # For inventory-wide caching + cache_expiration_time = config.get_cache_expiration_time() + cache_path = config.get_cache_path() + if not os.path.exists(cache_path): + os.makedirs(cache_path) + cache_file = os.path.join(cache_path, 'ansible-inventory.cache') + return (cache_file, cache_expiration_time) + + +def to_json(in_dict): + return json.dumps(in_dict, sort_keys=True, indent=2) def parse_args(): @@ -138,21 +154,32 @@ def parse_args(): help='Use private address for ansible host') parser.add_argument('--refresh', action='store_true', help='Refresh cached information') + parser.add_argument('--debug', action='store_true', default=False, + help='Enable debug output') 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) + config_files = os_client_config.config.CONFIG_FILES + CONFIG_FILES + shade.simple_logging(debug=args.debug) + inventory = shade.inventory.OpenStackInventory( + refresh=args.refresh, + config_files=config_files, + private=args.private, + ) + if args.list: - inventory.list_instances() + output = get_host_groups(inventory) elif args.host: - inventory.get_host(args.host) + output = to_json(inventory.get_host(args.host)) + print(output) except shade.OpenStackCloudException as e: sys.stderr.write('%s\n' % e.message) sys.exit(1)