Merge commit '28ea478' into release-v0.3.32

pull/1366/head
Alex Willmer 2 weeks ago
commit c785c0e889

@ -1,33 +0,0 @@
---
name: Mitogen 0.2.x bug report
about: Report a bug in Mitogen 0.2.x (for Ansible 2.5, 2.6, 2.7, 2.8, or 2.9)
title: ''
labels: affects-0.2, bug
assignees: ''
---
Please drag-drop large logs as text file attachments.
Feel free to write an issue in your preferred format, however if in doubt, use
the following checklist as a guide for what to include.
* Which version of Ansible are you running?
* Is your version of Ansible patched in any way?
* Are you running with any custom modules, or `module_utils` loaded?
* Have you tried the latest master version from Git?
* Do you have some idea of what the underlying problem may be?
https://mitogen.networkgenomics.com/ansible_detailed.html#common-problems has
instructions to help figure out the likely cause and how to gather relevant
logs.
* Mention your host and target OS and versions
* Mention your host and target Python versions
* If reporting a performance issue, mention the number of targets and a rough
description of your workload (lots of copies, lots of tiny file edits, etc.)
* If reporting a crash or hang in Ansible, please rerun with -vvv and include
200 lines of output around the point of the error, along with a full copy of
any traceback or error text in the log. Beware "-vvv" may include secret
data! Edit as necessary before posting.
* If reporting any kind of problem with Ansible, please include the Ansible
version along with output of "ansible-config dump --only-changed".

@ -1,33 +0,0 @@
---
name: Mitogen 0.3.x bug report
about: Report a bug in Mitogen 0.3.x (for Ansible 2.10.x)
title: ''
labels: affects-0.3, bug
assignees: ''
---
Please drag-drop large logs as text file attachments.
Feel free to write an issue in your preferred format, however if in doubt, use
the following checklist as a guide for what to include.
* Which version of Ansible are you running?
* Is your version of Ansible patched in any way?
* Are you running with any custom modules, or `module_utils` loaded?
* Have you tried the latest master version from Git?
* Do you have some idea of what the underlying problem may be?
https://mitogen.networkgenomics.com/ansible_detailed.html#common-problems has
instructions to help figure out the likely cause and how to gather relevant
logs.
* Mention your host and target OS and versions
* Mention your host and target Python versions
* If reporting a performance issue, mention the number of targets and a rough
description of your workload (lots of copies, lots of tiny file edits, etc.)
* If reporting a crash or hang in Ansible, please rerun with -vvv and include
200 lines of output around the point of the error, along with a full copy of
any traceback or error text in the log. Beware "-vvv" may include secret
data! Edit as necessary before posting.
* If reporting any kind of problem with Ansible, please include the Ansible
version along with output of "ansible-config dump --only-changed".

@ -0,0 +1,62 @@
name: Bug report
description: Report a bug in Mitogen 0.3.x (for Ansible 2.10 and above)
labels:
- affects-0.3
type: bug
body:
- type: textarea
attributes:
label: Description
description: >
When does the problem occur?
What happens after?
How is this different?
Did it previously behave as expected?
placeholder: |
When I do X, Y happens, but I was expecting Z because ...
Before version 1.2.3 it worked as expected.
validations:
required: true
- type: input
attributes:
label: Mitogen version
placeholder: 0.3.31, 0.3.3-9+deb12u1
validations:
required: true
- type: input
attributes:
label: Ansible version (if applicable)
placeholder: 2.18.11
- type: textarea
attributes:
label: OS and environment
description: >
What operating system version(s), Python version(s), etc. are you using?
placeholder: |
Controller (master): Debian 13, Python 3.14
Targets (slaves): Ubuntu 20.04/Python 2.7, RHEL 10, ...
- type: textarea
attributes:
label: Steps to reproduce
description: >
Instructions, code, or playbook(s) recreate the beahviour
value: |
Steps:
1. Set config `foo = 42` in somefile.cfg
2. Run the following Python or Playbook with `cmd --option bar ...`
```
Code or playbook here
```
- type: textarea
attributes:
label: Anything else
description: >
Include any other details you think might be relevant or helpful.
Examples might include logs, unusual settings, environment variables, ...

@ -1,10 +0,0 @@
path_classifiers:
library:
- "mitogen/compat"
- "ansible_mitogen/compat"
queries:
# Mitogen 2.4 compatibility trips this query everywhere, so just disable it
- exclude: py/unreachable-statement
- exclude: py/should-use-with
# mitogen.core.b() trips this query everywhere, so just disable it
- exclude: py/import-and-import-from

