diff options
author | Brian Coca <bcoca@users.noreply.github.com> | 2022-01-14 19:24:50 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-14 19:24:50 +0100 |
commit | 4676c08f188fb5dca98df61630c76dba1f0d2d77 (patch) | |
tree | 5f208dcaf516408634aea44c63c86170910e1a57 | |
parent | ansible-config avoid _terms and _input in --only-changed (#76597) (diff) | |
download | ansible-4676c08f188fb5dca98df61630c76dba1f0d2d77.tar.xz ansible-4676c08f188fb5dca98df61630c76dba1f0d2d77.zip |
prevent fact gathering from breaking on bad caps (#76691)
* prevent fact gathering from breaking on bad caps
fxies #75832
-rw-r--r-- | changelogs/fragments/runc_command_exception_toggle.yml | 4 | ||||
-rw-r--r-- | lib/ansible/module_utils/basic.py | 15 | ||||
-rw-r--r-- | lib/ansible/module_utils/facts/system/caps.py | 52 |
3 files changed, 45 insertions, 26 deletions
diff --git a/changelogs/fragments/runc_command_exception_toggle.yml b/changelogs/fragments/runc_command_exception_toggle.yml new file mode 100644 index 0000000000..15883d5b32 --- /dev/null +++ b/changelogs/fragments/runc_command_exception_toggle.yml @@ -0,0 +1,4 @@ +minor_changes: + - AnsibleModule.run_command() now has a toggle to allow caller to decide to handle exceptions from executing the command itself +bugfixes: + - gather_facts/setup will not fail anymore if capsh is present but not executable diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index b55f9d433d..3aad634cf6 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -1837,7 +1837,7 @@ class AnsibleModule(object): def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict', - expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None, ignore_invalid_cwd=True): + expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None, ignore_invalid_cwd=True, handle_exceptions=True): ''' Execute a command, returns rc, stdout, and stderr. @@ -1891,6 +1891,9 @@ class AnsibleModule(object): :kw ignore_invalid_cwd: This flag indicates whether an invalid ``cwd`` (non-existent or not a directory) should be ignored or should raise an exception. + :kw handle_exceptions: This flag indicates whether an exception will + be handled inline and issue a failed_json or if the caller should + handle it. :returns: A 3-tuple of return code (integer), stdout (native string), and stderr (native string). On python2, stdout and stderr are both byte strings. On python3, stdout and stderr are text strings converted @@ -2080,10 +2083,16 @@ class AnsibleModule(object): rc = cmd.returncode except (OSError, IOError) as e: self.log("Error Executing CMD:%s Exception:%s" % (self._clean_args(args), to_native(e))) - self.fail_json(rc=e.errno, stdout=b'', stderr=b'', msg=to_native(e), cmd=self._clean_args(args)) + if handle_exceptions: + self.fail_json(rc=e.errno, stdout=b'', stderr=b'', msg=to_native(e), cmd=self._clean_args(args)) + else: + raise e except Exception as e: self.log("Error Executing CMD:%s Exception:%s" % (self._clean_args(args), to_native(traceback.format_exc()))) - self.fail_json(rc=257, stdout=b'', stderr=b'', msg=to_native(e), exception=traceback.format_exc(), cmd=self._clean_args(args)) + if handle_exceptions: + self.fail_json(rc=257, stdout=b'', stderr=b'', msg=to_native(e), exception=traceback.format_exc(), cmd=self._clean_args(args)) + else: + raise e if rc != 0 and check_rc: msg = heuristic_log_sanitize(stderr.rstrip(), self.no_log_values) diff --git a/lib/ansible/module_utils/facts/system/caps.py b/lib/ansible/module_utils/facts/system/caps.py index 057eeda48e..5c376d5e6e 100644 --- a/lib/ansible/module_utils/facts/system/caps.py +++ b/lib/ansible/module_utils/facts/system/caps.py @@ -19,6 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +from ansible.module_utils._text import to_text from ansible.module_utils.facts.collector import BaseFactCollector @@ -28,28 +29,33 @@ class SystemCapabilitiesFactCollector(BaseFactCollector): 'system_capabilities_enforced']) def collect(self, module=None, collected_facts=None): - facts_dict = {} - if not module: - return facts_dict - - capsh_path = module.get_bin_path('capsh') - # NOTE: early exit 'if not crash_path' and unindent rest of method -akl - if capsh_path: - # NOTE: -> get_caps_data()/parse_caps_data() for easier mocking -akl - rc, out, err = module.run_command([capsh_path, "--print"], errors='surrogate_then_replace') - enforced_caps = [] - enforced = 'NA' - for line in out.splitlines(): - if len(line) < 1: - continue - if line.startswith('Current:'): - if line.split(':')[1].strip() == '=ep': - enforced = 'False' - else: - enforced = 'True' - enforced_caps = [i.strip() for i in line.split('=')[1].split(',')] - - facts_dict['system_capabilities_enforced'] = enforced - facts_dict['system_capabilities'] = enforced_caps + + rc = -1 + facts_dict = {'system_capabilities_enforced': 'N/A', + 'system_capabilities': 'N/A'} + if module: + capsh_path = module.get_bin_path('capsh') + if capsh_path: + # NOTE: -> get_caps_data()/parse_caps_data() for easier mocking -akl + try: + rc, out, err = module.run_command([capsh_path, "--print"], errors='surrogate_then_replace', handle_exceptions=False) + except (IOError, OSError) as e: + module.warn('Could not query system capabilities: %s' % str(e)) + + if rc == 0: + enforced_caps = [] + enforced = 'NA' + for line in out.splitlines(): + if len(line) < 1: + continue + if line.startswith('Current:'): + if line.split(':')[1].strip() == '=ep': + enforced = 'False' + else: + enforced = 'True' + enforced_caps = [i.strip() for i in line.split('=')[1].split(',')] + + facts_dict['system_capabilities_enforced'] = enforced + facts_dict['system_capabilities'] = enforced_caps return facts_dict |