1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

support deterministic host ordering from group ancestors (#44067)

Fixes #44065
This commit is contained in:
Alan Rominger 2019-02-20 10:41:25 -05:00 committed by Brian Coca
parent 4b379745ca
commit 62feba3d15
2 changed files with 48 additions and 14 deletions

View file

@ -82,7 +82,7 @@ class Group:
g.deserialize(parent_data) g.deserialize(parent_data)
self.parent_groups.append(g) self.parent_groups.append(g)
def _walk_relationship(self, rel): def _walk_relationship(self, rel, include_self=False, preserve_ordering=False):
''' '''
Given `rel` that is an iterable property of Group, Given `rel` that is an iterable property of Group,
consitituting a directed acyclic graph among all groups, consitituting a directed acyclic graph among all groups,
@ -98,21 +98,34 @@ class Group:
''' '''
seen = set([]) seen = set([])
unprocessed = set(getattr(self, rel)) unprocessed = set(getattr(self, rel))
if include_self:
unprocessed.add(self)
if preserve_ordering:
ordered = [self] if include_self else []
ordered.extend(getattr(self, rel))
while unprocessed: while unprocessed:
seen.update(unprocessed) seen.update(unprocessed)
unprocessed = set(chain.from_iterable( new_unprocessed = set([])
getattr(g, rel) for g in unprocessed
))
unprocessed.difference_update(seen)
for new_item in chain.from_iterable(getattr(g, rel) for g in unprocessed):
new_unprocessed.add(new_item)
if preserve_ordering:
if new_item not in seen:
ordered.append(new_item)
new_unprocessed.difference_update(seen)
unprocessed = new_unprocessed
if preserve_ordering:
return ordered
return seen return seen
def get_ancestors(self): def get_ancestors(self):
return self._walk_relationship('parent_groups') return self._walk_relationship('parent_groups')
def get_descendants(self): def get_descendants(self, **kwargs):
return self._walk_relationship('child_groups') return self._walk_relationship('child_groups', **kwargs)
@property @property
def host_names(self): def host_names(self):
@ -215,7 +228,7 @@ class Group:
hosts = [] hosts = []
seen = {} seen = {}
for kid in self.get_descendants(): for kid in self.get_descendants(include_self=True, preserve_ordering=True):
kid_hosts = kid.hosts kid_hosts = kid.hosts
for kk in kid_hosts: for kk in kid_hosts:
if kk not in seen: if kk not in seen:
@ -223,12 +236,6 @@ class Group:
if self.name == 'all' and kk.implicit: if self.name == 'all' and kk.implicit:
continue continue
hosts.append(kk) hosts.append(kk)
for mine in self.hosts:
if mine not in seen:
seen[mine] = 1
if self.name == 'all' and mine.implicit:
continue
hosts.append(mine)
return hosts return hosts
def get_vars(self): def get_vars(self):

View file

@ -76,6 +76,33 @@ class TestGroup(unittest.TestCase):
with self.assertRaises(AnsibleError): with self.assertRaises(AnsibleError):
C.add_child_group(A) C.add_child_group(A)
def test_direct_host_ordering(self):
"""Hosts are returned in order they are added
"""
group = Group('A')
# host names not added in alphabetical order
host_name_list = ['z', 'b', 'c', 'a', 'p', 'q']
expected_hosts = []
for host_name in host_name_list:
h = Host(host_name)
group.add_host(h)
expected_hosts.append(h)
assert group.get_hosts() == expected_hosts
def test_sub_group_host_ordering(self):
"""With multiple nested groups, asserts that hosts are returned
in deterministic order
"""
top_group = Group('A')
expected_hosts = []
for name in ['z', 'b', 'c', 'a', 'p', 'q']:
child = Group('group_{0}'.format(name))
top_group.add_child_group(child)
host = Host('host_{0}'.format(name))
child.add_host(host)
expected_hosts.append(host)
assert top_group.get_hosts() == expected_hosts
def test_populates_descendant_hosts(self): def test_populates_descendant_hosts(self):
A = Group('A') A = Group('A')
B = Group('B') B = Group('B')