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