Skip to content

Commit a0df1a9

Browse files
committed
WIP
1 parent 98ae5e2 commit a0df1a9

File tree

6 files changed

+56
-56
lines changed

6 files changed

+56
-56
lines changed

ansible_mitogen/mixins.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -470,30 +470,27 @@ 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+
if self._connection.transport in {'ssh'}:
474+
possible_pythons = [
475+
'$(for p in python3 python2 python; do command -v "$p" 2>/dev/null && break; done;)',
476+
]
477+
else:
478+
possible_pythons = ['python3' 'python2', 'python']
485479
else:
486480
# not used, just adding a filler value
487481
possible_pythons = ['python']
488482

489483
for possible_python in possible_pythons:
490484
try:
485+
LOG.debug('_low_level_execute_command(): trying possible_python=%r', possible_python)
491486
self._mitogen_interpreter_candidate = possible_python
492487
rc, stdout, stderr = self._connection.exec_command(
493488
cmd, in_data, sudoable, mitogen_chdir=chdir,
494489
)
490+
LOG.debug('_low_level_execute_command(): got rc=%d, stdout=%r, stderr=%r', rc, stdout, stderr)
495491
# TODO: what exception is thrown?
496-
except:
492+
except BaseException as exc:
493+
LOG.debug('%r._low_level_execute_command for possible_python=%r: %s, %r', self, possible_python, type(exc), exc)
497494
# we've reached the last python attempted and failed
498495
if possible_python == possible_pythons[-1]:
499496
raise

ansible_mitogen/transport_config.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,19 @@
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'
88+
8189

