Skip to content

Commit 3a52b44

Browse files
authored
Merge pull request #719 from s1113950/issue672
Resolves ansible 2.9+, Mitogen, and Python 3.5 setup module issue
2 parents 67f1ca9 + 81076c9 commit 3a52b44

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

ansible_mitogen/planner.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ def __init__(self, action, connection, module_name, module_args,
9696
#: Initially ``None``, but set by :func:`invoke`. The raw source or
9797
#: binary contents of the module.
9898
self._module_source = None
99+
#: Initially ``{}``, but set by :func:`invoke`. Optional source to send
100+
#: to :func:`propagate_paths_and_modules` to fix Python3.5 relative import errors
101+
self._overridden_sources = {}
99102

100103
def get_module_source(self):
101104
if self._module_source is None:
@@ -476,6 +479,7 @@ def _propagate_deps(invocation, planner, context):
476479
context=context,
477480
paths=planner.get_push_files(),
478481
modules=planner.get_module_deps(),
482+
overridden_sources=invocation._overridden_sources
479483
)
480484

481485

@@ -533,6 +537,26 @@ def _get_planner(name, path, source):
533537
raise ansible.errors.AnsibleError(NO_METHOD_MSG + repr(invocation))
534538

535539

540+
def _fix_py35(invocation, module_source):
541+
"""
542+
super edge case with a relative import error in Python 3.5.1-3.5.3
543+
in Ansible's setup module when using Mitogen
544+
https://github.com/dw/mitogen/issues/672#issuecomment-636408833
545+
We replace a relative import in the setup module with the actual full file path
546+
This works in vanilla Ansible but not in Mitogen otherwise
547+
"""
548+
if invocation.module_name == 'setup' and \
549+
invocation.module_path not in invocation._overridden_sources:
550+
# in-memory replacement of setup module's relative import
551+
# would check for just python3.5 and run this then but we don't know the
552+
# target python at this time yet
553+
module_source = module_source.replace(
554+
b"from ...module_utils.basic import AnsibleModule",
555+
b"from ansible.module_utils.basic import AnsibleModule"
556+
)
557+
invocation._overridden_sources[invocation.module_path] = module_source
558+
559+
536560
def invoke(invocation):
537561
"""
538562
Find a Planner subclass corresponding to `invocation` and use it to invoke
@@ -555,10 +579,12 @@ def invoke(invocation):
555579

556580
invocation.module_path = mitogen.core.to_text(path)
557581
if invocation.module_path not in _planner_by_path:
582+
module_source = invocation.get_module_source()
583+
_fix_py35(invocation, module_source)
558584
_planner_by_path[invocation.module_path] = _get_planner(
559585
invocation.module_name,
560586
invocation.module_path,
561-
invocation.get_module_source()
587+
module_source
562588
)
563589

564590
planner = _planner_by_path[invocation.module_path](invocation)

mitogen/service.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -746,28 +746,41 @@ def _forward(self, context, path):
746746
'paths': list,
747747
'modules': list,
748748
})
749-
def propagate_paths_and_modules(self, context, paths, modules):
749+
def propagate_paths_and_modules(self, context, paths, modules, overridden_sources=None):
750750
"""
751751
One size fits all method to ensure a target context has been preloaded
752752
with a set of small files and Python modules.
753+
754+
overridden_sources: optional dict containing source code to override path's source code
753755
"""
754756
for path in paths:
755-
self.propagate_to(context, mitogen.core.to_text(path))
757+
overridden_source = None
758+
if overridden_sources is not None and path in overridden_sources:
759+
overridden_source = overridden_sources[path]
760+
self.propagate_to(context, mitogen.core.to_text(path), overridden_source)
756761
#self.router.responder.forward_modules(context, modules) TODO
757762

758763
@expose(policy=AllowParents())
759764
@arg_spec({
760765
'context': mitogen.core.Context,
761766
'path': mitogen.core.FsPathTypes,
762767
})
763-
def propagate_to(self, context, path):
768+
def propagate_to(self, context, path, overridden_source=None):
769+
"""
770+
If the optional parameter 'overridden_source' is passed, use
771+
that instead of the path's code as source code. This works around some bugs
772+
of source modules such as relative imports on unsupported Python versions
773+
"""
764774
if path not in self._cache:
765775
LOG.debug('caching small file %s', path)
766-
fp = open(path, 'rb')
767-
try:
768-
self._cache[path] = mitogen.core.Blob(fp.read())
769-
finally:
770-
fp.close()
776+
if overridden_source is None:
777+
fp = open(path, 'rb')
778+
try:
779+
self._cache[path] = mitogen.core.Blob(fp.read())
780+
finally:
781+
fp.close()
782+
else:
783+
self._cache[path] = mitogen.core.Blob(overridden_source)
771784
self._forward(context, path)
772785

773786
@expose(policy=AllowParents())

0 commit comments

Comments
 (0)