Merge pull request #719 from s1113950/issue672
Resolves ansible 2.9+, Mitogen, and Python 3.5 setup module issue
This commit is contained in:
commit
3a52b44b6b
|
@ -96,6 +96,9 @@ class Invocation(object):
|
||||||
#: Initially ``None``, but set by :func:`invoke`. The raw source or
|
#: Initially ``None``, but set by :func:`invoke`. The raw source or
|
||||||
#: binary contents of the module.
|
#: binary contents of the module.
|
||||||
self._module_source = None
|
self._module_source = None
|
||||||
|
#: Initially ``{}``, but set by :func:`invoke`. Optional source to send
|
||||||
|
#: to :func:`propagate_paths_and_modules` to fix Python3.5 relative import errors
|
||||||
|
self._overridden_sources = {}
|
||||||
|
|
||||||
def get_module_source(self):
|
def get_module_source(self):
|
||||||
if self._module_source is None:
|
if self._module_source is None:
|
||||||
|
@ -476,6 +479,7 @@ def _propagate_deps(invocation, planner, context):
|
||||||
context=context,
|
context=context,
|
||||||
paths=planner.get_push_files(),
|
paths=planner.get_push_files(),
|
||||||
modules=planner.get_module_deps(),
|
modules=planner.get_module_deps(),
|
||||||
|
overridden_sources=invocation._overridden_sources
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -533,6 +537,26 @@ def _get_planner(name, path, source):
|
||||||
raise ansible.errors.AnsibleError(NO_METHOD_MSG + repr(invocation))
|
raise ansible.errors.AnsibleError(NO_METHOD_MSG + repr(invocation))
|
||||||
|
|
||||||
|
|
||||||
|
def _fix_py35(invocation, module_source):
|
||||||
|
"""
|
||||||
|
super edge case with a relative import error in Python 3.5.1-3.5.3
|
||||||
|
in Ansible's setup module when using Mitogen
|
||||||
|
https://github.com/dw/mitogen/issues/672#issuecomment-636408833
|
||||||
|
We replace a relative import in the setup module with the actual full file path
|
||||||
|
This works in vanilla Ansible but not in Mitogen otherwise
|
||||||
|
"""
|
||||||
|
if invocation.module_name == 'setup' and \
|
||||||
|
invocation.module_path not in invocation._overridden_sources:
|
||||||
|
# in-memory replacement of setup module's relative import
|
||||||
|
# would check for just python3.5 and run this then but we don't know the
|
||||||
|
# target python at this time yet
|
||||||
|
module_source = module_source.replace(
|
||||||
|
b"from ...module_utils.basic import AnsibleModule",
|
||||||
|
b"from ansible.module_utils.basic import AnsibleModule"
|
||||||
|
)
|
||||||
|
invocation._overridden_sources[invocation.module_path] = module_source
|
||||||
|
|
||||||
|
|
||||||
def invoke(invocation):
|
def invoke(invocation):
|
||||||
"""
|
"""
|
||||||
Find a Planner subclass corresponding to `invocation` and use it to invoke
|
Find a Planner subclass corresponding to `invocation` and use it to invoke
|
||||||
|
@ -555,10 +579,12 @@ def invoke(invocation):
|
||||||
|
|
||||||
invocation.module_path = mitogen.core.to_text(path)
|
invocation.module_path = mitogen.core.to_text(path)
|
||||||
if invocation.module_path not in _planner_by_path:
|
if invocation.module_path not in _planner_by_path:
|
||||||
|
module_source = invocation.get_module_source()
|
||||||
|
_fix_py35(invocation, module_source)
|
||||||
_planner_by_path[invocation.module_path] = _get_planner(
|
_planner_by_path[invocation.module_path] = _get_planner(
|
||||||
invocation.module_name,
|
invocation.module_name,
|
||||||
invocation.module_path,
|
invocation.module_path,
|
||||||
invocation.get_module_source()
|
module_source
|
||||||
)
|
)
|
||||||
|
|
||||||
planner = _planner_by_path[invocation.module_path](invocation)
|
planner = _planner_by_path[invocation.module_path](invocation)
|
||||||
|
|
|
@ -746,13 +746,18 @@ class PushFileService(Service):
|
||||||
'paths': list,
|
'paths': list,
|
||||||
'modules': list,
|
'modules': list,
|
||||||
})
|
})
|
||||||
def propagate_paths_and_modules(self, context, paths, modules):
|
def propagate_paths_and_modules(self, context, paths, modules, overridden_sources=None):
|
||||||
"""
|
"""
|
||||||
One size fits all method to ensure a target context has been preloaded
|
One size fits all method to ensure a target context has been preloaded
|
||||||
with a set of small files and Python modules.
|
with a set of small files and Python modules.
|
||||||
|
|
||||||
|
overridden_sources: optional dict containing source code to override path's source code
|
||||||
"""
|
"""
|
||||||
for path in paths:
|
for path in paths:
|
||||||
self.propagate_to(context, mitogen.core.to_text(path))
|
overridden_source = None
|
||||||
|
if overridden_sources is not None and path in overridden_sources:
|
||||||
|
overridden_source = overridden_sources[path]
|
||||||
|
self.propagate_to(context, mitogen.core.to_text(path), overridden_source)
|
||||||
#self.router.responder.forward_modules(context, modules) TODO
|
#self.router.responder.forward_modules(context, modules) TODO
|
||||||
|
|
||||||
@expose(policy=AllowParents())
|
@expose(policy=AllowParents())
|
||||||
|
@ -760,14 +765,22 @@ class PushFileService(Service):
|
||||||
'context': mitogen.core.Context,
|
'context': mitogen.core.Context,
|
||||||
'path': mitogen.core.FsPathTypes,
|
'path': mitogen.core.FsPathTypes,
|
||||||
})
|
})
|
||||||
def propagate_to(self, context, path):
|
def propagate_to(self, context, path, overridden_source=None):
|
||||||
|
"""
|
||||||
|
If the optional parameter 'overridden_source' is passed, use
|
||||||
|
that instead of the path's code as source code. This works around some bugs
|
||||||
|
of source modules such as relative imports on unsupported Python versions
|
||||||
|
"""
|
||||||
if path not in self._cache:
|
if path not in self._cache:
|
||||||
LOG.debug('caching small file %s', path)
|
LOG.debug('caching small file %s', path)
|
||||||
|
if overridden_source is None:
|
||||||
fp = open(path, 'rb')
|
fp = open(path, 'rb')
|
||||||
try:
|
try:
|
||||||
self._cache[path] = mitogen.core.Blob(fp.read())
|
self._cache[path] = mitogen.core.Blob(fp.read())
|
||||||
finally:
|
finally:
|
||||||
fp.close()
|
fp.close()
|
||||||
|
else:
|
||||||
|
self._cache[path] = mitogen.core.Blob(overridden_source)
|
||||||
self._forward(context, path)
|
self._forward(context, path)
|
||||||
|
|
||||||
@expose(policy=AllowParents())
|
@expose(policy=AllowParents())
|
||||||
|
|
Loading…
Reference in New Issue