Skip to content

Commit 699a8eb

Browse files
committed
ansible_mitogen: Use INTERPRETER_PYTHON_FALLBACK as python candidates
This shouldn't change the interpreter ultimately chosen by Ansible. It should only improve the hit rate of performing interpreter discovery, particular in cases where only pythonX.Y is present on the target. Interpreter discovery may take longer or shorter, depending on the Ansible version and the interpreters present on the target.
1 parent abb77e7 commit 699a8eb

File tree

3 files changed

+34
-25
lines changed

3 files changed

+34
-25
lines changed

ansible_mitogen/mixins.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -470,18 +470,7 @@ def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
470470
# chicken-and-egg issue, mitogen needs a python to run low_level_execute_command
471471
# which is required by Ansible's discover_interpreter function
472472
if self._mitogen_discovering_interpreter:
473-
possible_pythons = [
474-
'/usr/bin/python',
475-
'python3',
476-
'python3.7',
477-
'python3.6',
478-
'python3.5',
479-
'python2.7',
480-
'python2.6',
481-
'/usr/libexec/platform-python',
482-
'/usr/bin/python3',
483-
'python'
484-
]
473+
possible_pythons = self._mitogen_interpreter_candidates
485474
else:
486475
# not used, just adding a filler value
487476
possible_pythons = ['python']
@@ -492,12 +481,15 @@ def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
492481
rc, stdout, stderr = self._connection.exec_command(
493482
cmd, in_data, sudoable, mitogen_chdir=chdir,
494483
)
495-
# TODO: what exception is thrown?
496-
except:
484+
except BaseException as exc:
497485
# we've reached the last python attempted and failed
498486
if possible_python == possible_pythons[-1]:
499487
raise
500488
else:
489+
LOG.debug(
490+
'%r._low_level_execute_command: candidate=%r ignored: %s, %r',
491+
self, possible_python, type(exc), exc,
492+
)
501493
continue
502494

503495
stdout_text = to_text(stdout, errors=encoding_errors)

ansible_mitogen/transport_config.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,21 @@
7373
from ansible.module_utils.six import with_metaclass
7474
from ansible.module_utils.parsing.convert_bool import boolean
7575

76+
import ansible_mitogen.utils
7677
import mitogen.core
7778

7879

7980
LOG = logging.getLogger(__name__)
8081

82+
if ansible_mitogen.utils.ansible_version[:2] >= (2, 19):
83+
_FALLBACK_INTERPRETER = ansible.executor.interpreter_discovery._FALLBACK_INTERPRETER
84+
elif ansible_mitogen.utils.ansible_version[:2] >= (2, 17):
85+
_FALLBACK_INTERPRETER = u'/usr/bin/python3'
86+
else:
87+
_FALLBACK_INTERPRETER = u'/usr/bin/python'
8188

82-
def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_python):
89+
90+
def run_interpreter_discovery_if_necessary(s, candidates, task_vars, action, rediscover_python):
8391
"""
8492
Triggers ansible python interpreter discovery if requested.
8593
Caches this value the same way Ansible does it.
@@ -107,8 +115,11 @@ def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_pyth
107115
# blow away the discovered_interpreter_config cache and rediscover
108116
del task_vars['ansible_facts'][discovered_interpreter_config]
109117

110-
if discovered_interpreter_config not in task_vars['ansible_facts']:
118+
try:
119+
s = task_vars[u'ansible_facts'][discovered_interpreter_config]
120+
except KeyError:
111121
action._mitogen_discovering_interpreter = True
122+
action._mitogen_interpreter_candidates = candidates
112123
# fake pipelining so discover_interpreter can be happy
113124
action._connection.has_pipelining = True
114125
s = ansible.executor.interpreter_discovery.discover_interpreter(
@@ -121,18 +132,17 @@ def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_pyth
121132
# cache discovered interpreter
122133
task_vars['ansible_facts'][discovered_interpreter_config] = s
123134
action._connection.has_pipelining = False
124-
else:
125-
s = task_vars['ansible_facts'][discovered_interpreter_config]
126135

127136
# propagate discovered interpreter as fact
128137
action._discovered_interpreter_key = discovered_interpreter_config
129138
action._discovered_interpreter = s
130139

131140
action._mitogen_discovering_interpreter = False
141+
action._mitogen_interpreter_candidates = None
132142
return s
133143

134144

135-
def parse_python_path(s, task_vars, action, rediscover_python):
145+
def parse_python_path(s, candidates, task_vars, action, rediscover_python):
136146
"""
137147
Given the string set for ansible_python_interpeter, parse it using shell
138148
syntax and return an appropriate argument vector. If the value detected is
@@ -143,10 +153,9 @@ def parse_python_path(s, task_vars, action, rediscover_python):
143153
# if python_path doesn't exist, default to `auto` and attempt to discover it
144154
s = 'auto'
145155

146-
s = run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_python)
147-
# if unable to determine python_path, fallback to '/usr/bin/python'
156+
s = run_interpreter_discovery_if_necessary(s, candidates, task_vars, action, rediscover_python)
148157
if not s:
149-
s = '/usr/bin/python'
158+
s = _FALLBACK_INTERPRETER
150159

151160
return ansible.utils.shlex.shlex_split(s)
152161

@@ -510,13 +519,17 @@ def python_path(self, rediscover_python=False):
510519
interpreter_python = C.config.get_config_value(
511520
'INTERPRETER_PYTHON', variables=variables,
512521
)
522+
interpreter_python_fallback = C.config.get_config_value(
523+
'INTERPRETER_PYTHON_FALLBACK', variables=variables,
524+
)
513525

514526
if '{{' in interpreter_python or '{%' in interpreter_python:
515527
templar = self._connection.templar
516528
interpreter_python = templar.template(interpreter_python)
517529

518530
return parse_python_path(
519531
interpreter_python,
532+
candidates=interpreter_python_fallback,
520533
task_vars=self._task_vars,
521534
action=self._action,
522535
rediscover_python=rediscover_python)
@@ -732,11 +745,12 @@ def port(self):
732745

733746
def python_path(self, rediscover_python=False):
734747
s = self._host_vars.get('ansible_python_interpreter')
735-
# #511, #536: executor/module_common.py::_get_shebang() hard-wires
736-
# "/usr/bin/python" as the default interpreter path if no other
737-
# interpreter is specified.
748+
interpreter_python_fallback = self._host_vars.get(
749+
'ansible_interpreter_python_fallback', [],
750+
)
738751
return parse_python_path(
739752
s,
753+
candidates=interpreter_python_fallback,
740754
task_vars=self._task_vars,
741755
action=self._action,
742756
rediscover_python=rediscover_python)

docs/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ To avail of fixes in an unreleased version, please download a ZIP file
2121
In progress (unreleased)
2222
------------------------
2323

24+
* :gh:issue:`1132` :mod:`ansible_mitogen` During intrepreter discovery use
25+
Ansible ``INTERPRETER_PYTHON_FALLBACK`` config as list of candidates
26+
2427

2528
v0.3.34 (2025-11-27)
2629
--------------------

0 commit comments

Comments
 (0)