ansible: handle >2.6 magic exceptions + sys.excepthook damage

Closes #332.
pull/350/head
David Wilson 6 years ago
parent a192935daf
commit b521f215fd

@ -627,6 +627,14 @@ class NewStyleRunner(ScriptRunner):
for fullname in self.module_map['builtin']:
mitogen.core.import_module(fullname)
def _setup_excepthook(self):
"""
Starting with Ansible 2.6, some modules (file.py) install a
sys.excepthook and never clean it up. So we must preserve the original
excepthook and restore it after the run completes.
"""
self.original_excepthook = sys.excepthook
def setup(self):
super(NewStyleRunner, self).setup()
@ -640,12 +648,17 @@ class NewStyleRunner(ScriptRunner):
module_utils=self.module_map['custom'],
)
self._setup_imports()
self._setup_excepthook()
if libc__res_init:
libc__res_init()
def _revert_excepthook(self):
sys.excepthook = self.original_excepthook
def revert(self):
self._argv.revert()
self._stdio.revert()
self._revert_excepthook()
super(NewStyleRunner, self).revert()
def _get_program_filename(self):
@ -679,6 +692,20 @@ class NewStyleRunner(ScriptRunner):
else:
main_module_name = b'__main__'
def _handle_magic_exception(self, mod, exc):
"""
Beginning with Ansible >2.6, some modules (file.py) install a
sys.excepthook which is a closure over AnsibleModule, redirecting the
magical exception to AnsibleModule.fail_json().
For extra special needs bonus points, the class is not defined in
module_utils, but is defined in the module itself, meaning there is no
type for isinstance() that outlasts the invocation.
"""
klass = getattr(mod, 'AnsibleModuleError', None)
if klass and isinstance(exc, klass):
mod.module.fail_json(**exc.results)
def _run(self):
code = self._get_code()
@ -694,11 +721,15 @@ class NewStyleRunner(ScriptRunner):
)
exc = None
try:
try:
if mitogen.core.PY3:
exec(code, vars(mod))
else:
exec('exec code in vars(mod)')
except Exception as e:
self._handle_magic_exception(mod, e)
raise
except SystemExit as e:
exc = e

@ -7,3 +7,4 @@
- import_playbook: issue_152__virtualenv_python_fails.yml
- import_playbook: issue_154__module_state_leaks.yml
- import_playbook: issue_177__copy_module_failing.yml
- import_playbook: issue_332_ansiblemoduleerror_first_occurrence.yml

@ -0,0 +1,14 @@
# issue #332: Ansible 2.6 file.py started defining an excepthook and private
# AnsibleModuleError. Ensure file fails correctly.
- name: regression/issue_332_ansiblemoduleerror_first_occurrence.yml
hosts: all
tasks:
- file: path=/usr/bin/does-not-exist mode='a-s' state=file follow=yes
ignore_errors: true
register: out
- assert:
that:
- out.state == 'absent'
- out.msg == 'file (/usr/bin/does-not-exist) is absent, cannot continue'
Loading…
Cancel
Save