|
|
|
@ -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,8 +84,9 @@ 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
|
|
|
|
|
if ctypes:
|
|
|
|
|
libc = ctypes.CDLL(None)
|
|
|
|
|
for symbol in 'res_init', '__res_init':
|
|
|
|
|
try:
|
|
|
|
|
libc__res_init = getattr(libc, symbol)
|
|
|
|
@ -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'<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>'
|
|
|
|
|
JSON_ARGS = b('<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>')
|
|
|
|
|
|
|
|
|
|
def _get_args_contents(self):
|
|
|
|
|
return json.dumps(self.args).encode()
|
|
|
|
|