From dc548678b40dc400b62614df846e25a50d656b39 Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 14:31:19 -0500 Subject: First version of meta inventory. --- inventory/.gitignore | 1 + inventory/meta.py | 183 ++++++++++++++++++++++++++++++++++++++++++++ inventory/meta.yaml.example | 15 ++++ 3 files changed, 199 insertions(+) create mode 100644 inventory/.gitignore create mode 100755 inventory/meta.py create mode 100644 inventory/meta.yaml.example diff --git a/inventory/.gitignore b/inventory/.gitignore new file mode 100644 index 000000000..055263611 --- /dev/null +++ b/inventory/.gitignore @@ -0,0 +1 @@ +meta.yaml diff --git a/inventory/meta.py b/inventory/meta.py new file mode 100755 index 000000000..c13a0295c --- /dev/null +++ b/inventory/meta.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +from time import time +import argparse +import yaml +import os +import sys +import pdb +import subprocess +import json +import pprint + + +class MetaInventory(object): + + def __init__(self): + self.config = None + self.results = {} + self.result = {} + self.cache_path_cache = os.path.expanduser('~/.ansible/tmp/meta-inventory.cache') + + self.parse_cli_args() + + # load yaml + self.load_yaml_config() + + # if its a host query, fetch and do not cache + if self.args.host: + self.get_inventory() + elif not self.is_cache_valid(): + # go fetch the inventories and cache them if cache is expired + self.get_inventory() + self.write_to_cache() + else: + # get data from disk + self.get_inventory_from_cache() + + def load_yaml_config(self,conf_file=os.path.join(os.getcwd(),'meta.yaml')): + """Load a yaml config file with credentials to query the + respective cloud for inventory. + """ + config = None + with open(conf_file) as conf: + self.config = yaml.safe_load(conf) + + def get_provider_tags(self,provider, env={}): + """Call and query all of the tags that are usuable + by ansible. If environment is empty use the default env. + """ + if not env: + env = os.environ + + # check to see if provider exists + if not os.path.isfile(os.path.join(os.getcwd(),provider)): + raise RuntimeError("Unkown provider: %s" % provider) + + cmds = [provider] + if self.args.host: + cmds.append("--host") + cmds.append(self.args.host) + else: + cmds.append('--list') + + cmds.append('--refresh-cache') + + return subprocess.Popen(cmds, stderr=subprocess.PIPE, \ + stdout=subprocess.PIPE, env=env) + def get_inventory(self): + """Create the subprocess to fetch tags from a provider. + Host query: + Query to return a specific host. If > 1 queries have + results then fail. + + List query: + Query all of the different clouds for their tags. Once completed + store all of their results into one merged updated hash. + """ + processes = {} + for account in self.config['clouds']: + env = account['env_vars'] + name = account['name'] + provider = account['provider'] + processes[name] = self.get_provider_tags(provider, env) + + # for each process collect stdout when its available + all_results = [] + for name, process in processes.items(): + out, err = process.communicate() + all_results.append({ + "name": name, + "out": out.strip(), + "err": err.strip(), + "code": process.returncode + }) + + if not self.args.host: + # For any non-zero, raise an error on it + for result in all_results: + if result['code'] != 0: + raise RuntimeError(result['err']) + else: + self.results[result['name']] = json.loads(result['out']) + self.merge() + else: + # For any 0 result, return it + count = 0 + for results in all_results: + if results['code'] == 0 and results['err'] == '' and results['out'] != '{}': + self.result = json.loads(out) + count += 1 + if count > 1: + raise RuntimeError("Found > 1 results for --host %s. \ + This is an invalid state." % self.args.host) + + def merge(self): + """Merge the results into a single hash. Duplicate keys are placed + into a list. + """ + for name, cloud_result in self.results.items(): + for k,v in cloud_result.items(): + if self.result.has_key(k): + # need to combine into a list + if isinstance(self.result[k], list): + self.result[k].append(v) + else: + self.result[k] = [self.result[k],v] + else: + self.result[k] = [v] + + self.result = self.json_format_dict(self.result) + + def is_cache_valid(self): + ''' Determines if the cache files have expired, or if it is still valid ''' + + if os.path.isfile(self.cache_path_cache): + mod_time = os.path.getmtime(self.cache_path_cache) + current_time = time() + if (mod_time + self.config['cache_max_age']) > current_time: + #if os.path.isfile(self.cache_path_index): + return True + + return False + + 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('--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') + 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) + with open(self.cache_path_cache, 'w') as cache: + cache.write(json_data) + + def get_inventory_from_cache(self): + ''' Reads the inventory from the cache file and returns it as a JSON + object ''' + + with open(self.cache_path_cache, 'r') as cache: + self.result = json.loads(cache.read()) + + def json_format_dict(self, data, pretty=False): + ''' Converts a dict to a JSON object and dumps it as a formatted + string ''' + + if pretty: + return json.dumps(data, sort_keys=True, indent=2) + else: + return json.dumps(data) + + +if __name__ == "__main__": + mi = MetaInventory() + #print mi.result + pp = pprint.PrettyPrinter(indent=2) + pp.pprint(mi.result) + diff --git a/inventory/meta.yaml.example b/inventory/meta.yaml.example new file mode 100644 index 000000000..bba26f016 --- /dev/null +++ b/inventory/meta.yaml.example @@ -0,0 +1,15 @@ +# meta inventory configs +clouds: + - name: aws1 + provider: aws/ec2.py + env_vars: + AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX + AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + - name: aws2 + provider: aws/ec2.py + env_vars: + AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX + AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +cache_max_age: 60 -- cgit v1.2.3 From 444062124fa3b6bb5a29225107138638eb24b21b Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 14:42:31 -0500 Subject: Updated name to multi_ec2 instead of meta. --- inventory/.gitignore | 1 + inventory/meta.py | 183 ------------------------------------------------- inventory/multi_ec2.py | 183 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 183 deletions(-) delete mode 100755 inventory/meta.py create mode 100755 inventory/multi_ec2.py diff --git a/inventory/.gitignore b/inventory/.gitignore index 055263611..cddc716f2 100644 --- a/inventory/.gitignore +++ b/inventory/.gitignore @@ -1 +1,2 @@ meta.yaml +*pyc diff --git a/inventory/meta.py b/inventory/meta.py deleted file mode 100755 index c13a0295c..000000000 --- a/inventory/meta.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python - -from time import time -import argparse -import yaml -import os -import sys -import pdb -import subprocess -import json -import pprint - - -class MetaInventory(object): - - def __init__(self): - self.config = None - self.results = {} - self.result = {} - self.cache_path_cache = os.path.expanduser('~/.ansible/tmp/meta-inventory.cache') - - self.parse_cli_args() - - # load yaml - self.load_yaml_config() - - # if its a host query, fetch and do not cache - if self.args.host: - self.get_inventory() - elif not self.is_cache_valid(): - # go fetch the inventories and cache them if cache is expired - self.get_inventory() - self.write_to_cache() - else: - # get data from disk - self.get_inventory_from_cache() - - def load_yaml_config(self,conf_file=os.path.join(os.getcwd(),'meta.yaml')): - """Load a yaml config file with credentials to query the - respective cloud for inventory. - """ - config = None - with open(conf_file) as conf: - self.config = yaml.safe_load(conf) - - def get_provider_tags(self,provider, env={}): - """Call and query all of the tags that are usuable - by ansible. If environment is empty use the default env. - """ - if not env: - env = os.environ - - # check to see if provider exists - if not os.path.isfile(os.path.join(os.getcwd(),provider)): - raise RuntimeError("Unkown provider: %s" % provider) - - cmds = [provider] - if self.args.host: - cmds.append("--host") - cmds.append(self.args.host) - else: - cmds.append('--list') - - cmds.append('--refresh-cache') - - return subprocess.Popen(cmds, stderr=subprocess.PIPE, \ - stdout=subprocess.PIPE, env=env) - def get_inventory(self): - """Create the subprocess to fetch tags from a provider. - Host query: - Query to return a specific host. If > 1 queries have - results then fail. - - List query: - Query all of the different clouds for their tags. Once completed - store all of their results into one merged updated hash. - """ - processes = {} - for account in self.config['clouds']: - env = account['env_vars'] - name = account['name'] - provider = account['provider'] - processes[name] = self.get_provider_tags(provider, env) - - # for each process collect stdout when its available - all_results = [] - for name, process in processes.items(): - out, err = process.communicate() - all_results.append({ - "name": name, - "out": out.strip(), - "err": err.strip(), - "code": process.returncode - }) - - if not self.args.host: - # For any non-zero, raise an error on it - for result in all_results: - if result['code'] != 0: - raise RuntimeError(result['err']) - else: - self.results[result['name']] = json.loads(result['out']) - self.merge() - else: - # For any 0 result, return it - count = 0 - for results in all_results: - if results['code'] == 0 and results['err'] == '' and results['out'] != '{}': - self.result = json.loads(out) - count += 1 - if count > 1: - raise RuntimeError("Found > 1 results for --host %s. \ - This is an invalid state." % self.args.host) - - def merge(self): - """Merge the results into a single hash. Duplicate keys are placed - into a list. - """ - for name, cloud_result in self.results.items(): - for k,v in cloud_result.items(): - if self.result.has_key(k): - # need to combine into a list - if isinstance(self.result[k], list): - self.result[k].append(v) - else: - self.result[k] = [self.result[k],v] - else: - self.result[k] = [v] - - self.result = self.json_format_dict(self.result) - - def is_cache_valid(self): - ''' Determines if the cache files have expired, or if it is still valid ''' - - if os.path.isfile(self.cache_path_cache): - mod_time = os.path.getmtime(self.cache_path_cache) - current_time = time() - if (mod_time + self.config['cache_max_age']) > current_time: - #if os.path.isfile(self.cache_path_index): - return True - - return False - - 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('--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') - 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) - with open(self.cache_path_cache, 'w') as cache: - cache.write(json_data) - - def get_inventory_from_cache(self): - ''' Reads the inventory from the cache file and returns it as a JSON - object ''' - - with open(self.cache_path_cache, 'r') as cache: - self.result = json.loads(cache.read()) - - def json_format_dict(self, data, pretty=False): - ''' Converts a dict to a JSON object and dumps it as a formatted - string ''' - - if pretty: - return json.dumps(data, sort_keys=True, indent=2) - else: - return json.dumps(data) - - -if __name__ == "__main__": - mi = MetaInventory() - #print mi.result - pp = pprint.PrettyPrinter(indent=2) - pp.pprint(mi.result) - diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py new file mode 100755 index 000000000..c13a0295c --- /dev/null +++ b/inventory/multi_ec2.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +from time import time +import argparse +import yaml +import os +import sys +import pdb +import subprocess +import json +import pprint + + +class MetaInventory(object): + + def __init__(self): + self.config = None + self.results = {} + self.result = {} + self.cache_path_cache = os.path.expanduser('~/.ansible/tmp/meta-inventory.cache') + + self.parse_cli_args() + + # load yaml + self.load_yaml_config() + + # if its a host query, fetch and do not cache + if self.args.host: + self.get_inventory() + elif not self.is_cache_valid(): + # go fetch the inventories and cache them if cache is expired + self.get_inventory() + self.write_to_cache() + else: + # get data from disk + self.get_inventory_from_cache() + + def load_yaml_config(self,conf_file=os.path.join(os.getcwd(),'meta.yaml')): + """Load a yaml config file with credentials to query the + respective cloud for inventory. + """ + config = None + with open(conf_file) as conf: + self.config = yaml.safe_load(conf) + + def get_provider_tags(self,provider, env={}): + """Call and query all of the tags that are usuable + by ansible. If environment is empty use the default env. + """ + if not env: + env = os.environ + + # check to see if provider exists + if not os.path.isfile(os.path.join(os.getcwd(),provider)): + raise RuntimeError("Unkown provider: %s" % provider) + + cmds = [provider] + if self.args.host: + cmds.append("--host") + cmds.append(self.args.host) + else: + cmds.append('--list') + + cmds.append('--refresh-cache') + + return subprocess.Popen(cmds, stderr=subprocess.PIPE, \ + stdout=subprocess.PIPE, env=env) + def get_inventory(self): + """Create the subprocess to fetch tags from a provider. + Host query: + Query to return a specific host. If > 1 queries have + results then fail. + + List query: + Query all of the different clouds for their tags. Once completed + store all of their results into one merged updated hash. + """ + processes = {} + for account in self.config['clouds']: + env = account['env_vars'] + name = account['name'] + provider = account['provider'] + processes[name] = self.get_provider_tags(provider, env) + + # for each process collect stdout when its available + all_results = [] + for name, process in processes.items(): + out, err = process.communicate() + all_results.append({ + "name": name, + "out": out.strip(), + "err": err.strip(), + "code": process.returncode + }) + + if not self.args.host: + # For any non-zero, raise an error on it + for result in all_results: + if result['code'] != 0: + raise RuntimeError(result['err']) + else: + self.results[result['name']] = json.loads(result['out']) + self.merge() + else: + # For any 0 result, return it + count = 0 + for results in all_results: + if results['code'] == 0 and results['err'] == '' and results['out'] != '{}': + self.result = json.loads(out) + count += 1 + if count > 1: + raise RuntimeError("Found > 1 results for --host %s. \ + This is an invalid state." % self.args.host) + + def merge(self): + """Merge the results into a single hash. Duplicate keys are placed + into a list. + """ + for name, cloud_result in self.results.items(): + for k,v in cloud_result.items(): + if self.result.has_key(k): + # need to combine into a list + if isinstance(self.result[k], list): + self.result[k].append(v) + else: + self.result[k] = [self.result[k],v] + else: + self.result[k] = [v] + + self.result = self.json_format_dict(self.result) + + def is_cache_valid(self): + ''' Determines if the cache files have expired, or if it is still valid ''' + + if os.path.isfile(self.cache_path_cache): + mod_time = os.path.getmtime(self.cache_path_cache) + current_time = time() + if (mod_time + self.config['cache_max_age']) > current_time: + #if os.path.isfile(self.cache_path_index): + return True + + return False + + 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('--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') + 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) + with open(self.cache_path_cache, 'w') as cache: + cache.write(json_data) + + def get_inventory_from_cache(self): + ''' Reads the inventory from the cache file and returns it as a JSON + object ''' + + with open(self.cache_path_cache, 'r') as cache: + self.result = json.loads(cache.read()) + + def json_format_dict(self, data, pretty=False): + ''' Converts a dict to a JSON object and dumps it as a formatted + string ''' + + if pretty: + return json.dumps(data, sort_keys=True, indent=2) + else: + return json.dumps(data) + + +if __name__ == "__main__": + mi = MetaInventory() + #print mi.result + pp = pprint.PrettyPrinter(indent=2) + pp.pprint(mi.result) + -- cgit v1.2.3 From 54de85ff38cd0e68bb669e8cebbaccc6719e3d64 Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 14:44:18 -0500 Subject: Updated with the class name. --- inventory/multi_ec2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index c13a0295c..131d7fa76 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -11,7 +11,7 @@ import json import pprint -class MetaInventory(object): +class MultiEc2(object): def __init__(self): self.config = None @@ -176,7 +176,7 @@ class MetaInventory(object): if __name__ == "__main__": - mi = MetaInventory() + mi = MultiEc2() #print mi.result pp = pprint.PrettyPrinter(indent=2) pp.pprint(mi.result) -- cgit v1.2.3 From f6dfc719d88fc0fd41a114f4ec0d670e962da0b8 Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 14:55:09 -0500 Subject: In order to agree with previous renaming these naming changes were made. --- inventory/.gitignore | 2 +- inventory/meta.yaml.example | 15 --------------- inventory/multi_ec2.py | 2 +- inventory/multi_ec2.yaml.example | 15 +++++++++++++++ 4 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 inventory/meta.yaml.example create mode 100644 inventory/multi_ec2.yaml.example diff --git a/inventory/.gitignore b/inventory/.gitignore index cddc716f2..6b11bed20 100644 --- a/inventory/.gitignore +++ b/inventory/.gitignore @@ -1,2 +1,2 @@ -meta.yaml +multi_ec2.yaml *pyc diff --git a/inventory/meta.yaml.example b/inventory/meta.yaml.example deleted file mode 100644 index bba26f016..000000000 --- a/inventory/meta.yaml.example +++ /dev/null @@ -1,15 +0,0 @@ -# meta inventory configs -clouds: - - name: aws1 - provider: aws/ec2.py - env_vars: - AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX - AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - - name: aws2 - provider: aws/ec2.py - env_vars: - AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX - AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - -cache_max_age: 60 diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index 131d7fa76..97f158e8a 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -35,7 +35,7 @@ class MultiEc2(object): # get data from disk self.get_inventory_from_cache() - def load_yaml_config(self,conf_file=os.path.join(os.getcwd(),'meta.yaml')): + def load_yaml_config(self,conf_file=os.path.join(os.getcwd(),'multi_ec2.yaml')): """Load a yaml config file with credentials to query the respective cloud for inventory. """ diff --git a/inventory/multi_ec2.yaml.example b/inventory/multi_ec2.yaml.example new file mode 100644 index 000000000..bba26f016 --- /dev/null +++ b/inventory/multi_ec2.yaml.example @@ -0,0 +1,15 @@ +# meta inventory configs +clouds: + - name: aws1 + provider: aws/ec2.py + env_vars: + AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX + AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + - name: aws2 + provider: aws/ec2.py + env_vars: + AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX + AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +cache_max_age: 60 -- cgit v1.2.3 From 58e392c3243feaed8c0fff0f637279aa88f7467b Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 15:12:43 -0500 Subject: Fixed naming for chache file. --- inventory/multi_ec2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index 97f158e8a..e569b56d5 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -17,7 +17,7 @@ class MultiEc2(object): self.config = None self.results = {} self.result = {} - self.cache_path_cache = os.path.expanduser('~/.ansible/tmp/meta-inventory.cache') + self.cache_path_cache = os.path.expanduser('~/.ansible/tmp/multi_ec2_inventory.cache') self.parse_cli_args() -- cgit v1.2.3 From 6eead926a86f3de1ea0dd4113a715a1516458bcc Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 17:21:30 -0500 Subject: Updated merge function to merge recursively --- inventory/multi_ec2.py | 57 ++++++++++++++++++++++++---------------- inventory/multi_ec2.yaml.example | 4 +-- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index e569b56d5..6085a1aef 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -18,6 +18,7 @@ class MultiEc2(object): self.results = {} self.result = {} self.cache_path_cache = os.path.expanduser('~/.ansible/tmp/multi_ec2_inventory.cache') + self.file_path = os.path.join(os.path.dirname(os.path.realpath(__file__))) self.parse_cli_args() @@ -35,11 +36,13 @@ class MultiEc2(object): # get data from disk self.get_inventory_from_cache() - def load_yaml_config(self,conf_file=os.path.join(os.getcwd(),'multi_ec2.yaml')): + def load_yaml_config(self,conf_file=None): """Load a yaml config file with credentials to query the respective cloud for inventory. """ config = None + if not conf_file: + conf_file = os.path.join(self.file_path,'multi_ec2.yaml') with open(conf_file) as conf: self.config = yaml.safe_load(conf) @@ -51,8 +54,9 @@ class MultiEc2(object): env = os.environ # check to see if provider exists - if not os.path.isfile(os.path.join(os.getcwd(),provider)): - raise RuntimeError("Unkown provider: %s" % provider) + if not os.path.isfile(provider) or not os.access(provider, os.X_OK): + raise RuntimeError("Problem with the provider. Please check path " \ + "and that it is executable. (%s)" % provider) cmds = [provider] if self.args.host: @@ -72,11 +76,11 @@ class MultiEc2(object): results then fail. List query: - Query all of the different clouds for their tags. Once completed + Query all of the different accounts for their tags. Once completed store all of their results into one merged updated hash. """ processes = {} - for account in self.config['clouds']: + for account in self.config['accounts']: env = account['env_vars'] name = account['name'] provider = account['provider'] @@ -100,7 +104,9 @@ class MultiEc2(object): raise RuntimeError(result['err']) else: self.results[result['name']] = json.loads(result['out']) - self.merge() + values = self.results.values() + values.insert(0, self.result) + map(lambda x: self.merge(self.result, x), values) else: # For any 0 result, return it count = 0 @@ -111,23 +117,30 @@ class MultiEc2(object): if count > 1: raise RuntimeError("Found > 1 results for --host %s. \ This is an invalid state." % self.args.host) - - def merge(self): - """Merge the results into a single hash. Duplicate keys are placed - into a list. - """ - for name, cloud_result in self.results.items(): - for k,v in cloud_result.items(): - if self.result.has_key(k): - # need to combine into a list - if isinstance(self.result[k], list): - self.result[k].append(v) - else: - self.result[k] = [self.result[k],v] + def merge(self, a, b): + "merges b into a" + for key in b: + if key in a: + if isinstance(a[key], dict) and isinstance(b[key], dict): + self.merge(a[key], b[key]) + elif a[key] == 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) + # 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]] else: - self.result[k] = [v] - - self.result = self.json_format_dict(self.result) + a[key] = [a[key],b[key]] + else: + a[key] = b[key] + return a def is_cache_valid(self): ''' Determines if the cache files have expired, or if it is still valid ''' diff --git a/inventory/multi_ec2.yaml.example b/inventory/multi_ec2.yaml.example index bba26f016..0bd505816 100644 --- a/inventory/multi_ec2.yaml.example +++ b/inventory/multi_ec2.yaml.example @@ -1,5 +1,5 @@ -# meta inventory configs -clouds: +# multi ec2 inventory configs +accounts: - name: aws1 provider: aws/ec2.py env_vars: -- cgit v1.2.3 From d8ccf2a6b937f53e4f564102d4e7f009ade1e26a Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 12 Dec 2014 20:07:49 -0500 Subject: Updated the function name to accurately reflect its procedure. --- inventory/multi_ec2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index 6085a1aef..7fbfb0c90 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -106,7 +106,7 @@ class MultiEc2(object): self.results[result['name']] = json.loads(result['out']) values = self.results.values() values.insert(0, self.result) - map(lambda x: self.merge(self.result, x), values) + map(lambda x: self.merge_destructively(self.result, x), values) else: # For any 0 result, return it count = 0 @@ -117,12 +117,12 @@ class MultiEc2(object): if count > 1: raise RuntimeError("Found > 1 results for --host %s. \ This is an invalid state." % self.args.host) - def merge(self, a, b): + def merge_destructively(self, a, b): "merges b into a" for key in b: if key in a: if isinstance(a[key], dict) and isinstance(b[key], dict): - self.merge(a[key], b[key]) + self.merge_destructively(a[key], b[key]) elif a[key] == b[key]: pass # same leaf value # both lists so add each element in b to a if it does ! exist -- cgit v1.2.3