From 9b088a1e4049cdc30bc3f8cbb3228b52895efc47 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 15 Oct 2015 11:19:11 -0400 Subject: [PATCH] implemented inventory_hostname lookup in v2 --- lib/ansible/inventory/__init__.py | 25 ++++++++----- .../plugins/lookup/inventory_hostnames.py | 37 ++++++++++++++----- test/units/inventory/test_inventory.py | 4 +- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index c31116e0a39..62afaddd3e7 100644 --- a/lib/ansible/inventory/__init__.py +++ b/lib/ansible/inventory/__init__.py @@ -159,7 +159,7 @@ class Inventory(object): or applied subsets """ - patterns = self._split_pattern(pattern) + patterns = Inventory.split_host_pattern(pattern) hosts = self._evaluate_patterns(patterns) # mainly useful for hostvars[host] access @@ -175,7 +175,8 @@ class Inventory(object): return hosts - def _split_pattern(self, pattern): + @classmethod + def split_host_pattern(cls, pattern): """ Takes a string containing host patterns separated by commas (or a list thereof) and returns a list of single patterns (which may not contain @@ -188,7 +189,7 @@ class Inventory(object): """ if isinstance(pattern, list): - return list(itertools.chain(*map(self._split_pattern, pattern))) + return list(itertools.chain(*map(cls.split_host_pattern, pattern))) if ';' in pattern: display.deprecated("Use ',' instead of ';' to separate host patterns") @@ -226,11 +227,8 @@ class Inventory(object): return [p.strip() for p in patterns] - def _evaluate_patterns(self, patterns): - """ - Takes a list of patterns and returns a list of matching host names, - taking into account any negative and intersection patterns. - """ + @classmethod + def order_patterns(cls, patterns): # Host specifiers should be sorted to ensure consistent behavior pattern_regular = [] @@ -251,8 +249,15 @@ class Inventory(object): # when applying the host selectors, run those without the "&" or "!" # first, then the &s, then the !s. - patterns = pattern_regular + pattern_intersection + pattern_exclude + return pattern_regular + pattern_intersection + pattern_exclude + + def _evaluate_patterns(self, patterns): + """ + Takes a list of patterns and returns a list of matching host names, + taking into account any negative and intersection patterns. + """ + patterns = Inventory.order_patterns(patterns) hosts = [] for p in patterns: @@ -575,7 +580,7 @@ class Inventory(object): if subset_pattern is None: self._subset = None else: - subset_patterns = self._split_pattern(subset_pattern) + subset_patterns = Inventory.split_host_pattern(subset_pattern) results = [] # allow Unix style @filename data for x in subset_patterns: diff --git a/lib/ansible/plugins/lookup/inventory_hostnames.py b/lib/ansible/plugins/lookup/inventory_hostnames.py index 046e1482597..118f3d163ff 100644 --- a/lib/ansible/plugins/lookup/inventory_hostnames.py +++ b/lib/ansible/plugins/lookup/inventory_hostnames.py @@ -21,18 +21,35 @@ __metaclass__ = type from ansible.errors import * from ansible.plugins.lookup import LookupBase +from ansible.inventory import Inventory class LookupModule(LookupBase): - def run(self, terms, inject=None, **kwargs): - ### FIXME: Is this needed now that listify is run on all lookup plugin terms? - if not isinstance(terms, list): - raise AnsibleError("with_inventory_hostnames expects a list") + def get_hosts(self, variables, pattern): + #print(variables) + #print(variables['groups']) + hosts = [] + if pattern in variables['groups']: + hosts = variables['groups'][pattern] + elif pattern in variables['groups']['all']: + hosts = [pattern] + return hosts - # FIXME: the inventory is no longer available this way, so we may have - # to dump the host list into the list of variables and read it back - # in here (or the inventory sources, so we can recreate the list - # of hosts) - #return self._flatten(inventory.Inventory(self.host_list).list_hosts(terms)) - return terms + def run(self, terms, variables=None, **kwargs): + host_list = [] + + for term in terms: + patterns = Inventory.order_patterns(Inventory.split_host_pattern(term)) + + for p in patterns: + that = self.get_hosts(variables, p) + if p.startswith("!"): + host_list = [ h for h in host_list if h not in that] + elif p.startswith("&"): + host_list = [ h for h in host_list if h in that ] + else: + host_list.extend(that) + + # return unique list + return list(set(host_list)) diff --git a/test/units/inventory/test_inventory.py b/test/units/inventory/test_inventory.py index b6a5938862c..42f488aa372 100644 --- a/test/units/inventory/test_inventory.py +++ b/test/units/inventory/test_inventory.py @@ -92,10 +92,10 @@ class TestInventory(unittest.TestCase): for p in self.patterns: r = self.patterns[p] - self.assertEqual(r, self.i._split_pattern(p)) + self.assertEqual(r, self.i.split_host_pattern(p)) for p, r in self.pattern_lists: - self.assertEqual(r, self.i._split_pattern(p)) + self.assertEqual(r, self.i.split_host_pattern(p)) def test_ranges(self):