From 1d410ca700a468723be2bf76b142dc7be66401fc Mon Sep 17 00:00:00 2001 From: Ruediger Pluem <53253255+rpluem-vf@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:57:02 +0200 Subject: [PATCH] Fix local facts unreadable (#76095) * Catch exceptions during stat calls If such an exception is not caught it causes the complete local facts gathering to fail. --- changelogs/fragments/local_fact_unreadable.yml | 6 ++++++ lib/ansible/module_utils/facts/system/local.py | 11 +++++++++-- test/integration/targets/facts_d/tasks/main.yml | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/local_fact_unreadable.yml diff --git a/changelogs/fragments/local_fact_unreadable.yml b/changelogs/fragments/local_fact_unreadable.yml new file mode 100644 index 00000000000..c5e5baef5b8 --- /dev/null +++ b/changelogs/fragments/local_fact_unreadable.yml @@ -0,0 +1,6 @@ +bugfixes: + - >- + local facts - if a local fact in the facts directory cannot be stated, + store an error message as the fact value and emit a warning just as if + just as if the facts execution has failed. The stat can fail e.g. on + dangling symlinks. diff --git a/lib/ansible/module_utils/facts/system/local.py b/lib/ansible/module_utils/facts/system/local.py index 6579aae0a5b..bacdbe0d426 100644 --- a/lib/ansible/module_utils/facts/system/local.py +++ b/lib/ansible/module_utils/facts/system/local.py @@ -50,8 +50,15 @@ class LocalFactCollector(BaseFactCollector): for fn in sorted(glob.glob(fact_path + '/*.fact')): # use filename for key where it will sit under local facts fact_base = os.path.basename(fn).replace('.fact', '') - if stat.S_IXUSR & os.stat(fn)[stat.ST_MODE]: - failed = None + failed = None + try: + executable_fact = stat.S_IXUSR & os.stat(fn)[stat.ST_MODE] + except OSError as e: + failed = 'Could not stat fact (%s): %s' % (fn, to_text(e)) + local[fact_base] = failed + module.warn(failed) + continue + if executable_fact: try: # run it rc, out, err = module.run_command(fn) diff --git a/test/integration/targets/facts_d/tasks/main.yml b/test/integration/targets/facts_d/tasks/main.yml index 7f7b5f96477..f2cdf3449e6 100644 --- a/test/integration/targets/facts_d/tasks/main.yml +++ b/test/integration/targets/facts_d/tasks/main.yml @@ -20,6 +20,13 @@ - name: unreadable mode: '0000' + - name: Create dangling symlink + file: + path: "{{ fact_dir }}/dead_symlink.fact" + src: /tmp/dead_symlink + force: yes + state: link + - name: force fact gather to get ansible_local setup: fact_path: "{{ fact_dir | expanduser }}" @@ -43,3 +50,4 @@ - 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')