@ -7,5 +7,3 @@
<a href="https://mitogen.networkgenomics.com/">Please see the documentation</a>. <a href="https://mitogen.networkgenomics.com/">Please see the documentation</a>.
![](https://i.imgur.com/eBM6LhJ.gif) ![](https://i.imgur.com/eBM6LhJ.gif)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/mitogen-hq/mitogen.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mitogen-hq/mitogen/alerts/)

@ -49,18 +49,6 @@ __all__ = [
ANSIBLE_VERSION_MIN = (2, 10) ANSIBLE_VERSION_MIN = (2, 10)
ANSIBLE_VERSION_MAX = (2, 19)
NEW_VERSION_MSG = (
"Your Ansible version (%s) is too recent. The most recent version\n"
"supported by Mitogen for Ansible is %s.x. Please check the Mitogen\n"
"release notes to see if a new version is available, otherwise\n"
"subscribe to the corresponding GitHub issue to be notified when\n"
"support becomes available.\n"
"\n"
" https://mitogen.rtfd.io/en/latest/changelog.html\n"
" https://github.com/mitogen-hq/mitogen/issues/\n"
)
OLD_VERSION_MSG = ( OLD_VERSION_MSG = (
"Your version of Ansible (%s) is too old. The oldest version supported by " "Your version of Ansible (%s) is too old. The oldest version supported by "
"Mitogen for Ansible is %s." "Mitogen for Ansible is %s."
@ -78,11 +66,6 @@ def assert_supported_release():
OLD_VERSION_MSG % (v, ANSIBLE_VERSION_MIN) OLD_VERSION_MSG % (v, ANSIBLE_VERSION_MIN)
) )
if v[:2] > ANSIBLE_VERSION_MAX:
raise ansible.errors.AnsibleError(
NEW_VERSION_MSG % (v, ANSIBLE_VERSION_MAX)
)
# this is the first file our strategy plugins import, so we need to check this here # this is the first file our strategy plugins import, so we need to check this here
# in prior Ansible versions, connection_loader.get_with_context didn't exist, so if a user # in prior Ansible versions, connection_loader.get_with_context didn't exist, so if a user

@ -18,6 +18,15 @@ To avail of fixes in an unreleased version, please download a ZIP file
`directly from GitHub <https://github.com/mitogen-hq/mitogen/>`_. `directly from GitHub <https://github.com/mitogen-hq/mitogen/>`_.
v0.3.32 (2025-11-21)
--------------------
* :gh:issue:`1243` :mod:`mitogen`: Pass first stage, context name, & preamble
size as seperate **argv** arguments
* :gh:issue:`1218` :mod:`ansible_mitogen`: Remove maximum Ansible version check
* :gh:issue:`1260` CI: Remove integration of retired lgtm.com
v0.3.31 (2025-11-05) v0.3.31 (2025-11-05)
-------------------- --------------------

@ -27,14 +27,13 @@ Python Command Line
################### ###################
The Python command line sent to the host is a :mod:`zlib`-compressed [#f2]_ and The Python command line sent to the host is a :mod:`zlib`-compressed [#f2]_ and
base64-encoded copy of the :py:meth:`mitogen.master.Stream._first_stage` base64-encoded copy of :py:meth:`mitogen.parent.Connection._first_stage`,
function, which has been carefully optimized to reduce its size. Prior to which is carefully written to maximize it compatibility and minimize its size.
compression and encoding, ``CONTEXT_NAME`` is replaced with the desired context A simplified illustration of the bootstrap command is
name in the function's source code.
.. code:: .. code::
python -c 'exec "xxx".decode("base64").decode("zlib")' python -c 'exec(sys.argv[1].decode("base64").decode("zlib"))' <base64> ...
The command-line arranges for the Python interpreter to decode the base64'd The command-line arranges for the Python interpreter to decode the base64'd
component, decompress it and execute it as Python code. Base64 is used since component, decompress it and execute it as Python code. Base64 is used since
@ -71,8 +70,8 @@ of the large base64-encoded first stage parameter, and to replace **argv[0]**
with something descriptive. with something descriptive.
After configuring its ``stdin`` to point to the read end of the pipe, the After configuring its ``stdin`` to point to the read end of the pipe, the
parent half of the fork re-executes Python, with **argv[0]** taken from the fork parent re-executes Python with **argv[0]** composed of the Python
``CONTEXT_NAME`` variable earlier substituted into its source code. As no interpreter path and a remote name supplied by the Mitogen parent. As no
arguments are provided to this new execution of Python, and since ``stdin`` is arguments are provided to this new execution of Python, and since ``stdin`` is
connected to a pipe (whose write end is connected to the first stage), the connected to a pipe (whose write end is connected to the first stage), the
Python interpreter begins reading source code to execute from the pipe Python interpreter begins reading source code to execute from the pipe

@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup.
#: Library version as a tuple. #: Library version as a tuple.
__version__ = (0, 3, 31) __version__ = (0, 3, 32)
#: This is :data:`False` in slave contexts. Previously it was used to prevent #: This is :data:`False` in slave contexts. Previously it was used to prevent

@ -1396,10 +1396,6 @@ class Connection(object):
# with a custom argv. # with a custom argv.
# * Optimized for minimum byte count after minification & compression. # * Optimized for minimum byte count after minification & compression.
# The script preamble_size.py measures this. # The script preamble_size.py measures this.
# * 'CONTEXT_NAME' and 'PREAMBLE_COMPRESSED_LEN' are substituted with
# their respective values.
# * CONTEXT_NAME must be prefixed with the name of the Python binary in
# order to allow virtualenvs to detect their install prefix.
# #
# macOS tweaks for Python 2.7 must be kept in sync with the the Ansible # macOS tweaks for Python 2.7 must be kept in sync with the the Ansible
# module test_echo_module, used by the integration tests. # module test_echo_module, used by the integration tests.
@ -1435,20 +1431,21 @@ class Connection(object):
os.close(r) os.close(r)
os.close(W) os.close(W)
os.close(w) os.close(w)
if os.uname()[0]=='Darwin'and os.uname()[2][:2]<'19'and sys.executable=='/usr/bin/python':sys.executable='/usr/bin/python2.7' if os.uname()[0]+os.uname()[2][:2]+sys.executable=='Darwin19/usr/bin/python':sys.executable+='2.7'
if os.uname()[0]=='Darwin'and os.uname()[2][:2]in'2021'and sys.version[:3]=='2.7':os.environ['PYTHON_LAUNCHED_FROM_WRAPPER']='1' if os.uname()[0]+os.uname()[2][:2]+sys.version[:3]=='Darwin202.7':os.environ['PYTHON_LAUNCHED_FROM_WRAPPER']='1'
if os.uname()[0]+os.uname()[2][:2]+sys.version[:3]=='Darwin212.7':os.environ['PYTHON_LAUNCHED_FROM_WRAPPER']='1'
os.environ['ARGV0']=sys.executable os.environ['ARGV0']=sys.executable
os.execl(sys.executable,sys.executable+'(mitogen:CONTEXT_NAME)') os.execl(sys.executable,sys.executable+'(mitogen:%s)'%sys.argv[2])
os.write(1,'MITO000\n'.encode()) os.write(1,'MITO000\n'.encode())
C=''.encode() C=''.encode()
while PREAMBLE_COMPRESSED_LEN-len(C)and select.select([0],[],[]):C+=os.read(0,PREAMBLE_COMPRESSED_LEN-len(C)) while int(sys.argv[3])-len(C)and select.select([0],[],[]):C+=os.read(0,int(sys.argv[3])-len(C))
C=zlib.decompress(C) C=zlib.decompress(C)
fp=os.fdopen(W,'wb',0) f=os.fdopen(W,'wb',0)
fp.write(C) f.write(C)
fp.close() f.close()
fp=os.fdopen(w,'wb',0) f=os.fdopen(w,'wb',0)
fp.write(C) f.write(C)
fp.close() f.close()
os.write(1,'MITO001\n'.encode()) os.write(1,'MITO001\n'.encode())
os.close(2) os.close(2)
@ -1469,11 +1466,10 @@ class Connection(object):
source = inspect.getsource(self._first_stage) source = inspect.getsource(self._first_stage)
source = textwrap.dedent('\n'.join(source.strip().split('\n')[2:])) source = textwrap.dedent('\n'.join(source.strip().split('\n')[2:]))
source = source.replace(' ', ' ') source = source.replace(' ', ' ')
source = source.replace('CONTEXT_NAME', self.options.remote_name) compressor = zlib.compressobj(
preamble_compressed = self.get_preamble() zlib.Z_BEST_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS,
source = source.replace('PREAMBLE_COMPRESSED_LEN', )
str(len(preamble_compressed))) compressed = compressor.compress(source.encode()) + compressor.flush()
compressed = zlib.compress(source.encode(), 9)
encoded = binascii.b2a_base64(compressed).replace(b('\n'), b('')) encoded = binascii.b2a_base64(compressed).replace(b('\n'), b(''))
# Just enough to decode, decompress, and exec the first stage. # Just enough to decode, decompress, and exec the first stage.
@ -1484,7 +1480,10 @@ class Connection(object):
'-c', '-c',
'import sys;sys.path=[p for p in sys.path if p];' 'import sys;sys.path=[p for p in sys.path if p];'
'import binascii,os,select,zlib;' 'import binascii,os,select,zlib;'
'exec(zlib.decompress(binascii.a2b_base64("%s")))' % (encoded.decode(),), 'exec(zlib.decompress(binascii.a2b_base64(sys.argv[1]),-15))',
encoded.decode(),
self.options.remote_name,
str(len(self.get_preamble())),
] ]
def get_econtext_config(self): def get_econtext_config(self):

@ -26,7 +26,7 @@ class CommandLineTest(testlib.RouterMixin, testlib.TestCase):
# preamble from stdin, then execute it. # preamble from stdin, then execute it.
# This test attaches /dev/zero to stdin to create a specific failure # This test attaches /dev/zero to stdin to create a specific failure
# 1. Fork child reads PREAMBLE_COMPRESSED_LEN bytes of junk (all `\0`) # 1. Fork child reads <compressed preamble size> bytes of NUL (`b'\0'`)
# 2. Fork child crashes (trying to decompress the junk data) # 2. Fork child crashes (trying to decompress the junk data)
# 3. Fork child's file descriptors (write pipes) are closed by the OS # 3. Fork child's file descriptors (write pipes) are closed by the OS
# 4. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)` # 4. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)`

Loading…
Cancel
Save