8290
def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_python):
8391
"""
@@ -107,7 +115,9 @@ 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['ansible_facts'][discovered_interpreter_config]
120+
except KeyError:
111121
action._mitogen_discovering_interpreter = True
112122
# fake pipelining so discover_interpreter can be happy
113123
action._connection.has_pipelining = True
@@ -121,8 +131,6 @@ def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_pyth
121131
# cache discovered interpreter
122132
task_vars['ansible_facts'][discovered_interpreter_config] = s
123133
action._connection.has_pipelining = False
124-
else:
125-
s = task_vars['ansible_facts'][discovered_interpreter_config]
126134

127135
# propagate discovered interpreter as fact
128136
action._discovered_interpreter_key = discovered_interpreter_config
@@ -144,9 +152,9 @@ def parse_python_path(s, task_vars, action, rediscover_python):
144152
s = 'auto'
145153

146154
s = run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_python)
147-
# if unable to determine python_path, fallback to '/usr/bin/python'
148155
if not s:
149-
s = '/usr/bin/python'
156+
s = _FALLBACK_INTERPRETER
157+
# raise ValueError("Interpreter discovery failed, got: %r", s)
150158

151159
return ansible.utils.shlex.shlex_split(s)
152160

@@ -715,9 +723,6 @@ def port(self):
715723

716724
def python_path(self, rediscover_python=False):
717725
s = self._host_vars.get('ansible_python_interpreter')
718-
# #511, #536: executor/module_common.py::_get_shebang() hard-wires
719-
# "/usr/bin/python" as the default interpreter path if no other
720-
# interpreter is specified.
721726
return parse_python_path(
722727
s,
723728
task_vars=self._task_vars,

docs/index.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ to your network topology**.
8080
:class: mitogen-right-150
8181

8282
.. code::
83+
import mitogen.master
84+
85+
broker = mitogen.master.Broker()
86+
router = mitogen.master.Router(broker)
8387
8488
bastion_host = router.ssh(
8589
hostname='jump-box.mycorp.com'
@@ -101,7 +105,9 @@ to your network topology**.
101105
container='billing0',
102106
)
103107
104-
internal_box.call(subprocess.check_call, ['./run-nightly-billing.py'])
108+
internal_box.call(
109+
subprocess.check_call, ['./nightly-billing.py'],
110+
)
105111
106112
The multiplexer also ensures the remote process is terminated if your Python
107113
program crashes, communication is lost, or the application code running in the

mitogen/parent.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ def get_python_argv(self):
14621462
return self.options.python_path
14631463
return [self.options.python_path]
14641464

1465-
def get_boot_command(self):
1465+
def _first_stage_base64(self):
14661466
source = inspect.getsource(self._first_stage)
14671467
source = textwrap.dedent('\n'.join(source.strip().split('\n')[2:]))
14681468
source = source.replace(' ', ' ')
@@ -1472,17 +1472,23 @@ def get_boot_command(self):
14721472
str(len(preamble_compressed)))
14731473
compressed = zlib.compress(source.encode(), 9)
14741474
encoded = binascii.b2a_base64(compressed).replace(b('\n'), b(''))
1475+
return encoded.decode('ascii')
14751476

1477+
def _bootstrap_argv(self):
14761478
# Just enough to decode, decompress, and exec the first stage.
14771479
# Priorities: wider compatibility, faster startup, shorter length.
14781480
# `import os` here, instead of stage 1, to save a few bytes.
14791481
# `sys.path=...` for https://github.com/python/cpython/issues/115911.
1480-
return self.get_python_argv() + [
1482+
return [
14811483
'-c',
14821484
'import sys;sys.path=[p for p in sys.path if p];import binascii,os,zlib;'
1483-
'exec(zlib.decompress(binascii.a2b_base64("%s")))' % (encoded.decode(),),
1485+
'exec(zlib.decompress(binascii.a2b_base64(sys.argv[1])))',
1486+
self._first_stage_base64(),
14841487
]
14851488

1489+
def get_boot_command(self):
1490+
return self.get_python_argv() + self._bootstrap_argv()
1491+
14861492
def get_econtext_config(self):
14871493
assert self.options.max_message_size is not None
14881494
parent_ids = mitogen.parent_ids[:]
@@ -1518,7 +1524,7 @@ def _get_name(self):
15181524

15191525
def start_child(self):
15201526
args = self.get_boot_command()
1521-
LOG.debug('command line for %r: %s', self, Argv(args))
1527+
LOG.debug('command line for %r: %s', self, args)
15221528
try:
15231529
return self.create_child(args=args, **self.create_child_args)
15241530
except OSError:

mitogen/ssh.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,8 @@ def get_boot_command(self):
296296
if self.options.ssh_args:
297297
bits += self.options.ssh_args
298298
bits.append(self.options.hostname)
299-
base = super(Connection, self).get_boot_command()
300299

301-
base_parts = []
302-
for s in base:
303-
val = s if s in self.SHLEX_IGNORE else shlex_quote(s).strip()
304-
base_parts.append(val)
305-
return bits + base_parts
300+
# https://datatracker.ietf.org/doc/html/rfc4254#section-6.5
301+
python_argv = self.get_python_argv()
302+
bootstrap_argv = self._bootstrap_argv()
303+
return bits + python_argv + [shlex_quote(s) for s in bootstrap_argv]

mitogen/sudo.py

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
import logging
3333
import optparse
3434
import re
35+
import shlex
36+
37+
try:
38+
from shlex import quote as shlex_quote
39+
except ImportError:
40+
from pipes import quote as shlex_quote
41+
3542

3643
import mitogen.core
3744
import mitogen.parent
@@ -256,8 +263,6 @@ def get_boot_command(self):
256263
# Note: sudo did not introduce long-format option processing until July
257264
# 2013, so even though we parse long-format options, supply short-form
258265
# to the sudo command.
259-
boot_cmd = super(Connection, self).get_boot_command()
260-
261266
bits = [self.options.sudo_path, '-u', self.options.username]
262267
if self.options.preserve_env:
263268
bits += ['-E']
@@ -270,25 +275,8 @@ def get_boot_command(self):
270275
if self.options.selinux_type:
271276
bits += ['-t', self.options.selinux_type]
272277

273-
# special handling for bash builtins
274-
# TODO: more efficient way of doing this, at least
275-
# it's only 1 iteration of boot_cmd to go through
276-
source_found = False
277-
for cmd in boot_cmd[:]:
278-
# rip `source` from boot_cmd if it exists; sudo.py can't run this
279-
# even with -i or -s options
280-
# since we've already got our ssh command working we shouldn't
281-
# need to source anymore
282-
# couldn't figure out how to get this to work using sudo flags
283-
if 'source' == cmd:
284-
boot_cmd.remove(cmd)
285-
source_found = True
286-
continue
287-
if source_found:
288-
# remove words until we hit the python interpreter call
289-
if not cmd.endswith('python'):
290-
boot_cmd.remove(cmd)
291-
else:
292-
break
293-
294-
return bits + ['--'] + boot_cmd
278+
279+
python_argv = self.get_python_argv()
280+
bootstrap_argv = self._bootstrap_argv()
281+
boot_argv = python_argv + [shlex_quote(s) for s in bootstrap_argv]
282+
return bits + ['--', 'sh', '-c', ' '.join(boot_argv)]

0 commit comments

Comments
 (0)