summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Coca <bcoca@users.noreply.github.com>2022-01-14 19:24:50 +0100
committerGitHub <noreply@github.com>2022-01-14 19:24:50 +0100
commit4676c08f188fb5dca98df61630c76dba1f0d2d77 (patch)
tree5f208dcaf516408634aea44c63c86170910e1a57
parentansible-config avoid _terms and _input in --only-changed (#76597) (diff)
downloadansible-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.yml4
-rw-r--r--lib/ansible/module_utils/basic.py15
-rw-r--r--lib/ansible/module_utils/facts/system/caps.py52
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