diff --git a/changelogs/fragments/systemd_facts.yml b/changelogs/fragments/systemd_facts.yml new file mode 100644 index 00000000000..2015e64babc --- /dev/null +++ b/changelogs/fragments/systemd_facts.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - systemd facts - handle AttributeError raised while gathering facts on non-systemd hosts. diff --git a/lib/ansible/module_utils/facts/collector.py b/lib/ansible/module_utils/facts/collector.py index 616188b3db9..0983df7aad4 100644 --- a/lib/ansible/module_utils/facts/collector.py +++ b/lib/ansible/module_utils/facts/collector.py @@ -90,6 +90,8 @@ class BaseFactCollector: def _transform_dict_keys(self, fact_dict): '''update a dicts keys to use new names as transformed by self._transform_name''' + if fact_dict is None: + return {} for old_key in list(fact_dict.keys()): new_key = self._transform_name(old_key) # pop the item by old_key and replace it using new_key diff --git a/lib/ansible/module_utils/facts/system/systemd.py b/lib/ansible/module_utils/facts/system/systemd.py index 154dc73fb2a..3ba2bbfcbdf 100644 --- a/lib/ansible/module_utils/facts/system/systemd.py +++ b/lib/ansible/module_utils/facts/system/systemd.py @@ -29,19 +29,19 @@ class SystemdFactCollector(BaseFactCollector): def collect(self, module=None, collected_facts=None): systemctl_bin = module.get_bin_path("systemctl") + systemd_facts = {} if systemctl_bin and ServiceMgrFactCollector.is_systemd_managed(module): - rc, stdout, stderr = module.run_command( + rc, stdout, dummy = module.run_command( [systemctl_bin, "--version"], check_rc=False, ) - systemd_facts = {} - if rc != 0: return systemd_facts - systemd_facts["systemd"] = {} - systemd_facts["systemd"]["features"] = str(stdout.split("\n")[1]) - systemd_facts["systemd"]["version"] = int(stdout.split(" ")[1]) + systemd_facts["systemd"] = { + "features": str(stdout.split("\n")[1]), + "version": int(stdout.split(" ")[1]), + } - return systemd_facts + return systemd_facts diff --git a/test/units/module_utils/facts/test_ansible_collector.py b/test/units/module_utils/facts/test_ansible_collector.py index 3316464c47b..badfddd9d8c 100644 --- a/test/units/module_utils/facts/test_ansible_collector.py +++ b/test/units/module_utils/facts/test_ansible_collector.py @@ -378,7 +378,7 @@ class TestCollectorDepsWithFilter(unittest.TestCase): facts_dict = fact_collector.collect(module=_mock_module, collected_facts=collected_facts) self.assertIn('concat_fact', facts_dict) - self.assertTrue('THE_NEEDED_FACT_VALUE' in facts_dict['concat_fact']) + self.assertIn('THE_NEEDED_FACT_VALUE', facts_dict['concat_fact']) def test_concat_collector_with_filter_on_concat(self): _mock_module = mock_module(gather_subset=['all', '!facter', '!ohai'], @@ -396,8 +396,8 @@ class TestCollectorDepsWithFilter(unittest.TestCase): facts_dict = fact_collector.collect(module=_mock_module, collected_facts=collected_facts) self.assertIn('concat_fact', facts_dict) - self.assertTrue('THE_NEEDED_FACT_VALUE' in facts_dict['concat_fact']) - self.assertTrue('compound' in facts_dict['concat_fact']) + self.assertIn('THE_NEEDED_FACT_VALUE', facts_dict['concat_fact']) + self.assertIn('compound', facts_dict['concat_fact']) def _collect(self, _mock_module, collected_facts=None): _collectors = self._collectors(_mock_module) @@ -439,6 +439,21 @@ class TestOnlyExceptionCollector(TestCollectedFacts): return [ExceptionThrowingCollector()] +class NoneReturningCollector(collector.BaseFactCollector): + def collect(self, module=None, collected_facts=None): + return None + + +class TestOnlyNoneCollector(TestCollectedFacts): + expected_facts = [] + min_fact_count = 0 + + def _collectors(self, module, + all_collector_classes=None, + minimal_gather_subset=None): + return [NoneReturningCollector(namespace='ansible')] + + class TestMinimalCollectedFacts(TestCollectedFacts): gather_subset = ['!all'] min_fact_count = 1