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:
parent
4b379745ca
commit
62feba3d15
2 changed files with 48 additions and 14 deletions
|
@ -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):
|
||||||
|
|
|
@ -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')
|
||||||
|
|
Loading…
Reference in a new issue