issue #477: backport ansible_mitogen.runner to 2.4.

issue510
David Wilson 7 years ago
parent 0b0ae5c971
commit 81f15028a7

@ -26,7 +26,6 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
""" """
These classes implement execution for each style of Ansible module. They are These classes implement execution for each style of Ansible module. They are
instantiated in the target context by way of target.py::run_module(). instantiated in the target context by way of target.py::run_module().
@ -35,14 +34,8 @@ Each class in here has a corresponding Planner class in planners.py that knows
how to build arguments for it, preseed related data, etc. how to build arguments for it, preseed related data, etc.
""" """
from __future__ import absolute_import
from __future__ import unicode_literals
import atexit import atexit
import ctypes
import imp import imp
import json
import logging
import os import os
import shlex import shlex
import shutil import shutil
@ -52,6 +45,21 @@ import types
import mitogen.core import mitogen.core
import ansible_mitogen.target # TODO: circular import import ansible_mitogen.target # TODO: circular import
from mitogen.core import b
from mitogen.core import bytes_partition
from mitogen.core import str_rpartition
try:
import ctypes
except ImportError:
# Python 2.4
ctypes = None
try:
import json
except ImportError:
# Python 2.4
import simplejson as json
try: try:
# Cannot use cStringIO as it does not support Unicode. # Cannot use cStringIO as it does not support Unicode.
@ -64,6 +72,10 @@ try:
except ImportError: except ImportError:
from pipes import quote as shlex_quote from pipes import quote as shlex_quote
# Absolute imports for <2.5.
logging = __import__('logging')
# Prevent accidental import of an Ansible module from hanging on stdin read. # Prevent accidental import of an Ansible module from hanging on stdin read.
import ansible.module_utils.basic import ansible.module_utils.basic
ansible.module_utils.basic._ANSIBLE_ARGS = '{}' ansible.module_utils.basic._ANSIBLE_ARGS = '{}'
@ -72,13 +84,14 @@ ansible.module_utils.basic._ANSIBLE_ARGS = '{}'
# resolv.conf at startup and never implicitly reload it. Cope with that via an # resolv.conf at startup and never implicitly reload it. Cope with that via an
# explicit call to res_init() on each task invocation. BSD-alikes export it # explicit call to res_init() on each task invocation. BSD-alikes export it
# directly, Linux #defines it as "__res_init". # directly, Linux #defines it as "__res_init".
libc = ctypes.CDLL(None)
libc__res_init = None libc__res_init = None
for symbol in 'res_init', '__res_init': if ctypes:
try: libc = ctypes.CDLL(None)
libc__res_init = getattr(libc, symbol) for symbol in 'res_init', '__res_init':
except AttributeError: try:
pass libc__res_init = getattr(libc, symbol)
except AttributeError:
pass
iteritems = getattr(dict, 'iteritems', dict.items) iteritems = getattr(dict, 'iteritems', dict.items)
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -118,8 +131,11 @@ class EnvironmentFileWatcher(object):
def _load(self): def _load(self):
try: try:
with open(self.path, 'r') as fp: fp = open(self.path, 'r')
try:
return list(self._parse(fp)) return list(self._parse(fp))
finally:
fp.close()
except IOError: except IOError:
return [] return []
@ -136,7 +152,7 @@ class EnvironmentFileWatcher(object):
if bits[0] == 'export': if bits[0] == 'export':
bits.pop(0) bits.pop(0)
key, sep, value = (' '.join(bits)).partition('=') key, sep, value = bytes_partition(' '.join(bits), '=')
if key and sep: if key and sep:
yield key, value yield key, value
@ -437,7 +453,7 @@ class ModuleUtilsImporter(object):
mod.__path__ = [] mod.__path__ = []
mod.__package__ = str(fullname) mod.__package__ = str(fullname)
else: else:
mod.__package__ = str(fullname.rpartition('.')[0]) mod.__package__ = str(str_rpartition(fullname, '.')[0])
exec(code, mod.__dict__) exec(code, mod.__dict__)
self._loaded.add(fullname) self._loaded.add(fullname)
return mod return mod
@ -581,7 +597,7 @@ class ProgramRunner(Runner):
Return the final argument vector used to execute the program. Return the final argument vector used to execute the program.
""" """
return [ return [
self.args['_ansible_shell_executable'], self.args.get('_ansible_shell_executable', '/bin/sh'),
'-c', '-c',
self._get_shell_fragment(), self._get_shell_fragment(),
] ]
@ -598,18 +614,19 @@ class ProgramRunner(Runner):
args=self._get_argv(), args=self._get_argv(),
emulate_tty=self.emulate_tty, emulate_tty=self.emulate_tty,
) )
except Exception as e: except Exception:
LOG.exception('While running %s', self._get_argv()) LOG.exception('While running %s', self._get_argv())
e = sys.exc_info()[1]
return { return {
'rc': 1, u'rc': 1,
'stdout': '', u'stdout': u'',
'stderr': '%s: %s' % (type(e), e), u'stderr': u'%s: %s' % (type(e), e),
} }
return { return {
'rc': rc, u'rc': rc,
'stdout': mitogen.core.to_text(stdout), u'stdout': mitogen.core.to_text(stdout),
'stderr': mitogen.core.to_text(stderr), u'stderr': mitogen.core.to_text(stderr),
} }
@ -659,7 +676,7 @@ class ScriptRunner(ProgramRunner):
self.interpreter_fragment = interpreter_fragment self.interpreter_fragment = interpreter_fragment
self.is_python = is_python self.is_python = is_python
b_ENCODING_STRING = b'# -*- coding: utf-8 -*-' b_ENCODING_STRING = b('# -*- coding: utf-8 -*-')
def _get_program(self): def _get_program(self):
return self._rewrite_source( return self._rewrite_source(
@ -668,7 +685,7 @@ class ScriptRunner(ProgramRunner):
def _get_argv(self): def _get_argv(self):
return [ return [
self.args['_ansible_shell_executable'], self.args.get('_ansible_shell_executable', '/bin/sh'),
'-c', '-c',
self._get_shell_fragment(), self._get_shell_fragment(),
] ]
@ -692,13 +709,13 @@ class ScriptRunner(ProgramRunner):
# While Ansible rewrites the #! using ansible_*_interpreter, it is # While Ansible rewrites the #! using ansible_*_interpreter, it is
# never actually used to execute the script, instead it is a shell # never actually used to execute the script, instead it is a shell
# fragment consumed by shell/__init__.py::build_module_command(). # fragment consumed by shell/__init__.py::build_module_command().
new = [b'#!' + utf8(self.interpreter_fragment)] new = [b('#!') + utf8(self.interpreter_fragment)]
if self.is_python: if self.is_python:
new.append(self.b_ENCODING_STRING) new.append(self.b_ENCODING_STRING)
_, _, rest = s.partition(b'\n') _, _, rest = bytes_partition(s, b('\n'))
new.append(rest) new.append(rest)
return b'\n'.join(new) return b('\n').join(new)
class NewStyleRunner(ScriptRunner): class NewStyleRunner(ScriptRunner):
@ -786,16 +803,18 @@ class NewStyleRunner(ScriptRunner):
return self._code_by_path[self.path] return self._code_by_path[self.path]
except KeyError: except KeyError:
return self._code_by_path.setdefault(self.path, compile( return self._code_by_path.setdefault(self.path, compile(
source=self.source, # Py2.4 doesn't support kwargs.
filename="master:" + self.path, self.source, # source
mode='exec', "master:" + self.path, # filename
dont_inherit=True, 'exec', # mode
0, # flags
True, # dont_inherit
)) ))
if mitogen.core.PY3: if mitogen.core.PY3:
main_module_name = '__main__' main_module_name = '__main__'
else: else:
main_module_name = b'__main__' main_module_name = b('__main__')
def _handle_magic_exception(self, mod, exc): def _handle_magic_exception(self, mod, exc):
""" """
@ -817,8 +836,8 @@ class NewStyleRunner(ScriptRunner):
exec(code, vars(mod)) exec(code, vars(mod))
else: else:
exec('exec code in vars(mod)') exec('exec code in vars(mod)')
except Exception as e: except Exception:
self._handle_magic_exception(mod, e) self._handle_magic_exception(mod, sys.exc_info()[1])
raise raise
def _run(self): def _run(self):
@ -834,24 +853,25 @@ class NewStyleRunner(ScriptRunner):
) )
code = self._get_code() code = self._get_code()
exc = None rc = 2
try: try:
try: try:
self._run_code(code, mod) self._run_code(code, mod)
except SystemExit as e: except SystemExit:
exc = e exc = sys.exc_info()[1]
rc = exc.args[0]
finally: finally:
self.atexit_wrapper.run_callbacks() self.atexit_wrapper.run_callbacks()
return { return {
'rc': exc.args[0] if exc else 2, u'rc': rc,
'stdout': mitogen.core.to_text(sys.stdout.getvalue()), u'stdout': mitogen.core.to_text(sys.stdout.getvalue()),
'stderr': mitogen.core.to_text(sys.stderr.getvalue()), u'stderr': mitogen.core.to_text(sys.stderr.getvalue()),
} }
class JsonArgsRunner(ScriptRunner): class JsonArgsRunner(ScriptRunner):
JSON_ARGS = b'<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>' JSON_ARGS = b('<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>')
def _get_args_contents(self): def _get_args_contents(self):
return json.dumps(self.args).encode() return json.dumps(self.args).encode()

Loading…
Cancel
Save