Commit f63904fd by Michael DeHaan

Merge pull request #1750 from dhozac/intersection-host-pattern

Allow intersecting host patterns by using &
parents ea5d79a7 54b45e9b
...@@ -104,27 +104,12 @@ class Inventory(object): ...@@ -104,27 +104,12 @@ class Inventory(object):
if isinstance(pattern, list): if isinstance(pattern, list):
pattern = ';'.join(pattern) pattern = ';'.join(pattern)
patterns = pattern.replace(";",":").split(":") patterns = pattern.replace(";",":").split(":")
positive_patterns = [ p for p in patterns if not p.startswith("!") ] hosts = self._get_hosts(patterns)
negative_patterns = [ p for p in patterns if p.startswith("!") ]
# find hosts matching positive patterns
hosts = self._get_hosts(positive_patterns)
# exclude hosts mentioned in a negative pattern
if len(negative_patterns):
exclude_hosts = [ h.name for h in self._get_hosts(negative_patterns) ]
hosts = [ h for h in hosts if h.name not in exclude_hosts ]
# exclude hosts not in a subset, if defined # exclude hosts not in a subset, if defined
if self._subset: if self._subset:
positive_subsetp = [ p for p in self._subset if not p.startswith("!") ] subset = self._get_hosts(self._subset)
negative_subsetp = [ p for p in self._subset if p.startswith("!") ] hosts.intersection_update(subset)
if len(positive_subsetp):
positive_subset = [ h.name for h in self._get_hosts(positive_subsetp) ]
hosts = [ h for h in hosts if (h.name in positive_subset) ]
if len(negative_subsetp):
negative_subset = [ h.name for h in self._get_hosts(negative_subsetp) ]
hosts = [ h for h in hosts if (h.name not in negative_subset)]
# exclude hosts mentioned in any restriction (ex: failed hosts) # exclude hosts mentioned in any restriction (ex: failed hosts)
if self._restriction is not None: if self._restriction is not None:
...@@ -135,27 +120,35 @@ class Inventory(object): ...@@ -135,27 +120,35 @@ class Inventory(object):
return sorted(hosts, key=lambda x: x.name) return sorted(hosts, key=lambda x: x.name)
def _get_hosts(self, patterns): def _get_hosts(self, patterns):
""" """
finds hosts that postively match a particular list of patterns. Does not finds hosts that match a list of patterns. Handles negative
take into account negative matches. matches as well as intersection matches.
""" """
by_pattern = {} hosts = set()
for p in patterns: for p in patterns:
(name, enumeration_details) = self._enumeration_info(p) if p.startswith("!"):
hpat = self._hosts_in_unenumerated_pattern(name) # Discard excluded hosts
hpat = sorted(hpat, key=lambda x: x.name) hosts.difference_update(self.__get_hosts(p))
by_pattern[p] = hpat elif p.startswith("&"):
# Only leave the intersected hosts
hosts.intersection_update(self.__get_hosts(p))
else:
# Get all hosts from both patterns
hosts.update(self.__get_hosts(p))
return hosts
ranged = {} def __get_hosts(self, pattern):
for (pat, hosts) in by_pattern.iteritems(): """
ranged[pat] = self._apply_ranges(pat, hosts) finds hosts that postively match a particular pattern. Does not
take into account negative matches.
"""
results = [] (name, enumeration_details) = self._enumeration_info(pattern)
for (pat, hosts) in ranged.iteritems(): hpat = self._hosts_in_unenumerated_pattern(name)
results.extend(hosts) hpat = sorted(hpat, key=lambda x: x.name)
return list(set(results)) return set(self._apply_ranges(pattern, hpat))
def _enumeration_info(self, pattern): def _enumeration_info(self, pattern):
""" """
...@@ -200,7 +193,7 @@ class Inventory(object): ...@@ -200,7 +193,7 @@ class Inventory(object):
hosts = {} hosts = {}
# ignore any negative checks here, this is handled elsewhere # ignore any negative checks here, this is handled elsewhere
pattern = pattern.replace("!","") pattern = pattern.replace("!","").replace("&", "")
groups = self.get_groups() groups = self.get_groups()
for group in groups: for group in groups:
......
...@@ -177,6 +177,13 @@ class TestInventory(unittest.TestCase): ...@@ -177,6 +177,13 @@ class TestInventory(unittest.TestCase):
hosts = inventory.list_hosts("nc[2-3]:florida[1-2]") hosts = inventory.list_hosts("nc[2-3]:florida[1-2]")
self.compare(hosts, expected4, sort=False) self.compare(hosts, expected4, sort=False)
def test_complex_intersect(self):
inventory = self.complex_inventory()
hosts = inventory.list_hosts("nc:&redundantgroup:!rtp_c")
self.compare(hosts, ['rtp_a'])
hosts = inventory.list_hosts("nc:&triangle:!tri_c")
self.compare(hosts, ['tri_a', 'tri_b'])
################################################### ###################################################
### Inventory API tests ### Inventory API tests
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment