mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-10-24 04:54:00 -07:00
Fix fact failures cause by ordering of collectors (#30777)
* Fix fact failures cause by ordering of collectors
Some fact collectors need info collected by other facts.
(for ex, service_mgr needs to know 'ansible_system').
This info is passed to the Collector.collect method via
the 'collected_facts' info.
But, the order the fact collectors were running in is
not a set order, so collectors like service_mgr could
run before the PlatformFactCollect ('ansible_system', etc),
so the 'ansible_system' fact would not exist yet.
Depending on the collector and the deps, this can result
in incorrect behavior and wrong or missing facts.
To make the ordering of the collectors more consistent
and predictable, the code that builds that list is now
driven by the order of collectors in default_collectors.py,
and the rest of the code tries to preserve it.
* Flip the loops when building collector names
iterate over the ordered default_collectors list
selecting them for the final list in order instead
of driving it from the unordered collector_names set.
This lets the list returned by select_collector_classes
to stay in the same order as default_collectors.collectors
For collectors that have implicit deps on other fact collectors,
the default collectors can be ordered to include those early.
* default_collectors.py now uses a handful of sub lists of
collectors that can be ordered in default_collectors.collectors.
fixes #30753
fixes #30623
This commit is contained in:
parent
c5971047a4
commit
95abc1d82e
5 changed files with 277 additions and 81 deletions
|
|
@ -20,6 +20,8 @@
|
|||
from __future__ import (absolute_import, division)
|
||||
__metaclass__ = type
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
# for testing
|
||||
from ansible.compat.tests import unittest
|
||||
|
||||
|
|
@ -28,6 +30,91 @@ from ansible.module_utils.facts import collector
|
|||
from ansible.module_utils.facts import default_collectors
|
||||
|
||||
|
||||
class TestFindCollectorsForPlatform(unittest.TestCase):
|
||||
def test(self):
|
||||
compat_platforms = [{'system': 'Generic'}]
|
||||
res = collector.find_collectors_for_platform(default_collectors.collectors,
|
||||
compat_platforms)
|
||||
for coll_class in res:
|
||||
self.assertIn(coll_class._platform, ('Generic'))
|
||||
|
||||
def test_linux(self):
|
||||
compat_platforms = [{'system': 'Linux'}]
|
||||
res = collector.find_collectors_for_platform(default_collectors.collectors,
|
||||
compat_platforms)
|
||||
for coll_class in res:
|
||||
self.assertIn(coll_class._platform, ('Linux'))
|
||||
|
||||
def test_linux_or_generic(self):
|
||||
compat_platforms = [{'system': 'Generic'}, {'system': 'Linux'}]
|
||||
res = collector.find_collectors_for_platform(default_collectors.collectors,
|
||||
compat_platforms)
|
||||
for coll_class in res:
|
||||
self.assertIn(coll_class._platform, ('Generic', 'Linux'))
|
||||
|
||||
|
||||
class TestSelectCollectorNames(unittest.TestCase):
|
||||
def test(self):
|
||||
collector_names = set(['distribution', 'all_ipv4_addresses',
|
||||
'local', 'pkg_mgr'])
|
||||
all_fact_subsets = self._all_fact_subsets()
|
||||
all_collector_classes = self._all_collector_classes()
|
||||
res = collector.select_collector_classes(collector_names,
|
||||
all_fact_subsets,
|
||||
all_collector_classes)
|
||||
|
||||
expected = [default_collectors.DistributionFactCollector,
|
||||
default_collectors.PkgMgrFactCollector]
|
||||
|
||||
self.assertEqual(res, expected)
|
||||
|
||||
def test_reverse(self):
|
||||
collector_names = set(['distribution', 'all_ipv4_addresses',
|
||||
'local', 'pkg_mgr'])
|
||||
all_fact_subsets = self._all_fact_subsets()
|
||||
all_collector_classes = self._all_collector_classes()
|
||||
all_collector_classes.reverse()
|
||||
res = collector.select_collector_classes(collector_names,
|
||||
all_fact_subsets,
|
||||
all_collector_classes)
|
||||
|
||||
expected = [default_collectors.PkgMgrFactCollector,
|
||||
default_collectors.DistributionFactCollector]
|
||||
|
||||
self.assertEqual(res, expected)
|
||||
|
||||
def test_default_collectors(self):
|
||||
platform_info = {'system': 'Generic'}
|
||||
compat_platforms = [platform_info]
|
||||
collectors_for_platform = collector.find_collectors_for_platform(default_collectors.collectors,
|
||||
compat_platforms)
|
||||
|
||||
all_fact_subsets, aliases_map = collector.build_fact_id_to_collector_map(collectors_for_platform)
|
||||
|
||||
all_valid_subsets = frozenset(all_fact_subsets.keys())
|
||||
collector_names = collector.get_collector_names(valid_subsets=all_valid_subsets,
|
||||
aliases_map=aliases_map,
|
||||
platform_info=platform_info)
|
||||
collector.select_collector_classes(collector_names,
|
||||
all_fact_subsets,
|
||||
default_collectors.collectors)
|
||||
|
||||
def _all_collector_classes(self):
|
||||
return [default_collectors.DistributionFactCollector,
|
||||
default_collectors.PkgMgrFactCollector,
|
||||
default_collectors.LinuxNetworkCollector]
|
||||
|
||||
def _all_fact_subsets(self, data=None):
|
||||
all_fact_subsets = defaultdict(list)
|
||||
_data = {'pkg_mgr': [default_collectors.PkgMgrFactCollector],
|
||||
'distribution': [default_collectors.DistributionFactCollector],
|
||||
'network': [default_collectors.LinuxNetworkCollector]}
|
||||
data = data or _data
|
||||
for key, value in data.items():
|
||||
all_fact_subsets[key] = value
|
||||
return all_fact_subsets
|
||||
|
||||
|
||||
class TestGetCollectorNames(unittest.TestCase):
|
||||
def test_none(self):
|
||||
res = collector.get_collector_names()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue