diff --git a/changelogs/fragments/local_facts_d.yml b/changelogs/fragments/local_facts_d.yml new file mode 100644 index 00000000000..884abc74ba3 --- /dev/null +++ b/changelogs/fragments/local_facts_d.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - local - handle error while parsing values in ini files (https://github.com/ansible/ansible/issues/82717). diff --git a/lib/ansible/module_utils/facts/system/local.py b/lib/ansible/module_utils/facts/system/local.py index 3d656f5a345..66ec58a2e7d 100644 --- a/lib/ansible/module_utils/facts/system/local.py +++ b/lib/ansible/module_utils/facts/system/local.py @@ -1,17 +1,5 @@ -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# Copyright: Contributors to the Ansible project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations @@ -25,7 +13,6 @@ import ansible.module_utils.compat.typing as t from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.facts.utils import get_file_content from ansible.module_utils.facts.collector import BaseFactCollector -from ansible.module_utils.six import PY3 from ansible.module_utils.six.moves import configparser, StringIO @@ -91,12 +78,9 @@ class LocalFactCollector(BaseFactCollector): # if that fails read it with ConfigParser cp = configparser.ConfigParser() try: - if PY3: - cp.read_file(StringIO(out)) - else: - cp.readfp(StringIO(out)) + cp.read_file(StringIO(out)) except configparser.Error: - fact = "error loading facts as JSON or ini - please check content: %s" % fn + fact = f"error loading facts as JSON or ini - please check content: {fn}" module.warn(fact) else: fact = {} @@ -104,8 +88,14 @@ class LocalFactCollector(BaseFactCollector): if sect not in fact: fact[sect] = {} for opt in cp.options(sect): - val = cp.get(sect, opt) - fact[sect][opt] = val + try: + val = cp.get(sect, opt) + except configparser.Error as ex: + fact = f"error loading facts as ini - please check content: {fn} ({ex})" + module.warn(fact) + continue + else: + fact[sect][opt] = val except Exception as e: fact = "Failed to convert (%s) to JSON: %s" % (fn, to_text(e)) module.warn(fact) diff --git a/test/integration/targets/facts_d/files/bad.fact b/test/integration/targets/facts_d/files/bad.fact new file mode 100644 index 00000000000..b504ac2b995 --- /dev/null +++ b/test/integration/targets/facts_d/files/bad.fact @@ -0,0 +1,2 @@ +[bad fact] +value = this is a % bad % fact diff --git a/test/integration/targets/facts_d/tasks/main.yml b/test/integration/targets/facts_d/tasks/main.yml index f2cdf3449e6..279b1893e2e 100644 --- a/test/integration/targets/facts_d/tasks/main.yml +++ b/test/integration/targets/facts_d/tasks/main.yml @@ -19,6 +19,7 @@ mode: '0775' - name: unreadable mode: '0000' + - name: bad - name: Create dangling symlink file: @@ -39,15 +40,16 @@ - name: check for expected results from local facts assert: that: - - "'ansible_facts' in setup_result" - - "'ansible_local' in setup_result.ansible_facts" - - "'ansible_env' not in setup_result.ansible_facts" - - "'ansible_user_id' not in setup_result.ansible_facts" - - "'preferences' in setup_result.ansible_facts['ansible_local']" - - "'general' in setup_result.ansible_facts['ansible_local']['preferences']" - - "'bar' in setup_result.ansible_facts['ansible_local']['preferences']['general']" - - "setup_result.ansible_facts['ansible_local']['preferences']['general']['bar'] == 'loaded'" - - setup_result['ansible_facts']['ansible_local']['goodscript']['script_ran']|bool - - setup_result['ansible_facts']['ansible_local']['basdscript'].startswith("Failure executing fact script") - - setup_result['ansible_facts']['ansible_local']['unreadable'].startswith('error loading facts') - - setup_result['ansible_facts']['ansible_local']['dead_symlink'].startswith('Could not stat fact') + - "'ansible_facts' in setup_result" + - "'ansible_local' in setup_result.ansible_facts" + - "'ansible_env' not in setup_result.ansible_facts" + - "'ansible_user_id' not in setup_result.ansible_facts" + - "'preferences' in setup_result.ansible_facts['ansible_local']" + - "'general' in setup_result.ansible_facts['ansible_local']['preferences']" + - "'bar' in setup_result.ansible_facts['ansible_local']['preferences']['general']" + - "setup_result.ansible_facts['ansible_local']['preferences']['general']['bar'] == 'loaded'" + - setup_result['ansible_facts']['ansible_local']['goodscript']['script_ran']|bool + - setup_result['ansible_facts']['ansible_local']['basdscript'].startswith("Failure executing fact script") + - setup_result['ansible_facts']['ansible_local']['unreadable'].startswith('error loading facts') + - setup_result['ansible_facts']['ansible_local']['dead_symlink'].startswith('Could not stat fact') + - setup_result['ansible_facts']['ansible_local']['bad'].startswith('error loading facts as ini')