prevent fact gathering from breaking on bad caps (#76691)

* prevent fact gathering from breaking on bad caps

 fxies #75832
pull/76765/head
Brian Coca 3 years ago committed by GitHub
parent 2246ed9678
commit 4676c08f18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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

@ -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, 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', 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. 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`` :kw ignore_invalid_cwd: This flag indicates whether an invalid ``cwd``
(non-existent or not a directory) should be ignored or should raise (non-existent or not a directory) should be ignored or should raise
an exception. 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), :returns: A 3-tuple of return code (integer), stdout (native string),
and stderr (native string). On python2, stdout and stderr are both and stderr (native string). On python2, stdout and stderr are both
byte strings. On python3, stdout and stderr are text strings converted byte strings. On python3, stdout and stderr are text strings converted
@ -2080,10 +2083,16 @@ class AnsibleModule(object):
rc = cmd.returncode rc = cmd.returncode
except (OSError, IOError) as e: except (OSError, IOError) as e:
self.log("Error Executing CMD:%s Exception:%s" % (self._clean_args(args), to_native(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: except Exception as e:
self.log("Error Executing CMD:%s Exception:%s" % (self._clean_args(args), to_native(traceback.format_exc()))) 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: if rc != 0 and check_rc:
msg = heuristic_log_sanitize(stderr.rstrip(), self.no_log_values) msg = heuristic_log_sanitize(stderr.rstrip(), self.no_log_values)

@ -19,6 +19,7 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
from ansible.module_utils._text import to_text
from ansible.module_utils.facts.collector import BaseFactCollector from ansible.module_utils.facts.collector import BaseFactCollector
@ -28,28 +29,33 @@ class SystemCapabilitiesFactCollector(BaseFactCollector):
'system_capabilities_enforced']) 'system_capabilities_enforced'])
def collect(self, module=None, collected_facts=None): def collect(self, module=None, collected_facts=None):
facts_dict = {}
if not module: rc = -1
return facts_dict facts_dict = {'system_capabilities_enforced': 'N/A',
'system_capabilities': 'N/A'}
capsh_path = module.get_bin_path('capsh') if module:
# NOTE: early exit 'if not crash_path' and unindent rest of method -akl capsh_path = module.get_bin_path('capsh')
if capsh_path: if capsh_path:
# NOTE: -> get_caps_data()/parse_caps_data() for easier mocking -akl # NOTE: -> get_caps_data()/parse_caps_data() for easier mocking -akl
rc, out, err = module.run_command([capsh_path, "--print"], errors='surrogate_then_replace') try:
enforced_caps = [] rc, out, err = module.run_command([capsh_path, "--print"], errors='surrogate_then_replace', handle_exceptions=False)
enforced = 'NA' except (IOError, OSError) as e:
for line in out.splitlines(): module.warn('Could not query system capabilities: %s' % str(e))
if len(line) < 1:
continue if rc == 0:
if line.startswith('Current:'): enforced_caps = []
if line.split(':')[1].strip() == '=ep': enforced = 'NA'
enforced = 'False' for line in out.splitlines():
else: if len(line) < 1:
enforced = 'True' continue
enforced_caps = [i.strip() for i in line.split('=')[1].split(',')] if line.startswith('Current:'):
if line.split(':')[1].strip() == '=ep':
facts_dict['system_capabilities_enforced'] = enforced enforced = 'False'
facts_dict['system_capabilities'] = enforced_caps 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 return facts_dict

Loading…
Cancel
Save