Compare commits

..

92 Commits

Author SHA1 Message Date
Alex Willmer 81e11d5456
Merge pull request #1347 from moreati/release-v0.3.30
Release v0.3.30
1 month ago
Alex Willmer 263884070d Merge commit '1e90ff2' into release-v0.3.30 1 month ago
Alex Willmer c01f430957
Merge pull request #1340 from moreati/release-v0.3.29
Release v0.3.29
3 months ago
Alex Willmer c0dd5c6966 Merge commit 'e670bf0' into stable 3 months ago
Alex Willmer ce0c596700
Merge pull request #1338 from moreati/release-v0.3.28
Release v0.3.28
3 months ago
Alex Willmer 2791abe17a Merge commit '9f9b37d' into release-v0.3.28 3 months ago
Alex Willmer ced63f96d9
Merge pull request #1332 from moreati/release-v0.3.27
Release v0.3.27
4 months ago
Alex Willmer cbf47967b1 Merge commit '154331e455a3153252e44fe41a9e0b3d08ccf477' into release-v0.3.27 4 months ago
Alex Willmer f77db1da59
Merge pull request #1321 from moreati/release-v0.3.26
Release v0.3.26
4 months ago
Alex Willmer fd1d45568a Merge commit '5908936' into release-v0.3.26 4 months ago
Alex Willmer 021d712edc
Merge pull request #1316 from moreati/release-v0.3.25
Release v0.3.25
4 months ago
Alex Willmer 536ab7d78e Merge commit 'dfafa14' into release-v0.3.25 4 months ago
Alex Willmer 4f213ab365
Merge pull request #1270 from moreati/stable
Release 0.3.24
6 months ago
Alex Willmer 1b137f1531 Merge commit '229fd67' into stable 6 months ago
Alex Willmer 0eb7ee2250
Merge pull request #1262 from moreati/release-v0.3.24
Release v0.3.24
7 months ago
Alex Willmer 9e02175134 Merge commit '8e25944' into release-v0.3.24 7 months ago
Alex Willmer 29d78ae4aa
Merge pull request #1241 from moreati/release-v0.3.23
Release v0.3.22
10 months ago
Alex Willmer f423529211 Merge commit 'ae703b9' into release-v0.3.23 10 months ago
Alex Willmer b8c876dac5
Merge pull request #1224 from moreati/release-v0.3.22
Release v0.3.21
11 months ago
Alex Willmer 0ebbb0650d Merge commit '8b7354c' into release-v0.3.22 11 months ago
Alex Willmer 161a231e48
Merge pull request #1208 from moreati/release-v0.3.20
Release v0.3.20
11 months ago
Alex Willmer 517768ac3f Merge commit 'f1f8ad1' into release-v0.3.20 11 months ago
Alex Willmer 5075cf9c24
Merge pull request #1199 from moreati/release-v0.3.19
Release v0.3.19
1 year ago
Alex Willmer d8494129f5 Merge commit '24ba734ff9d1a3669a844c41623d1583970d9787' into release-v0.3.19 1 year ago
Alex Willmer 4b0954a441
Merge pull request #1195 from moreati/release-v0.3.18
Release v0.3.18
1 year ago
Alex Willmer 02898d70a4 Merge commit 'd85d9a25ee02bddecf068b888c2d814cc918864c' into release-v0.3.18 1 year ago
Alex Willmer d8408b1f25
Merge pull request #1191 from moreati/release-v0.3.17
Release v0.3.17
1 year ago
Alex Willmer 35cc81b074 Merge commit '6cf6f69751e4533eb4f77d2e277c5989571357a5' into release-v0.3.17 1 year ago
Alex Willmer c883f177f3
Merge pull request #1180 from moreati/release-v0.3.16
Release v0.3.16
1 year ago
Alex Willmer a41a9544eb Merge commit 'd28dd09e23c17d82c3eedd5de64c94bebcf290f5' into release-v0.3.16 1 year ago
Alex Willmer 33b082f432
Merge pull request #1171 from moreati/release-v0.3.15
Release v0.3.15
1 year ago
Alex Willmer f4d7385a9c Merge commit '7634e2c' into release-v0.3.15 1 year ago
Alex Willmer 4bc0d9a050
Merge pull request #1164 from moreati/release-v0.3.14
Release v0.3.14
1 year ago
Alex Willmer 9e5d6bfb1b Merge commit 'c4ca015' into release-v0.3.14 1 year ago
Alex Willmer 94e02e1157
Merge pull request #1152 from moreati/release-0.3.13
Release 0.3.13
1 year ago
Alex Willmer 37684545e7 Merge commit '8dec03894170353a7588b1414cf88772d330d1f0' into release-0.3.13 1 year ago
Alex Willmer 63e193bdbe
Merge pull request #1141 from moreati/release-v0.3.12
Release v0.3.12
1 year ago
Alex Willmer 644d42f831 Merge commit '298d28a650a2f154ce3db4bc98495eab964e0e7f' into release-v0.3.12 1 year ago
Alex Willmer 0b895c8673
Merge pull request #1131 from moreati/release-v0.3.11
Release v0.3.11
1 year ago
Alex Willmer 61c82c8dee Merge commit 'c63dc0e080b0f3b955686b10facd0918cc5a71b5' into release-v0.3.11 1 year ago
Alex Willmer 80efb4668d
Merge pull request #1123 from moreati/release-0.3.10
Release 0.3.10
1 year ago
Alex Willmer 6f903b28de Merge commit 'cea2e7b98dc9e255b87f64471ed808a8e004afc1' into release-0.3.10 1 year ago
Alex Willmer db1b7af6cc
Merge pull request #1102 from moreati/release-v0.3.9
Release v0.3.9
1 year ago
Alex Willmer bfafcbbc77 Merge commit '6fbad3ae7dd03d6f41d3b0a4ceb7d0d4ed3832b8' into release-v0.3.9 1 year ago
Alex Willmer 5e903ab1e1
Merge pull request #1093 from moreati/release-v0.3.8
Release v0.3.8
1 year ago
Alex Willmer d0d39cccf2 Merge commit 'e334b50d9d5bc5174d1e07c83c6617db6406193e' into release-v0.3.8 1 year ago
Alex Willmer 3f7a0f74a5
Merge pull request #1057 from moreati/release-v0.3.7
Release v0.3.7
2 years ago
Alex Willmer f6ed546c38 Merge commit 'a3644963c40f117b2bef819cc8617bbd395c7f95' into release-v0.3.7 2 years ago
Alex Willmer b488baed25 Prepare 0.3.6 2 years ago
Alex Willmer d70ec4e540 ansible_mitogen: Handle AnsibleUnsafeText et al in Ansible >= 7
Follwing fixes in Ansible 7-9 for CVE-2023-5764 cating `AnsibleUnsafeBytes` &
`AnsibleUnsafeText` to `bytes()` or `str()` requires special handling. The
handling is Ansible specific, so it shouldn't go in the mitogen package but
rather the ansible_mitogen package.

`ansible_mitogen.utils.unsafe.cast()` is most like `mitogen.utils.cast()`.
During development it began as `ansible_mitogen.utils.unsafe.unwrap_var()`,
closer to an inverse of `ansible.utils.unsafe_procy.wrap_var()`. Future
enhancements may move in this direction.

refs #977, refs #1046

See also
- https://github.com/advisories/GHSA-7j69-qfc3-2fq9
- https://github.com/ansible/ansible/pull/82293
- https://github.com/mitogen-hq/mitogen/wiki/AnsibleUnsafe-notes
2 years ago
Alex Willmer 8059be7160 ansible_mitogen: Make ansible_mitogens.utils a package
Prep work for ansible_mitogen.utils.unsafe
2 years ago
Alex Willmer 1c0253f201 mitogen: Raise TypeError on `mitogen.utils.cast(custom_str)` failures
If casting a string fails then raise a TypeError. This is potentially an API
breaking change; chosen as the lesser evil vs. allowing silent errors.

`cast()` relies on `bytes(obj)` & `str(obj)` returning the respective
supertype. That's no longer the case for `AnsibleUnsafeBytes` &
`AnsibleUnsafeText`; since fixes/mitigations for  CVE-2023-5764.

fixes #1046, refs #977

See also
- https://github.com/advisories/GHSA-7j69-qfc3-2fq9
- https://github.com/ansible/ansible/pull/82293
2 years ago
Orion Poplawski 11e5529e44 ansible_mitogen: Add Ansible 7 support
Co-authored-by: Orion Poplawski <orion@nwra.com>
2 years ago
Alex Willmer 1fbf93203c Start v0.3.6 development 2 years ago
Alex Willmer 541f7c3247
Merge pull request #1044 from moreati/stable-0.3.5
Release v0.3.5
2 years ago
Alex Willmer 1572da1563 docs: Correct PEP 451 hyperlink
(cherry picked from commit 50efa53f8f)
2 years ago
Alex Willmer d83cfd6bed Merge v0.3.5 preperation 2 years ago
Alex Willmer d26ded2ecb
Merge pull request #1003 from moreati/release-0.3.4
Release 0.3.4
2 years ago
Alex Willmer b4d910ae1d Merge commit 'f18f516' into release-0.3.4 2 years ago
Alex Willmer 660d3e0885
Merge pull request #932 from moreati/release-0.3.3
Release 0.3.3
4 years ago
Alex Willmer 8ab84237af Merge commit 'c0d3deeac571eb36dfccbe5ca2f1579f2aceca2a' into release-0.3.3 4 years ago
Alex Willmer bd3cfb4230
Merge pull request #892 from moreati/prepare-0.3.2
Fix Trove classifier, bump version
4 years ago
Alex Willmer 1a84184838 Fix Trove classifier, bump version
fixes #891
4 years ago
Alex Willmer 2bdffd05d0
Merge pull request #886 from moreati/prepare-0.3.1
Prepare 0.3.1
4 years ago
Alex Willmer b19223c168 Release 0.3.1 4 years ago
Alex Willmer 61ccf055ad Merge branch 'master' into prepare-0.3.1 4 years ago
Alex Willmer 74e7bc2bf7
Merge pull request #862 from moreati/release-0.3.0
Release 0.3.0
4 years ago
Alex Willmer 55f973e74e Release v0.3.0 4 years ago
Alex Willmer 58ce9d83a4 Merge branch 'master' into release-0.3.0 4 years ago
David Wilson d3f6ad74c4 Merge remote-tracking branch 'origin/stable-029' into stable 6 years ago
David Wilson 706a94bc97 Merge remote-tracking branch 'origin/v028' into stable
* origin/v028: (383 commits)
  Bump version for release.
  docs: update Changelog for 0.2.8.
  issue #627: add test and tweak Reaper behaviour.
  docs: lots more changelog concision
  docs: changelog concision
  docs: more changelog tweaks
  docs: reorder chapters
  docs: versionless <title>
  docs: update supported Ansible version, mention unsupported features
  docs: changelog fixes/tweaks
  issue #590: update Changelog.
  issue #621: send ADD_ROUTE earlier and add test for early logging.
  issue #590: whoops, import missing test modules
  issue #590: rework ParentEnumerationMethod to recursively handle bad modules
  issue #627: reduce the default pool size in a child to 2.
  tests: add a few extra service tests.
  docs: some more hyperlink joy
  docs: more hyperlinks
  docs: add domainrefs plugin to make link aliases everywhere \o/
  docs: link IS_DEAD in changelog
  docs: tweaks to better explain changelog race
  issue #533: update routing to account for DEL_ROUTE propagation race
  tests: use defer_sync() Rather than defer() + ancient sync_with_broker()
  tests: one case from doas_test was invoking su
  tests: hide memory-mapped files from lsof output
  issue #615: remove meaningless test
  issue #625: ignore SIGINT within MuxProcess
  issue #625: use exec() instead of subprocess in mitogen_ansible_playbook
  issue #615: regression test
  issue #615: update Changelog.
  issue #615: ensure 4GB max_message_size is configured for task workers.
  issue #615: update Changelog.
  issue #615: route a dead message to recipients when no reply is expected
  issue #615: fetch_file() might be called with AnsibleUnicode.
  issue #615: redirect 'fetch' action to 'mitogen_fetch'.
  issue #615: extricate slurp brainwrong from mitogen_fetch
  issue #615: ansible: import Ansible fetch.py action plug-in
  issue #533: include object identity of Stream in repr()
  docs: lots more changelog
  issue #595: add buildah to docs and changelog.
  docs: a few more internals.rst additions
  ci: update to Ansible 2.8.3
  tests: another random string changed in 2.8.3
  tests: fix sudo_flags_failure for Ansible 2.8.3
  ci: fix procps command line format warning
  Whoops, merge together lgtm.yml and .lgtm.yml
  issue #440: log Python version during bootstrap.
  docs: update changelog
  issue #558: disable test on OSX to cope with boundless mediocrity
  issue #558, #582: preserve remote tmpdir if caller did not supply one
  issue #613: must await 'exit' and 'disconnect' in wait=False test
  Import LGTM config to disable some stuff
  Fix up another handful of LGTM errors.
  tests: work around AnsibleModule.run_command() race.
  docs: mention another __main__ safeguard
  docs: tweaks
  formatting error
  docs: make Sphinx install soft fail on Python 2.
  issue #598: allow disabling preempt in terraform
  issue #598: update Changelog.
  issue #605: update Changelog.
  issue #605: ansible: share a sem_t instead of a pthread_mutex_t
  issue #613: add tests for all the weird shutdown methods
  Add mitogen.core.now() and use it everywhere; closes #614.
  docs: move decorator docs into core.py and use autodecorator
  preamble_size: make it work on Python 3.
  docs: upgrade Sphinx to 2.1.2, require Python 3 to build docs.
  docs: fix Sphinx warnings, add LogHandler, more docstrings
  docs: tidy up some Changelog text
  issue #615: fix up FileService tests for new logic
  issue #615: another Py3x fix.
  issue #615: Py3x fix.
  issue #615: update Changelog.
  issue #615: use FileService for target->controll file transfers
  issue #482: another Py3 fix
  ci: try removing exclude: to make Azure jobs work again
  compat: fix Py2.4 SyntaxError
  issue #482: remove 'ssh' from checked processes
  ci: Py3 fix
  issue #279: add one more test for max_message_size
  issue #482: ci: add stray process checks to all jobs
  tests: fix format string error
  core: MitogenProtocol.is_privileged was not set in children
  issue #482: tests: fail DockerMixin tests if stray processes exist
  docs: update Changelog.
  issue #586: update Changelog.
  docs: update Changelog.
  [security] core: undirectional routing wasn't respected in some cases
  docs: tidy up Select.all()
  issue #612: update Changelog.
  master: fix TypeError
  pkgutil: fix Python3 compatibility
  parent: use protocol for getting remote_id
  docs: merge signals.rst into internals.rst
  os_fork: do not attempt to cork the active thread.
  parent: fix get_log_level() for split out loggers.
  issue #547: fix service_test failures.
  issue #547: update Changelog.
  issue #547: core/service: race/deadlock-free service pool init
  docs: update Changelog.
  ...
6 years ago
David Wilson 251642943d Merge remote-tracking branch 'origin/v027' into stable
* origin/v027:
  docs: update Changelog for release.
  Bump version for release.
  issue #587: update Changelog
  issue #587: ansible: descriptive version check during startup.
  ansible: descriptive version check during startup.
  issue #581: expose mitogen_mask_remote_name variable.
  issue #576: fix Kwargs minor version check.
  issue #574: fix ISSUE_TEMPLATE link
  issue #575: fix exception text rendering
  docs: remove infringing mark
  docs: fix config var scope
  docs: faster stats-preserving redirect
  docs: update ansible page
  issue #570: add firewalld to always-fork list for now.
  docs: removed excess word
  docs: fixed message routing example description
  docs: removed repeated word
  docs: update Changelog; closes #557.
  issue #557: support correct cpu_set_t size
7 years ago
David Wilson 407307adf6 Merge remote-tracking branch 'origin/026' into stable
* origin/026:
  docs: update Changelog for release.
  Bump version for release.
  issue #555: ansible: workaround ancient reload(sys) hack.
  issue #554: mitogen_action_script fix
  issue #554: fix Ansible 2.4 compatibility
  issue #554: don't rely on tmp_path autoremoval in test.
  issue #554: track and remove multiple make_tmp_path() calls.
  docs: update Changelog.
  docs: drastically simplify install/changelog.
  issue #552: include process identity in log messages.
  issue #550: update Changelog.
  issue #550: parent: add explanatory comment.
  issue #550: fix up TTY ioctls on WSL 2016 Anniversary Update
  docs: update Changelog.
  service: make service list optional.
  docs: update Changelog; closes #548.
  issue #548: always treat transport=smart as 'ssh' for mitogen_via=.
  docs: better intro paragraph.
  .ci: copy private key file to tempdir.
  os_fork: more doc tweaks
  os_fork: more doc tweaks
  os_fork: yet more doc tidyup
  os_fork: more doc tweaks
  os_fork: clean up docs
  .ci: import soak scripts.
  .ci: allow containers for different jobs to run simultaneously
  os_fork: python 3 fixes and tests.
  issue #535: activate Corker on 2.4 in master too.
  issue #535: update Changelog.
  issue #535: wire mitogen.os_fork into Broker and Pool.
  issue #535: parent: add create_socketpair(size=..) parameter.
  issue #535: introduce mitogen.os_fork module and Corker class.
  issue #535: docs: update Changelog
  issue #535: service: support Pool.defer() like Broker.defer()
  issue #535: core: unicode.encode() may take importer lock on 2.x
  issue #535: docs: fix up Select doc
  issue #535: docs: update Changelog.
  issue #535: core/select: support selecting from Latches.
  core: increase cookie field lengths to 64-bit; closes #545.
  tests: ensure serialization restrictions are in effect
  tests/bench: set process affinity in throughput.py.
  docs: update copyright year.
  docs: update Changelog.
  core: Make Latch.put(obj=) optional.
  docs: change 'unreleased' Changelog format and add a hint.
  docs: update Changelog; closes #542.
  issue #542: return of select poller, new selection logic
  issue #542: .ci: move some tests to Azure and enable Mac job.
  ansible: create stub __init__.py for sdist.
7 years ago
David Wilson ae80d42cb4 Merge remote-tracking branch 'origin/dmw' into stable
* origin/dmw:
  issue #537: disable just the trivial LinuxPolicyTest on Travis.
  docs: update Changelog; closes #537.
  ansible: refactor affinity class and add abstract tests.
  Bump version for release.
  docs: update Changelog.
  core: serialize calls to _service_stub_main().
  docs: update Changelog; closes #532.
  issue #532: PushFileService race.
  docs: more concise Changelog.
  issue #541: changelog typos.
  ansible: quiesce boto logger; closes #541.
  docs: update Changelog.
  tests/ansible: Spec.port() test & mitogen_via= fix.
  Update copyright year everywhere.
  tests/ansible: Spec.become_pass() test.
  docs: remove top "Table of Contents" link
  docs: remove a little more top margin wastage
  tests/ansible: Spec.become_user() test.
  docs: update Changelog; closes #539.
  issue #539: disable logger propagation.
  ansible: capture stderr stream of async tasks. Closes #540.
  docs: update Changelog.
  issue #536: rework how 2.3-compatible simplejson is served
  .github: add some more questions to issue template
  docs: duplicate word
  docs: update Changelog.
  tests/ansible: Spec.become_method() test & mitogen_via= fix.
  setup.py: include LICENSE; closes #538.
  tests/ansible: Spec.become() test
  tests/ansible: Spec.password() test, document interactive pw limitation.
  tests/ansible: Spec.remote_user() test & mitogen_via= fix.
  tests/ansible: Spec.remote_addr() test & mitogen_via= fix.
  tests/ansible: Spec.transport() test.
  docs: lighter pink
  docs: add 'Fixes' heading
  docs: more margin tweaks for changelog
  docs: tighter <p> margins, even less shouting, red headings
  docs: tidy up footer and GitHub link
  docs: enable fixed_sidebar
  docs: sans-serif fonts, reduce shouty headings
  issue #536: add mitogen_via= tests too.
  ansible: fix a crash on 2.3 when mitogen_via= host is missing.
  tests: for 2.3 compatibility, disable gcloud.py for now
  docs: update Changelog; closes #511, closes #536.
  docs: update Changelog release date.
  issue #536: disable transport_config tests on vanilla
  issue #536: restore correct Python interpreter selection behaviour.
  issue #536: connection_delegation/ tests were erroneously broken
  tests: define MITOGEN_INVENTORY_FILE even if -i unspecified.
  issue #536: add tests for each ansible_python_interpreter case.
  issue #536: stop defining explicit localhost in inventory.
  tests: allow running Ansible tests locally without -udmw again.
  stable: fix preamble_size on stable docs.
  issue #481: add test.
7 years ago
David Wilson 129f7c5dea Merge remote-tracking branch 'origin/docs-fix' into stable
* origin/docs-fix:
  stable: fix preamble_size on stable docs.
7 years ago
David Wilson cf1286b9e1 stable: fix preamble_size on stable docs. 7 years ago
David Wilson e56db4ccb7 Merge remote-tracking branch 'origin/v024' into stable
* origin/v024: (662 commits)
  docs: update Changelog release date.
  Bump version for release.
  docs: update Changelog; closes #481
  issue #481: core: preserve stderr TTY FD if one is present.
  issue #481: avoid crash if disconnect occurs during forward_modules()
  Add a few more important modules to preamble_size.py.
  .ci: add verbiage for run_batches() too.
  .ci: add README.md.
  docs: update thanks
  docs: lose "approaching stability" language, we're pretty good now
  docs: fix changelog syntax/order/"20KB"
  tests: add new compression parameter to mitogen_get_stack results
  tests: disable affinity_test on Travis :/
  issue #508: fix responder stats test due to new smaller parent.py.
  issue #508: tests: skip minify_test Py2.4/2.5 for profiler.py.
  tests: fix fallout from 36fb318adf5c56e729296c3efce84f4dd75ced4e
  issue #520: add AIX auth failure string to su.
  tests: move affinity_test to Ansible tests.
  core: cProfile is not available in 2.4.
  issue #505: docs: add new detail graph for one scenario.
  docs: update and re-record profile graphs in docs; closes #505
  service: fix PushFileService exception
  tests: pad out localhost-*
  service: start pool shutdown on broker shutdown.
  master: .encode() needed for Py3.
  ansible: stash PID files in CWD if requested for debugging.
  issue #508: master: minify_safe_re must be bytes for Py3.
  bench: tidy up and cpu-pin some more files.
  tests: add localhost-x100
  ansible: double the default pool size.
  ansible: raise error with correct exception type.
  issue #508: master: minify all Mitogen/ansible_mitogen sources.
  parent: PartialZlib docstrings.
  ansible: hacky parser to alow bools to be specified on command line
  parent: pre-cache bootstrap if possible.
  docs: update Changelog.
  ansible: add mitogen_ssh_compression variable.
  service: PushFileService never recorded a file as sent.
  parent: synchronize get_core_source()
  service: use correct profile aggregation name.
  SyntaxError.
  ansible: don't pin controller if <4 cores.
  tests: make soak testing work reliably on vanilla.
  docs: changelog tidyups.
  ansible: document and make affinity stuff portable to non-Linux
  ansible: fix affinity.py test failure on 2 cores.
  ansible: preheat PluginLoader caches before fork.
  tests: make mitogen_shutdown_all be run_once by default.
  docs: update Changelog.
  ansible: use Poller for WorkerProcess; closes #491.
  ansible: new multiplexer/workers configuration
  docs: update Changelog.
  docs: update Changelog.
  ansible: pin connection multiplexer to a single core
  utils: pad out reset_affinity() and integrate with detach_popen()
  utils: import reset_affinity() function.
  master: set Router.profiling if MITOGEN_PROFILING variable present.
  parent: don't kill children when profiling is active.
  ansible: hook strategy and worker processes into profiler
  profiler: import from linear2 branch
  core: tidy up existing profiling code and support MITOGEN_PROFILE_FMT
  issue #260: redundant if statement.
  ansible: ensure MuxProcess MITOGEN_PROFILING results reach disk.
  ansible/bench: make end= configurable.
  master: cache sent/forwarded module names
  Aggregate code coverage data across tox all runs
  Allow independant control of coverage erase and reporting
  Fix incorrect attempt to use coverage
  docs: update Changelog; closes #527.
  issue #527: catch new-style module tracebacks like vanilla.
  Fix DeprecationWarning in mitogen.utils.run_with_router()
  Generate coverage report even if some tests fail
  ci: fix incorrect partition/rpartition from 8a4caea84f
  issue #260: hide force-disconnect messages.
  issue #498: fix shutdown crash
  issue #260: avoid start_transmit()/on_transmit()/stop_transmit()
  core: ensure broker profiling output reaches disk
  master: keep is_stdlib_path() result as negative cache entry
  ci: Allow DISTROS="debian*32" variable, and KEEP=1
  Use develop mode in tox
  issue #429: fix sudo regression.
  misc: rename to scripts. tab completion!!
  core: Latch._wake improvements
  issue #498: prevent crash on double 'disconnect' signal.
  issue #413: don't double-propagate DEL_ROUTE to parent.
  issue #498: wrap Router dict mutations in a lock
  issue #429: enable en_US locale to unbreak debops test.
  issue #499: fix another mind-numbingly stupid vanilla inconsistency
  issue #497: do our best to cope with crap upstream code
  ssh: fix test to match updated log format.
  issue #429: update Changelog.
  issue #429: update Changelog.
  issue #429: teach sudo about every know i18n password string.
  issue #429: install i18n-related bits in test images.
  ssh: tidy up logs and stream names.
  tests: ensure file is closed in connection_test.
  gcloud: small updates
  tests: give ansible/gcloud/ its own requirements file.
  issue #499: another totally moronic implementation difference
  issue #499: disable new test on vanilla.
  ...
7 years ago
David Wilson d9696c1cd5 docs: update Changelog release date. 7 years ago
David Wilson 0114358df0 Merge remote-tracking branch 'origin/master' into v024
* origin/master: (661 commits)
  Bump version for release.
  docs: update Changelog; closes #481
  issue #481: core: preserve stderr TTY FD if one is present.
  issue #481: avoid crash if disconnect occurs during forward_modules()
  Add a few more important modules to preamble_size.py.
  .ci: add verbiage for run_batches() too.
  .ci: add README.md.
  docs: update thanks
  docs: lose "approaching stability" language, we're pretty good now
  docs: fix changelog syntax/order/"20KB"
  tests: add new compression parameter to mitogen_get_stack results
  tests: disable affinity_test on Travis :/
  issue #508: fix responder stats test due to new smaller parent.py.
  issue #508: tests: skip minify_test Py2.4/2.5 for profiler.py.
  tests: fix fallout from 36fb318adf5c56e729296c3efce84f4dd75ced4e
  issue #520: add AIX auth failure string to su.
  tests: move affinity_test to Ansible tests.
  core: cProfile is not available in 2.4.
  issue #505: docs: add new detail graph for one scenario.
  docs: update and re-record profile graphs in docs; closes #505
  service: fix PushFileService exception
  tests: pad out localhost-*
  service: start pool shutdown on broker shutdown.
  master: .encode() needed for Py3.
  ansible: stash PID files in CWD if requested for debugging.
  issue #508: master: minify_safe_re must be bytes for Py3.
  bench: tidy up and cpu-pin some more files.
  tests: add localhost-x100
  ansible: double the default pool size.
  ansible: raise error with correct exception type.
  issue #508: master: minify all Mitogen/ansible_mitogen sources.
  parent: PartialZlib docstrings.
  ansible: hacky parser to alow bools to be specified on command line
  parent: pre-cache bootstrap if possible.
  docs: update Changelog.
  ansible: add mitogen_ssh_compression variable.
  service: PushFileService never recorded a file as sent.
  parent: synchronize get_core_source()
  service: use correct profile aggregation name.
  SyntaxError.
  ansible: don't pin controller if <4 cores.
  tests: make soak testing work reliably on vanilla.
  docs: changelog tidyups.
  ansible: document and make affinity stuff portable to non-Linux
  ansible: fix affinity.py test failure on 2 cores.
  ansible: preheat PluginLoader caches before fork.
  tests: make mitogen_shutdown_all be run_once by default.
  docs: update Changelog.
  ansible: use Poller for WorkerProcess; closes #491.
  ansible: new multiplexer/workers configuration
  docs: update Changelog.
  docs: update Changelog.
  ansible: pin connection multiplexer to a single core
  utils: pad out reset_affinity() and integrate with detach_popen()
  utils: import reset_affinity() function.
  master: set Router.profiling if MITOGEN_PROFILING variable present.
  parent: don't kill children when profiling is active.
  ansible: hook strategy and worker processes into profiler
  profiler: import from linear2 branch
  core: tidy up existing profiling code and support MITOGEN_PROFILE_FMT
  issue #260: redundant if statement.
  ansible: ensure MuxProcess MITOGEN_PROFILING results reach disk.
  ansible/bench: make end= configurable.
  master: cache sent/forwarded module names
  Aggregate code coverage data across tox all runs
  Allow independant control of coverage erase and reporting
  Fix incorrect attempt to use coverage
  docs: update Changelog; closes #527.
  issue #527: catch new-style module tracebacks like vanilla.
  Fix DeprecationWarning in mitogen.utils.run_with_router()
  Generate coverage report even if some tests fail
  ci: fix incorrect partition/rpartition from 8a4caea84f
  issue #260: hide force-disconnect messages.
  issue #498: fix shutdown crash
  issue #260: avoid start_transmit()/on_transmit()/stop_transmit()
  core: ensure broker profiling output reaches disk
  master: keep is_stdlib_path() result as negative cache entry
  ci: Allow DISTROS="debian*32" variable, and KEEP=1
  Use develop mode in tox
  issue #429: fix sudo regression.
  misc: rename to scripts. tab completion!!
  core: Latch._wake improvements
  issue #498: prevent crash on double 'disconnect' signal.
  issue #413: don't double-propagate DEL_ROUTE to parent.
  issue #498: wrap Router dict mutations in a lock
  issue #429: enable en_US locale to unbreak debops test.
  issue #499: fix another mind-numbingly stupid vanilla inconsistency
  issue #497: do our best to cope with crap upstream code
  ssh: fix test to match updated log format.
  issue #429: update Changelog.
  issue #429: update Changelog.
  issue #429: teach sudo about every know i18n password string.
  issue #429: install i18n-related bits in test images.
  ssh: tidy up logs and stream names.
  tests: ensure file is closed in connection_test.
  gcloud: small updates
  tests: give ansible/gcloud/ its own requirements file.
  issue #499: another totally moronic implementation difference
  issue #499: disable new test on vanilla.
  docs: update Changelog; closes #499.
  ...
7 years ago
David Wilson 71f8e84845 docs: 4kify images.
These commits were squashed to avoid repo size exploding.

[cherrypick from master]
7 years ago
David Wilson 2ab6394d1c docs: fix up incomplete Temporary Files section.
[cherrypick from master]
7 years ago
David Wilson 3c63290445 docs: comment out temp files section until I have a chance to write it. 7 years ago
David Wilson 5667116f58 Merge remote-tracking branch 'origin/master' into stable (0.2.3) 7 years ago
David Wilson 2446f85cb6 docs: host demo on Vimeo. 7 years ago
David Wilson ff5044272f Merge branch 'master' into stable (missing changelog) 7 years ago
David Wilson b1c7afa948 Merge remote-tracking branch 'origin/master' into stable v0.2.2 7 years ago
David Wilson 92e058c178 docs: glaring ancient typo. 7 years ago
David Wilson 74eb9b2702 docs: fix lock icon. 7 years ago
David Wilson d16f7eec26 docs: link to PyPI release, not GitHub archive URL.
Now download counts are visible via PSF BigQuery.
7 years ago
David Wilson 2a53d7b658 docs: add "no route" to known issues. 7 years ago
David Wilson bac2fe1689 docs: add jgadling to Contributors 7 years ago
David Wilson f8e191ca8d Merge branch 'master' into stable v0.2.1. 8 years ago

@ -34,12 +34,12 @@ ANSIBLE_TESTS_HOSTS_DIR = os.path.join(GIT_ROOT, 'tests/ansible/hosts')
ANSIBLE_TESTS_TEMPLATES_DIR = os.path.join(GIT_ROOT, 'tests/ansible/templates') ANSIBLE_TESTS_TEMPLATES_DIR = os.path.join(GIT_ROOT, 'tests/ansible/templates')
DISTRO_SPECS = os.environ.get( DISTRO_SPECS = os.environ.get(
'MITOGEN_TEST_DISTRO_SPECS', 'MITOGEN_TEST_DISTRO_SPECS',
'alma9-py3 centos5 centos8-py3 debian9 debian12-py3 ubuntu1604 ubuntu2404-py3', 'centos6 centos8 debian9 debian11 ubuntu1604 ubuntu2004',
) )
IMAGE_PREP_DIR = os.path.join(GIT_ROOT, 'tests/image_prep') IMAGE_PREP_DIR = os.path.join(GIT_ROOT, 'tests/image_prep')
IMAGE_TEMPLATE = os.environ.get( IMAGE_TEMPLATE = os.environ.get(
'MITOGEN_TEST_IMAGE_TEMPLATE', 'MITOGEN_TEST_IMAGE_TEMPLATE',
'ghcr.io/mitogen-hq/%(distro)s-test:2025.02', 'ghcr.io/mitogen-hq/%(distro)s-test:2021',
) )
SUDOERS_DEFAULTS_SRC = './tests/image_prep/files/sudoers_defaults' SUDOERS_DEFAULTS_SRC = './tests/image_prep/files/sudoers_defaults'
SUDOERS_DEFAULTS_DEST = '/etc/sudoers.d/mitogen_test_defaults' SUDOERS_DEFAULTS_DEST = '/etc/sudoers.d/mitogen_test_defaults'
@ -156,15 +156,7 @@ def run_batches(batches):
subprocess.Popen(combine(batch), shell=True) subprocess.Popen(combine(batch), shell=True)
for batch in batches for batch in batches
] ]
for proc in procs: assert [proc.wait() for proc in procs] == [0] * len(procs)
proc.wait()
if proc.returncode:
print(
'proc: pid=%i rc=%i args=%r'
% (proc.pid, proc.returncode, proc.args),
file=sys.stderr, flush=True,
)
assert [proc.returncode for proc in procs] == [0] * len(procs)
def get_output(s, *args, **kwargs): def get_output(s, *args, **kwargs):
@ -239,7 +231,7 @@ def container_specs(
[{'distro': 'debian11', [{'distro': 'debian11',
'family': 'debian', 'family': 'debian',
'hostname': 'localhost', 'hostname': 'localhost',
'image': 'ghcr.io/mitogen-hq/debian11-test:2025.02', 'image': 'ghcr.io/mitogen-hq/debian11-test:2021',
'index': 1, 'index': 1,
'name': 'target-debian11-1', 'name': 'target-debian11-1',
'port': 2201, 'port': 2201,
@ -247,7 +239,7 @@ def container_specs(
{'distro': 'centos6', {'distro': 'centos6',
'family': 'centos', 'family': 'centos',
'hostname': 'localhost', 'hostname': 'localhost',
'image': 'ghcr.io/mitogen-hq/centos6-test:2025.02', 'image': 'ghcr.io/mitogen-hq/centos6-test:2021',
'index': 2, 'index': 2,
'name': 'target-centos6-2', 'name': 'target-centos6-2',
'port': 2202, 'port': 2202,

@ -0,0 +1,33 @@
---
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".

@ -0,0 +1,33 @@
---
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".

@ -1,62 +0,0 @@
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, ...

@ -101,21 +101,21 @@ jobs:
- tox_env: py313-m_ans-ans8 - tox_env: py313-m_ans-ans8
python_version: '3.13' python_version: '3.13'
- tox_env: py314-m_ans-ans9 - tox_env: py314-m_ans-ans9
python_version: '3.14' python_version: '3.14.0-rc.3'
- tox_env: py314-m_ans-ans10 - tox_env: py314-m_ans-ans10
python_version: '3.14' python_version: '3.14.0-rc.3'
- tox_env: py314-m_ans-ans11 - tox_env: py314-m_ans-ans11
python_version: '3.14' python_version: '3.14.0-rc.3'
- tox_env: py314-m_ans-ans12 - tox_env: py314-m_ans-ans12
python_version: '3.14' python_version: '3.14.0-rc.3'
- tox_env: py314-m_ans-ans13
python_version: '3.14'
- tox_env: py314-m_ans-ans13-s_lin - tox_env: py314-m_ans-ans11-s_lin
python_version: '3.14' python_version: '3.14.0-rc.3'
- tox_env: py314-m_ans-ans12-s_lin
python_version: '3.14.0-rc.3'
- tox_env: py314-m_mtg - tox_env: py314-m_mtg
python_version: '3.14' python_version: '3.14.0-rc.3'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -153,21 +153,27 @@ jobs:
macos: macos:
name: macos ${{ matrix.tox_env }} name: macos ${{ matrix.tox_env }}
# https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md
runs-on: macos-15 runs-on: macos-13
timeout-minutes: 15 timeout-minutes: 15
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- tox_env: py314-m_lcl-ans13 - tox_env: py314-m_lcl-ans11
python_version: '3.14' python_version: '3.14.0-rc.3'
- tox_env: py314-m_lcl-ans13-s_lin sshpass_version: "1.10"
python_version: '3.14' - tox_env: py314-m_lcl-ans11-s_lin
python_version: '3.14.0-rc.3'
sshpass_version: "1.10"
- tox_env: py314-m_lcl-ans12
python_version: '3.14.0-rc.3'
- tox_env: py314-m_lcl-ans12-s_lin
python_version: '3.14.0-rc.3'
- tox_env: py314-m_mtg - tox_env: py314-m_mtg
python_version: '3.14' python_version: '3.14.0-rc.3'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

1
.gitignore vendored

@ -13,7 +13,6 @@ build/
dist/ dist/
extra/ extra/
tests/ansible/.*.pid tests/ansible/.*.pid
tests/image_prep/logs
docs/_build/ docs/_build/
htmlcov/ htmlcov/
*.egg-info *.egg-info

@ -0,0 +1,10 @@
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,3 +7,5 @@
<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,6 +49,18 @@ __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."
@ -66,6 +78,11 @@ 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

@ -470,7 +470,18 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase):
# chicken-and-egg issue, mitogen needs a python to run low_level_execute_command # chicken-and-egg issue, mitogen needs a python to run low_level_execute_command
# which is required by Ansible's discover_interpreter function # which is required by Ansible's discover_interpreter function
if self._mitogen_discovering_interpreter: if self._mitogen_discovering_interpreter:
possible_pythons = self._mitogen_interpreter_candidates possible_pythons = [
'/usr/bin/python',
'python3',
'python3.7',
'python3.6',
'python3.5',
'python2.7',
'python2.6',
'/usr/libexec/platform-python',
'/usr/bin/python3',
'python'
]
else: else:
# not used, just adding a filler value # not used, just adding a filler value
possible_pythons = ['python'] possible_pythons = ['python']
@ -481,15 +492,12 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase):
rc, stdout, stderr = self._connection.exec_command( rc, stdout, stderr = self._connection.exec_command(
cmd, in_data, sudoable, mitogen_chdir=chdir, cmd, in_data, sudoable, mitogen_chdir=chdir,
) )
except BaseException as exc: # TODO: what exception is thrown?
except:
# we've reached the last python attempted and failed # we've reached the last python attempted and failed
if possible_python == possible_pythons[-1]: if possible_python == possible_pythons[-1]:
raise raise
else: else:
LOG.debug(
'%r._low_level_execute_command: candidate=%r ignored: %s, %r',
self, possible_python, type(exc), exc,
)
continue continue
stdout_text = to_text(stdout, errors=encoding_errors) stdout_text = to_text(stdout, errors=encoding_errors)

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2025 Mitogen authors <https://github.com/mitogen-hq>
# SPDX-License-Identifier: BSD-3-Clause
# !mitogen: minify_safe
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -30,16 +30,8 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
import ansible.errors import ansible.errors
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection
import ansible_mitogen.loaders import ansible_mitogen.loaders

@ -30,12 +30,6 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection
import ansible_mitogen.process import ansible_mitogen.process

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,9 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
from ansible.plugins.connection.ssh import ( from ansible.plugins.connection.ssh import (
DOCUMENTATION as _ansible_ssh_DOCUMENTATION, DOCUMENTATION as _ansible_ssh_DOCUMENTATION,
) )
@ -47,10 +44,6 @@ DOCUMENTATION = """
options: options:
""" + _ansible_ssh_DOCUMENTATION.partition('options:\n')[2] """ + _ansible_ssh_DOCUMENTATION.partition('options:\n')[2]
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection
import ansible_mitogen.loaders import ansible_mitogen.loaders

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -29,14 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.connection import ansible_mitogen.connection

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2025 Mitogen authors <https://github.com/mitogen-hq>
# SPDX-License-Identifier: BSD-3-Clause
# !mitogen: minify_safe
import os
import sys
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))

@ -29,8 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
# #
# This is not the real Strategy implementation module, it simply exists as a # This is not the real Strategy implementation module, it simply exists as a
@ -47,11 +45,6 @@ import sys
# debuggers and isinstance() work predictably. # debuggers and isinstance() work predictably.
# #
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.strategy import ansible_mitogen.strategy
import ansible.plugins.strategy.linear import ansible.plugins.strategy.linear

@ -29,8 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
# #
# This is not the real Strategy implementation module, it simply exists as a # This is not the real Strategy implementation module, it simply exists as a
@ -47,11 +45,6 @@ import sys
# debuggers and isinstance() work predictably. # debuggers and isinstance() work predictably.
# #
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.loaders import ansible_mitogen.loaders
import ansible_mitogen.strategy import ansible_mitogen.strategy

@ -29,8 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
# #
# This is not the real Strategy implementation module, it simply exists as a # This is not the real Strategy implementation module, it simply exists as a
@ -47,11 +45,6 @@ import sys
# debuggers and isinstance() work predictably. # debuggers and isinstance() work predictably.
# #
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.loaders import ansible_mitogen.loaders
import ansible_mitogen.strategy import ansible_mitogen.strategy

@ -29,8 +29,6 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
import os
import sys
# #
# This is not the real Strategy implementation module, it simply exists as a # This is not the real Strategy implementation module, it simply exists as a
@ -47,11 +45,6 @@ import sys
# debuggers and isinstance() work predictably. # debuggers and isinstance() work predictably.
# #
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))
import ansible_mitogen.loaders import ansible_mitogen.loaders
import ansible_mitogen.strategy import ansible_mitogen.strategy

@ -40,6 +40,7 @@ import errno
import grp import grp
import json import json
import logging import logging
import operator
import os import os
import pty import pty
import pwd import pwd
@ -65,6 +66,8 @@ if not sys.modules.get(str('__main__')):
import ansible.module_utils.json_utils import ansible.module_utils.json_utils
from ansible.module_utils.six.moves import reduce
import ansible_mitogen.runner import ansible_mitogen.runner
@ -715,9 +718,7 @@ def apply_mode_spec(spec, mode):
mask = CHMOD_MASKS[ch] mask = CHMOD_MASKS[ch]
bits = CHMOD_BITS[ch] bits = CHMOD_BITS[ch]
cur_perm_bits = mode & mask cur_perm_bits = mode & mask
new_perm_bits = 0 new_perm_bits = reduce(operator.or_, (bits[p] for p in perms), 0)
for perm in perms:
new_perm_bits |= bits[perm]
mode &= ~mask mode &= ~mask
if op == '=': if op == '=':
mode |= new_perm_bits mode |= new_perm_bits

@ -73,21 +73,13 @@ import ansible.utils.unsafe_proxy
from ansible.module_utils.six import with_metaclass from ansible.module_utils.six import with_metaclass
from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.parsing.convert_bool import boolean
import ansible_mitogen.utils
import mitogen.core import mitogen.core
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
if ansible_mitogen.utils.ansible_version[:2] >= (2, 19):
_FALLBACK_INTERPRETER = ansible.executor.interpreter_discovery._FALLBACK_INTERPRETER
elif ansible_mitogen.utils.ansible_version[:2] >= (2, 17):
_FALLBACK_INTERPRETER = u'/usr/bin/python3'
else:
_FALLBACK_INTERPRETER = u'/usr/bin/python'
def run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_python):
def run_interpreter_discovery_if_necessary(s, candidates, task_vars, action, rediscover_python):
""" """
Triggers ansible python interpreter discovery if requested. Triggers ansible python interpreter discovery if requested.
Caches this value the same way Ansible does it. Caches this value the same way Ansible does it.
@ -115,11 +107,8 @@ def run_interpreter_discovery_if_necessary(s, candidates, task_vars, action, red
# blow away the discovered_interpreter_config cache and rediscover # blow away the discovered_interpreter_config cache and rediscover
del task_vars['ansible_facts'][discovered_interpreter_config] del task_vars['ansible_facts'][discovered_interpreter_config]
try: if discovered_interpreter_config not in task_vars['ansible_facts']:
s = task_vars[u'ansible_facts'][discovered_interpreter_config]
except KeyError:
action._mitogen_discovering_interpreter = True action._mitogen_discovering_interpreter = True
action._mitogen_interpreter_candidates = candidates
# fake pipelining so discover_interpreter can be happy # fake pipelining so discover_interpreter can be happy
action._connection.has_pipelining = True action._connection.has_pipelining = True
s = ansible.executor.interpreter_discovery.discover_interpreter( s = ansible.executor.interpreter_discovery.discover_interpreter(
@ -132,17 +121,18 @@ def run_interpreter_discovery_if_necessary(s, candidates, task_vars, action, red
# cache discovered interpreter # cache discovered interpreter
task_vars['ansible_facts'][discovered_interpreter_config] = s task_vars['ansible_facts'][discovered_interpreter_config] = s
action._connection.has_pipelining = False action._connection.has_pipelining = False
else:
s = task_vars['ansible_facts'][discovered_interpreter_config]
# propagate discovered interpreter as fact # propagate discovered interpreter as fact
action._discovered_interpreter_key = discovered_interpreter_config action._discovered_interpreter_key = discovered_interpreter_config
action._discovered_interpreter = s action._discovered_interpreter = s
action._mitogen_discovering_interpreter = False action._mitogen_discovering_interpreter = False
action._mitogen_interpreter_candidates = None
return s return s
def parse_python_path(s, candidates, task_vars, action, rediscover_python): def parse_python_path(s, task_vars, action, rediscover_python):
""" """
Given the string set for ansible_python_interpeter, parse it using shell Given the string set for ansible_python_interpeter, parse it using shell
syntax and return an appropriate argument vector. If the value detected is syntax and return an appropriate argument vector. If the value detected is
@ -153,9 +143,10 @@ def parse_python_path(s, candidates, task_vars, action, rediscover_python):
# if python_path doesn't exist, default to `auto` and attempt to discover it # if python_path doesn't exist, default to `auto` and attempt to discover it
s = 'auto' s = 'auto'
s = run_interpreter_discovery_if_necessary(s, candidates, task_vars, action, rediscover_python) s = run_interpreter_discovery_if_necessary(s, task_vars, action, rediscover_python)
# if unable to determine python_path, fallback to '/usr/bin/python'
if not s: if not s:
s = _FALLBACK_INTERPRETER s = '/usr/bin/python'
return ansible.utils.shlex.shlex_split(s) return ansible.utils.shlex.shlex_split(s)
@ -519,9 +510,6 @@ class PlayContextSpec(Spec):
interpreter_python = C.config.get_config_value( interpreter_python = C.config.get_config_value(
'INTERPRETER_PYTHON', variables=variables, 'INTERPRETER_PYTHON', variables=variables,
) )
interpreter_python_fallback = C.config.get_config_value(
'INTERPRETER_PYTHON_FALLBACK', variables=variables,
)
if '{{' in interpreter_python or '{%' in interpreter_python: if '{{' in interpreter_python or '{%' in interpreter_python:
templar = self._connection.templar templar = self._connection.templar
@ -529,7 +517,6 @@ class PlayContextSpec(Spec):
return parse_python_path( return parse_python_path(
interpreter_python, interpreter_python,
candidates=interpreter_python_fallback,
task_vars=self._task_vars, task_vars=self._task_vars,
action=self._action, action=self._action,
rediscover_python=rediscover_python) rediscover_python=rediscover_python)
@ -745,12 +732,11 @@ class MitogenViaSpec(Spec):
def python_path(self, rediscover_python=False): def python_path(self, rediscover_python=False):
s = self._host_vars.get('ansible_python_interpreter') s = self._host_vars.get('ansible_python_interpreter')
interpreter_python_fallback = self._host_vars.get( # #511, #536: executor/module_common.py::_get_shebang() hard-wires
'ansible_interpreter_python_fallback', [], # "/usr/bin/python" as the default interpreter path if no other
) # interpreter is specified.
return parse_python_path( return parse_python_path(
s, s,
candidates=interpreter_python_fallback,
task_vars=self._task_vars, task_vars=self._task_vars,
action=self._action, action=self._action,
rediscover_python=rediscover_python) rediscover_python=rediscover_python)

@ -145,8 +145,6 @@ Noteworthy Differences
+-----------------+ 3.11 - 3.14 | +-----------------+ 3.11 - 3.14 |
| 12 | | | 12 | |
+-----------------+-----------------+ +-----------------+-----------------+
| 13 | 3.12 - 3.14 |
+-----------------+-----------------+
Verify your installation is running one of these versions by checking Verify your installation is running one of these versions by checking
``ansible --version`` output. ``ansible --version`` output.

@ -18,62 +18,6 @@ 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/>`_.
In progress (unreleased)
------------------------
* :gh:issue:`1237` :mod:`mitogen`: Re-declare Python 2.4 compatibility
* :gh:issue:`1385` :mod:`ansible_mitogen`: Remove a use of
``ansible.module_utils.six``
* :gh:issue:`1354` docs: Document Ansible 13 (ansible-core 2.20) support
* :gh:issue:`1354` :mod:`mitogen`: Clarify error message when a module
request would be refused by allow or deny listing
v0.3.35 (2025-12-01)
--------------------
* :gh:issue:`1132` :mod:`ansible_mitogen` During intrepreter discovery use
Ansible ``INTERPRETER_PYTHON_FALLBACK`` config as list of candidates
v0.3.34 (2025-11-27)
--------------------
* :gh:issue:`1118` CI: Use 2025.02 test images, keeping same OS releases
* :gh:issue:`1358` CI: Bump deprecated macOS 13 runner to macOS 15
* :gh:issue:`1118` CI: Add OS release coverage: AlmaLinux 9
* :gh:issue:`1118` CI: Add OS release coverage: CentOS 5
* :gh:issue:`1118` CI: Add OS release coverage: Debian 12
* :gh:issue:`1118` CI: Add OS release coverage: Ubuntu 22.04, Ubuntu 24.04
* :gh:issue:`1124` :mod:`mitogen`: Log why a module is sent or not sent by
:class:`mitogen.master.ModuleResponder`
* :gh:issue:`1124` :mod:`ansible_mitogen`: Speedup startup by not sending
``__main__`` as a related module
v0.3.33 (2025-11-22)
--------------------
* :gh:issue:`1354` :mod:`ansible_mitogen`: ansible_mitogen: Ansible 13
(ansible-core 2.20) support
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)
--------------------
* :gh:issue:`1350` :mod:`ansible_mitogen`: Fix regression when loading plugins
from ``/custom/path/to/mitogen``
v0.3.30 (2025-10-30) v0.3.30 (2025-10-30)
-------------------- --------------------
@ -448,7 +392,7 @@ v0.3.1 (unreleased)
* :gh:issue:`878` Kubectl connector fixed with Ansible 2.10 and above * :gh:issue:`878` Kubectl connector fixed with Ansible 2.10 and above
v0.3.0 (2021-11-24) v0.3.0 (2021-10-28)
------------------- -------------------
This release separates itself from the v0.2.X releases. Ansible's API changed too much to support backwards compatibility so from now on, v0.2.X releases will be for Ansible < 2.10 and v0.3.X will be for Ansible 2.10+. This release separates itself from the v0.2.X releases. Ansible's API changed too much to support backwards compatibility so from now on, v0.2.X releases will be for Ansible < 2.10 and v0.3.X will be for Ansible 2.10+.
@ -461,7 +405,7 @@ This release separates itself from the v0.2.X releases. Ansible's API changed to
* :gh:issue:`847` Removed historic Continuous Integration reverse shell * :gh:issue:`847` Removed historic Continuous Integration reverse shell
v0.2.10 (2021-11-24) v0.2.10 (2021-10-28)
-------------------- --------------------
* :gh:issue:`597` mitogen does not support Ansible 2.8 Python interpreter detection * :gh:issue:`597` mitogen does not support Ansible 2.8 Python interpreter detection
@ -476,6 +420,7 @@ v0.2.10 (2021-11-24)
:py:meth:`ansible.plugins.callback.CallbackBase.v2_runner_on_start` :py:meth:`ansible.plugins.callback.CallbackBase.v2_runner_on_start`
* :gh:issue:`775` Test with Python 3.9 * :gh:issue:`775` Test with Python 3.9
* :gh:issue:`775` Add msvcrt to the default module deny list * :gh:issue:`775` Add msvcrt to the default module deny list
* :gh:issue:`847` Removed historic Continuous Integration reverse shell
v0.2.9 (2019-11-02) v0.2.9 (2019-11-02)

@ -27,13 +27,14 @@ 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 :py:meth:`mitogen.parent.Connection._first_stage`, base64-encoded copy of the :py:meth:`mitogen.master.Stream._first_stage`
which is carefully written to maximize it compatibility and minimize its size. function, which has been carefully optimized to reduce its size. Prior to
A simplified illustration of the bootstrap command is compression and encoding, ``CONTEXT_NAME`` is replaced with the desired context
name in the function's source code.
.. code:: .. code::
python -c 'exec(sys.argv[1].decode("base64").decode("zlib"))' <base64> ... python -c 'exec "xxx".decode("base64").decode("zlib")'
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
@ -70,8 +71,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
fork parent re-executes Python with **argv[0]** composed of the Python parent half of the fork re-executes Python, with **argv[0]** taken from the
interpreter path and a remote name supplied by the Mitogen parent. As no ``CONTEXT_NAME`` variable earlier substituted into its source code. 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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 84 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 99 KiB

@ -332,16 +332,12 @@ a large fleet of machines, or to alert the parent of unexpected state changes.
Compatibility Compatibility
############# #############
``mitogen.*`` is compatible with Python 2.4 - 2.7 and 3.6 onward; making it Mitogen is compatible with **Python 2.4** released November 2004, making it
suitable for managing a fleet of potentially ancient corporate hardware, such suitable for managing a fleet of potentially ancient corporate hardware, such
as Red Hat Enterprise Linux 5, released in 2007. as Red Hat Enterprise Linux 5, released in 2007.
Every combination of Python 3.x/2.x parent and child should be possible. Every combination of Python 3.x/2.x parent and child should be possible,
Automated testing cannot cover every combination, automated testing tries to however at present only Python 2.4, 2.6, 2.7 and 3.6 are tested automatically.
cover the extemities (e.g. Python 3.14 parent -> Python 2.4 child).
``ansible_mitogen.*`` is compatible with Python 2.7 and 3.6 onward; making it
suitable for Ansible 2.10 onward.
Zero Dependencies Zero Dependencies

@ -0,0 +1,13 @@
# Add viewBox attr to SVGs lacking it, so IE scales properly.
import lxml.etree
import glob
for name in glob.glob('images/*.svg') + glob.glob('images/ansible/*.svg'):
doc = lxml.etree.parse(open(name))
svg = doc.getroot()
if 'viewBox' not in svg.attrib:
svg.attrib['viewBox'] = '0 0 %(width)s %(height)s' % svg.attrib
open(name, 'w').write(lxml.etree.tostring(svg, xml_declaration=True, encoding='UTF-8'))

@ -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, 36, 'dev') __version__ = (0, 3, 30)
#: 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

@ -541,7 +541,6 @@ def is_blacklisted_import(importer, fullname):
any packages have been whitelisted and `fullname` is not part of one. any packages have been whitelisted and `fullname` is not part of one.
NB: NB:
- The default whitelist is `['']` which matches any module name.
- If a package is on both lists, then it is treated as blacklisted. - If a package is on both lists, then it is treated as blacklisted.
- If any package is whitelisted, then all non-whitelisted packages are - If any package is whitelisted, then all non-whitelisted packages are
treated as blacklisted. treated as blacklisted.
@ -1537,8 +1536,9 @@ class Importer(object):
return importlib.machinery.ModuleSpec(fullname, loader=self) return importlib.machinery.ModuleSpec(fullname, loader=self)
blacklisted_msg = ( blacklisted_msg = (
'A %r request would be refused by the Mitogen master. The module is ' '%r is present in the Mitogen importer blacklist, therefore this '
'on the deny list (blacklist) or not on the allow list (whitelist).' 'context will not attempt to request it from the master, as the '
'request will always be refused.'
) )
pkg_resources_msg = ( pkg_resources_msg = (
'pkg_resources is prohibited from importing __main__, as it causes ' 'pkg_resources is prohibited from importing __main__, as it causes '

@ -843,12 +843,6 @@ class ModuleFinder(object):
related modules likely needed by a child context requesting the original related modules likely needed by a child context requesting the original
module. module.
""" """
# Fullnames of modules that should not be sent as a related module
_related_modules_denylist = frozenset({
'__main__',
})
def __init__(self): def __init__(self):
#: Import machinery is expensive, keep :py:meth`:get_module_source` #: Import machinery is expensive, keep :py:meth`:get_module_source`
#: results around. #: results around.
@ -937,34 +931,6 @@ class ModuleFinder(object):
fullname, _, _ = str_rpartition(to_text(fullname), u'.') fullname, _, _ = str_rpartition(to_text(fullname), u'.')
yield fullname yield fullname
def _reject_related_module(self, requested_fullname, related_fullname):
def _log_reject(reason):
LOG.debug(
'%r: Rejected related module %s of requested module %s: %s',
self, related_fullname, requested_fullname, reason,
)
return reason
try:
related_module = sys.modules[related_fullname]
except KeyError:
return _log_reject('sys.modules entry absent')
# Python 2.x "indirection entry"
if related_module is None:
return _log_reject('sys.modules entry is None')
if is_stdlib_name(related_fullname):
return _log_reject('stdlib module')
if 'six.moves' in related_fullname:
return _log_reject('six.moves avoidence')
if related_fullname in self._related_modules_denylist:
return _log_reject('on denylist')
return False
def find_related_imports(self, fullname): def find_related_imports(self, fullname):
""" """
Return a list of non-stdlib modules that are directly imported by Return a list of non-stdlib modules that are directly imported by
@ -1007,7 +973,9 @@ class ModuleFinder(object):
set( set(
mitogen.core.to_text(name) mitogen.core.to_text(name)
for name in maybe_names for name in maybe_names
if not self._reject_related_module(fullname, name) if sys.modules.get(name) is not None
and not is_stdlib_name(name)
and u'six.moves' not in name # TODO: crap
) )
)) ))
@ -1170,7 +1138,7 @@ class ModuleResponder(object):
self._cache[fullname] = tup self._cache[fullname] = tup
return tup return tup
def _send_load_module(self, stream, fullname, reason): def _send_load_module(self, stream, fullname):
if fullname not in stream.protocol.sent_modules: if fullname not in stream.protocol.sent_modules:
tup = self._build_tuple(fullname) tup = self._build_tuple(fullname)
msg = mitogen.core.Message.pickled( msg = mitogen.core.Message.pickled(
@ -1178,10 +1146,8 @@ class ModuleResponder(object):
dst_id=stream.protocol.remote_id, dst_id=stream.protocol.remote_id,
handle=mitogen.core.LOAD_MODULE, handle=mitogen.core.LOAD_MODULE,
) )
self._log.debug( self._log.debug('sending %s (%.2f KiB) to %s',
'sending %s %s (%.2f KiB) to %s', fullname, len(msg.data) / 1024.0, stream.name)
reason, fullname, len(msg.data) / 1024.0, stream.name,
)
self._router._async_route(msg) self._router._async_route(msg)
stream.protocol.sent_modules.add(fullname) stream.protocol.sent_modules.add(fullname)
if tup[2] is not None: if tup[2] is not None:
@ -1212,8 +1178,8 @@ class ModuleResponder(object):
# Parent hasn't been sent, so don't load submodule yet. # Parent hasn't been sent, so don't load submodule yet.
continue continue
self._send_load_module(stream, name, 'related') self._send_load_module(stream, name)
self._send_load_module(stream, fullname, 'requested') self._send_load_module(stream, fullname)
except Exception: except Exception:
LOG.debug('While importing %r', fullname, exc_info=True) LOG.debug('While importing %r', fullname, exc_info=True)
self._send_module_load_failed(stream, fullname) self._send_module_load_failed(stream, fullname)

@ -1396,6 +1396,10 @@ 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.
@ -1431,21 +1435,20 @@ 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]+os.uname()[2][:2]+sys.executable=='Darwin19/usr/bin/python':sys.executable+='2.7' 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.version[:3]=='Darwin202.7':os.environ['PYTHON_LAUNCHED_FROM_WRAPPER']='1' 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]=='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:%s)'%sys.argv[2]) os.execl(sys.executable,sys.executable+'(mitogen:CONTEXT_NAME)')
os.write(1,'MITO000\n'.encode()) os.write(1,'MITO000\n'.encode())
C=''.encode() C=''.encode()
while int(sys.argv[3])-len(C)and select.select([0],[],[]):C+=os.read(0,int(sys.argv[3])-len(C)) while PREAMBLE_COMPRESSED_LEN-len(C)and select.select([0],[],[]):C+=os.read(0,PREAMBLE_COMPRESSED_LEN-len(C))
C=zlib.decompress(C) C=zlib.decompress(C)
f=os.fdopen(W,'wb',0) fp=os.fdopen(W,'wb',0)
f.write(C) fp.write(C)
f.close() fp.close()
f=os.fdopen(w,'wb',0) fp=os.fdopen(w,'wb',0)
f.write(C) fp.write(C)
f.close() fp.close()
os.write(1,'MITO001\n'.encode()) os.write(1,'MITO001\n'.encode())
os.close(2) os.close(2)
@ -1466,10 +1469,11 @@ 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(' ', ' ')
compressor = zlib.compressobj( source = source.replace('CONTEXT_NAME', self.options.remote_name)
zlib.Z_BEST_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS, preamble_compressed = self.get_preamble()
) source = source.replace('PREAMBLE_COMPRESSED_LEN',
compressed = compressor.compress(source.encode()) + compressor.flush() str(len(preamble_compressed)))
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.
@ -1480,10 +1484,7 @@ 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(sys.argv[1]),-15))', 'exec(zlib.decompress(binascii.a2b_base64("%s")))' % (encoded.decode(),),
encoded.decode(),
self.options.remote_name,
str(len(self.get_preamble())),
] ]
def get_econtext_config(self): def get_econtext_config(self):

@ -82,7 +82,7 @@ setup(
license = 'BSD-3-Clause', license = 'BSD-3-Clause',
url = 'https://github.com/mitogen-hq/mitogen/', url = 'https://github.com/mitogen-hq/mitogen/',
packages = find_packages(exclude=['tests', 'examples']), packages = find_packages(exclude=['tests', 'examples']),
python_requires='>=2.4, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*', python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
zip_safe = False, zip_safe = False,
classifiers = [ classifiers = [
'Environment :: Console', 'Environment :: Console',
@ -91,9 +91,6 @@ setup(
'Operating System :: MacOS :: MacOS X', 'Operating System :: MacOS :: MacOS X',
'Operating System :: POSIX', 'Operating System :: POSIX',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2.4',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',

@ -76,7 +76,6 @@ ssh_args =
-o ControlPersist=60s -o ControlPersist=60s
-o ForwardAgent=yes -o ForwardAgent=yes
-o HostKeyAlgorithms=+ssh-rsa -o HostKeyAlgorithms=+ssh-rsa
-o KexAlgorithms=+diffie-hellman-group1-sha1
-o PubkeyAcceptedKeyTypes=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa
-o UserKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null
pipelining = True pipelining = True

@ -6,7 +6,6 @@
ansible_version_major_minor: "{{ ansible_version.major }}.{{ ansible_version.minor }}" ansible_version_major_minor: "{{ ansible_version.major }}.{{ ansible_version.minor }}"
ansible_version_major_minor_patch: "{{ ansible_version.major }}.{{ ansible_version.minor }}.{{ ansible_version.revision | regex_search('^[0-9]+') }}" ansible_version_major_minor_patch: "{{ ansible_version.major }}.{{ ansible_version.minor }}.{{ ansible_version.revision | regex_search('^[0-9]+') }}"
become_doas_available: false
become_unpriv_available: >- become_unpriv_available: >-
{# {#
Vanilla Ansible >= 4 (ansible-core >= 2.11) can use `setfacl` for Vanilla Ansible >= 4 (ansible-core >= 2.11) can use `setfacl` for
@ -35,11 +34,3 @@ become_unpriv_available: >-
-}} -}}
pkg_mgr_python_interpreter: python pkg_mgr_python_interpreter: python
virtualenv_create_argv:
- virtualenv
- -p
- "{{ virtualenv_python }}"
- "{{ virtualenv_path }}"
virtualenv_path: /path/intentionally/left/invalid
virtualenv_python: /path/intentionally/left/invalid

@ -1,8 +0,0 @@
pkg_mgr_python_interpreter: python3
# Alma Linux 9, RHEL 9, etc. lack a virtualenv package
virtualenv_create_argv:
- "{{ virtualenv_python }}"
- -m
- venv
- "{{ virtualenv_path }}"

@ -1,4 +1,3 @@
become_doas_available: true
package_manager_keys: package_manager_keys:
- src: debian-archive-bullseye-automatic.gpg # Debian 11 - src: debian-archive-bullseye-automatic.gpg # Debian 11
dest: /etc/apt/trusted.gpg.d/debian-archive-bullseye-automatic.gpg dest: /etc/apt/trusted.gpg.d/debian-archive-bullseye-automatic.gpg

@ -1,2 +0,0 @@
become_doas_available: true
pkg_mgr_python_interpreter: python3

@ -1,6 +1,4 @@
package_manager_repos: package_manager_repos:
- dest: /etc/apt/sources.list - dest: /etc/apt/sources.list
content: | content: |
deb http://archive.debian.org/debian/ stretch main contrib non-free deb http://archive.debian.org/debian stretch main contrib non-free
deb http://archive.debian.org/debian/ stretch-proposed-updates main contrib non-free
deb http://archive.debian.org/debian-security stretch/updates main contrib non-free

@ -1,2 +0,0 @@
become_doas_available: true
pkg_mgr_python_interpreter: python3

@ -1,2 +0,0 @@
become_doas_available: true
pkg_mgr_python_interpreter: python3

@ -15,16 +15,12 @@
changed_when: false changed_when: false
check_mode: false check_mode: false
register: doas_default_user register: doas_default_user
when:
- become_doas_available
- assert: - assert:
that: that:
- doas_default_user.stdout == 'root' - doas_default_user.stdout == 'root'
fail_msg: fail_msg:
doas_default_user={{ doas_default_user }} doas_default_user={{ doas_default_user }}
when:
- become_doas_available
- name: Test doas -> mitogen__user1 - name: Test doas -> mitogen__user1
become: true become: true
@ -34,7 +30,6 @@
check_mode: false check_mode: false
register: doas_mitogen__user1 register: doas_mitogen__user1
when: when:
- become_doas_available
- become_unpriv_available - become_unpriv_available
- assert: - assert:
@ -43,7 +38,6 @@
fail_msg: fail_msg:
doas_mitogen__user1={{ doas_mitogen__user1 }} doas_mitogen__user1={{ doas_mitogen__user1 }}
when: when:
- become_doas_available
- become_unpriv_available - become_unpriv_available
tags: tags:
- doas - doas
@ -67,16 +61,12 @@
changed_when: false changed_when: false
check_mode: false check_mode: false
register: fq_doas_default_user register: fq_doas_default_user
when:
- become_doas_available
- assert: - assert:
that: that:
- fq_doas_default_user.stdout == 'root' - fq_doas_default_user.stdout == 'root'
fail_msg: fail_msg:
fq_doas_default_user={{ fq_doas_default_user }} fq_doas_default_user={{ fq_doas_default_user }}
when:
- become_doas_available
- name: Test community.general.doas -> mitogen__user1 - name: Test community.general.doas -> mitogen__user1
become: true become: true
@ -86,7 +76,6 @@
check_mode: false check_mode: false
register: fq_doas_mitogen__user1 register: fq_doas_mitogen__user1
when: when:
- become_doas_available
- become_unpriv_available - become_unpriv_available
- assert: - assert:
@ -95,7 +84,6 @@
fail_msg: fail_msg:
fq_doas_mitogen__user1={{ fq_doas_mitogen__user1 }} fq_doas_mitogen__user1={{ fq_doas_mitogen__user1 }}
when: when:
- become_doas_available
- become_unpriv_available - become_unpriv_available
tags: tags:
- doas - doas

@ -47,7 +47,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -76,7 +75,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],

@ -84,7 +84,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -129,7 +128,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -185,7 +183,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -230,7 +227,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -259,7 +255,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -314,7 +309,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],
@ -360,7 +354,6 @@
-o, ControlPersist=60s, -o, ControlPersist=60s,
-o, ForwardAgent=yes, -o, ForwardAgent=yes,
-o, HostKeyAlgorithms=+ssh-rsa, -o, HostKeyAlgorithms=+ssh-rsa,
-o, KexAlgorithms=+diffie-hellman-group1-sha1,
-o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, PubkeyAcceptedKeyTypes=+ssh-rsa,
-o, UserKnownHostsFile=/dev/null, -o, UserKnownHostsFile=/dev/null,
], ],

@ -1,20 +1,58 @@
# ripped and ported from https://github.com/ansible/ansible/pull/50163/files, when interpreter discovery was added to ansible # ripped and ported from https://github.com/ansible/ansible/pull/50163/files, when interpreter discovery was added to ansible
--- ---
- name: integration/interpreter_discovery/ansible_2_8_tests.yml, baseline
hosts: test-targets
strategy: linear
tasks:
- meta: clear_facts
- name: Discover interpreter, linear, auto
vars:
ansible_python_interpreter: auto
ping:
register: linear_auto_result
- name: integration/interpreter_discovery/ansible_2_8_tests.yml - name: integration/interpreter_discovery/ansible_2_8_tests.yml
hosts: test-targets hosts: test-targets
gather_facts: true gather_facts: true
vars:
DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_lt_2_12:
centos:
'6': /usr/bin/python
'7': /usr/bin/python
'8': /usr/libexec/platform-python
debian:
'9': /usr/bin/python
'10': /usr/bin/python3
'11': /usr/bin/python
'NA': /usr/bin/python # Debian 11, Ansible <= 7 (ansible-core <= 2.14)
'bullseye/sid': /usr/bin/python # Debian 11, Ansible 8 - 9 (ansible-core 2.15 - 2.16)
ubuntu:
'16': /usr/bin/python3
'18': /usr/bin/python3
'20': /usr/bin/python3
DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_2_12_to_2_16:
centos:
'6': /usr/bin/python
'7': /usr/bin/python
'8': /usr/libexec/platform-python
debian:
'9': /usr/bin/python
'10': /usr/bin/python3
'11': /usr/bin/python3.9
'NA': /usr/bin/python3.9 # Debian 11, Ansible <= 7 (ansible-core <= 2.14)
'bullseye/sid': /usr/bin/python3.9 # Debian 11, Ansible 8 - 9 (ansible-core 2.15 - 2.16)
ubuntu:
'16': /usr/bin/python3
'18': /usr/bin/python3
'20': /usr/bin/python3
DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_ge_2_17:
debian:
'10': /usr/bin/python3.7
'11': /usr/bin/python3.9
'bullseye/sid': /usr/bin/python3.9
ubuntu:
'20': /usr/bin/python3.8
discovered_interpreter_expected: >-
{%- if ansible_version_major_minor is version('2.12', '<', strict=True) -%}
{{ DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_lt_2_12[distro][distro_major] }}
{%- elif ansible_version_major_minor is version('2.17', '<', strict=True) -%}
{{ DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_2_12_to_2_16[distro][distro_major] }}
{%- else -%}
{{ DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_ge_2_17[distro][distro_major] }}
{%- endif -%}
tasks: tasks:
- name: can only run these tests on ansible >= 2.8.0 - name: can only run these tests on ansible >= 2.8.0
block: block:
@ -27,6 +65,12 @@
fail_msg: "'ansible_python_interpreter' appears to be set at a high precedence to {{ ansible_python_interpreter }}, fail_msg: "'ansible_python_interpreter' appears to be set at a high precedence to {{ ansible_python_interpreter }},
which breaks this test." which breaks this test."
- name: snag some facts to validate for later
set_fact:
distro: '{{ ansible_facts.distribution | lower }}'
distro_major: '{{ ansible_facts.distribution_major_version }}'
system: '{{ ansible_facts.system }}'
- name: test that python discovery is working and that fact persistence makes it only run once - name: test that python discovery is working and that fact persistence makes it only run once
block: block:
- name: clear facts to force interpreter discovery to run - name: clear facts to force interpreter discovery to run
@ -171,10 +215,16 @@
- name: Check discovered interpreter matches expected - name: Check discovered interpreter matches expected
assert: assert:
that: that:
- auto_out.ansible_facts.discovered_interpreter_python == linear_auto_result.ansible_facts.discovered_interpreter_python - auto_out.ansible_facts.discovered_interpreter_python == discovered_interpreter_expected
fail_msg: | fail_msg: |
distro={{ distro }}
distro_major= {{ distro_major }}
system={{ system }}
auto_out={{ auto_out }} auto_out={{ auto_out }}
linear_auto_result={{ linear_auto_result }} discovered_interpreter_expected={{ discovered_interpreter_expected }}
ansible_version.full={{ ansible_version.full }}
when:
- system in ['Linux']
always: always:
- meta: clear_facts - meta: clear_facts

@ -14,7 +14,7 @@
ANSIBLE_CALLBACK_RESULT_FORMAT=json ANSIBLE_CALLBACK_RESULT_FORMAT=json
ANSIBLE_LOAD_CALLBACK_PLUGINS=false ANSIBLE_LOAD_CALLBACK_PLUGINS=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group1-sha1 -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}" ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -c local -a whoami ansible -m shell -c local -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}

@ -35,7 +35,7 @@
ssh_no_password_result.msg is search('SSH password was requested, but none specified') ssh_no_password_result.msg is search('SSH password was requested, but none specified')
or ssh_no_password_result.msg is search('SSH password is incorrect') or ssh_no_password_result.msg is search('SSH password is incorrect')
or ssh_no_password_result.msg is search('Invalid/incorrect password') or ssh_no_password_result.msg is search('Invalid/incorrect password')
or ssh_no_password_result.msg is search('Permission denied \(publickey(,gssapi-keyex)?(,gssapi-with-mic)?,password(,keyboard-interactive)?\)') or ssh_no_password_result.msg is search('Permission denied \(publickey,password(,keyboard-interactive)?\)')
fail_msg: | fail_msg: |
ssh_no_password_result={{ ssh_no_password_result }} ssh_no_password_result={{ ssh_no_password_result }}
@ -72,6 +72,6 @@
- >- - >-
ssh_wrong_password_result.msg is search('SSH password is incorrect') ssh_wrong_password_result.msg is search('SSH password is incorrect')
or ssh_wrong_password_result.msg is search('Invalid/incorrect password') or ssh_wrong_password_result.msg is search('Invalid/incorrect password')
or ssh_no_password_result.msg is search('Permission denied \(publickey(,gssapi-keyex)?(,gssapi-with-mic)?,password(,keyboard-interactive)?\)') or ssh_wrong_password_result.msg is search('Permission denied \(publickey,password(,keyboard-interactive)?\)')
fail_msg: | fail_msg: |
ssh_wrong_password_result={{ ssh_wrong_password_result }} ssh_wrong_password_result={{ ssh_wrong_password_result }}

@ -22,7 +22,7 @@
ANSIBLE_CALLBACK_RESULT_FORMAT=json ANSIBLE_CALLBACK_RESULT_FORMAT=json
ANSIBLE_LOAD_CALLBACK_PLUGINS=false ANSIBLE_LOAD_CALLBACK_PLUGINS=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group1-sha1 -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}" ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
@ -42,7 +42,7 @@
ANSIBLE_CALLBACK_RESULT_FORMAT=json ANSIBLE_CALLBACK_RESULT_FORMAT=json
ANSIBLE_LOAD_CALLBACK_PLUGINS=false ANSIBLE_LOAD_CALLBACK_PLUGINS=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group1-sha1 -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}" ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}

@ -8,12 +8,9 @@
- name: regression/issue_122__environment_difference.yml - name: regression/issue_122__environment_difference.yml
hosts: test-targets hosts: test-targets
tasks: tasks:
- name: Run print_env.py
script: - script: scripts/print_env.py
cmd: scripts/print_env.py register: env
executable: "{{ ansible_python_interpreter | default(ansible_facts.discovered_interpreter_python) }}" - debug: msg={{env}}
register: print_env_result
- debug:
var: print_env_result
tags: tags:
- issue_122 - issue_122

@ -1,29 +1,26 @@
- name: regression/issue_152__virtualenv_python_fails.yml - name: regression/issue_152__virtualenv_python_fails.yml
gather_facts: true gather_facts: true
hosts: test-targets hosts: test-targets
vars:
virtualenv_path: /tmp/issue_152_virtualenv
virtualenv_python: "{{ ansible_facts.python.executable }}"
tasks: tasks:
- custom_python_detect_environment: - custom_python_detect_environment:
register: lout register: lout
# Can't use pip module because it can't create virtualenvs, must call it # Can't use pip module because it can't create virtualenvs, must call it
# directly. # directly.
- name: Create temporary virtualenv - name: Create /tmp/issue_152_virtualenv
environment: environment:
https_proxy: "{{ lookup('env', 'https_proxy')|default('') }}" https_proxy: "{{ lookup('env', 'https_proxy')|default('') }}"
no_proxy: "{{ lookup('env', 'no_proxy')|default('') }}" no_proxy: "{{ lookup('env', 'no_proxy')|default('') }}"
PATH: "{{ lookup('env', 'PATH') }}" PATH: "{{ lookup('env', 'PATH') }}"
command: command:
argv: "{{ virtualenv_create_argv }}" cmd: virtualenv -p "{{ ansible_facts.python.executable }}" /tmp/issue_152_virtualenv
creates: "{{ virtualenv_path }}" creates: /tmp/issue_152_virtualenv
when: when:
- lout.python.version.full is version('2.7', '>=', strict=True) - lout.python.version.full is version('2.7', '>=', strict=True)
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:
ansible_python_interpreter: "{{ virtualenv_path }}/bin/python" ansible_python_interpreter: /tmp/issue_152_virtualenv/bin/python
register: out register: out
when: when:
- lout.python.version.full is version('2.7', '>=', strict=True) - lout.python.version.full is version('2.7', '>=', strict=True)
@ -31,7 +28,7 @@
- name: Check virtualenv was used - name: Check virtualenv was used
# On macOS runners a symlink /tmp -> /private/tmp has been seen # On macOS runners a symlink /tmp -> /private/tmp has been seen
vars: vars:
requested_executable: "{{ virtualenv_path }}/bin/python" requested_executable: /tmp/issue_152_virtualenv/bin/python
expected_executables: expected_executables:
- "{{ requested_executable }}" - "{{ requested_executable }}"
- "{{ requested_executable.replace('/tmp', out.fs['/tmp'].resolved) }}" - "{{ requested_executable.replace('/tmp', out.fs['/tmp'].resolved) }}"
@ -43,9 +40,9 @@
when: when:
- lout.python.version.full is version('2.7', '>=', strict=True) - lout.python.version.full is version('2.7', '>=', strict=True)
- name: Cleanup temporary virtualenv - name: Cleanup /tmp/issue_152_virtualenv
file: file:
path: "{{ virtualenv_path }}" path: /tmp/issue_152_virtualenv
state: absent state: absent
when: when:
- lout.python.version.full is version('2.7', '>=', strict=True) - lout.python.version.full is version('2.7', '>=', strict=True)

@ -12,12 +12,8 @@ class MyError(Exception):
def get_sentinel_value(): def get_sentinel_value():
# Some proof we're even talking to the mitogen-test Docker image # Some proof we're even talking to the mitogen-test Docker image
f = open('/etc/sentinel', 'rb') with open('/etc/sentinel', 'rb') as f:
try: return f.read().decode()
value = f.read().decode()
finally:
f.close()
return value
def add(x, y): def add(x, y):

@ -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 <compressed preamble size> bytes of NUL (`b'\0'`) # 1. Fork child reads PREAMBLE_COMPRESSED_LEN bytes of junk (all `\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>)`

@ -3,30 +3,18 @@
strategy: mitogen_free strategy: mitogen_free
gather_facts: false gather_facts: false
tasks: tasks:
- name: Fetch container images
docker_image:
name: "{{ docker_base }}"
delegate_to: localhost
- name: Start containers - name: Start containers
docker_container: docker_container:
name: "{{ inventory_hostname }}" name: "{{ inventory_hostname }}"
image: "{{ docker_base }}" image: "{{ docker_base }}"
command: /bin/bash command: /bin/bash
hostname: "mitogen-{{ inventory_hostname }}" hostname: "mitogen-{{ inventory_hostname }}"
etc_hosts:
centos-vault-proxy: host-gateway
detach: true detach: true
interactive: true interactive: true
tty: true tty: true
delegate_to: localhost delegate_to: localhost
- name: Wait for containers
# Can't use wait_for_connection yet, not all base images have a python
command: >-
docker inspect
--format "{% raw %}{{.State.Running}}{% endraw %}"
"{{ inventory_hostname }}"
register: container_inspect_result
retries: 5
delay: 10
until:
- container_inspect_result is succeeded
- container_inspect_result.stdout == "true"
changed_when: false
delegate_to: localhost

@ -1,7 +1,7 @@
- name: Prepare images - name: Prepare images
hosts: all hosts: all
strategy: mitogen_free strategy: mitogen_free
gather_facts: false gather_facts: true
tasks: tasks:
- name: Commit containers - name: Commit containers
command: > command: >
@ -10,11 +10,9 @@
--change 'CMD ["/usr/sbin/sshd", "-D"]' --change 'CMD ["/usr/sbin/sshd", "-D"]'
{{ inventory_hostname }} {{ inventory_hostname }}
{{ container_image_name }} {{ container_image_name }}
changed_when: true
delegate_to: localhost delegate_to: localhost
- name: Stop containers - name: Stop containers
command: > command: >
docker rm -f {{ inventory_hostname }} docker rm -f {{ inventory_hostname }}
changed_when: true
delegate_to: localhost delegate_to: localhost

@ -1,5 +0,0 @@
- name: Setup container host
hosts: localhost
become: true
roles:
- role: container_host

@ -2,44 +2,113 @@
hosts: all hosts: all
strategy: linear strategy: linear
gather_facts: false gather_facts: false
roles: tasks:
- role: bootstrap - name: Install bootstrap packages
raw: |
set -o errexit
set -o nounset
if type -p yum; then
yum -y install {{ bootstrap_packages | join(' ') }}
else
apt-get -y update
apt-get -y --no-install-recommends install {{ bootstrap_packages | join(' ') }}
fi
when: bootstrap_packages | length
- name: Setup containers - name: Setup containers
hosts: all hosts: all
strategy: mitogen_free strategy: mitogen_free
# Resource limitation, my laptop freezes doing every container concurrently
serial: 4
# Can't gather facts before here. # Can't gather facts before here.
gather_facts: true gather_facts: true
vars: vars:
distro: "{{ansible_distribution}}" distro: "{{ansible_distribution}}"
pre_tasks:
- meta: end_play
when:
- ansible_facts.virtualization_type != "docker"
roles: roles:
- role: package_manager - role: package_manager
- role: packages
- role: sshd - role: sshd
- role: sshd_container - role: sshd_container
tasks: tasks:
- name: Ensure requisite apt packages are installed
apt:
name: "{{ common_packages + packages }}"
state: present
install_recommends: false
update_cache: true
when: ansible_pkg_mgr == 'apt'
- name: Ensure requisite yum packages are installed
yum:
name: "{{ common_packages + packages }}"
state: present
update_cache: true
when: ansible_pkg_mgr == 'yum'
- name: Ensure requisite dnf packages are installed
dnf:
name: "{{ common_packages + packages }}"
state: present
update_cache: true
when: ansible_pkg_mgr == 'dnf'
- name: Clean up package cache
vars:
clean_command:
apt: apt-get clean
yum: yum clean all
dnf: dnf clean all
command: "{{ clean_command[ansible_pkg_mgr] }}"
args:
warn: "{{ False if ansible_version_major_minor is version('2.10', '<=', strict=True) else omit }}"
- name: Clean up apt package lists
shell: rm -rf {{item}}/*
with_items:
- /var/cache/apt
- /var/lib/apt/lists
when: ansible_pkg_mgr == 'apt'
- name: Configure /usr/bin/python
command: alternatives --set python /usr/bin/python3.8
args:
creates: /usr/bin/python
when: inventory_hostname in ["centos8"]
- name: Enable UTF-8 locale on Debian - name: Enable UTF-8 locale on Debian
copy: copy:
dest: /etc/locale.gen dest: /etc/locale.gen
content: | content: |
en_US.UTF-8 UTF-8 en_US.UTF-8 UTF-8
fr_FR.UTF-8 UTF-8 fr_FR.UTF-8 UTF-8
mode: u=rw,go=r
when: ansible_pkg_mgr == 'apt' when: ansible_pkg_mgr == 'apt'
- name: Generate UTF-8 locale on Debian - name: Generate UTF-8 locale on Debian
command: shell: locale-gen
cmd: locale-gen
changed_when: true
when: ansible_pkg_mgr == 'apt' when: ansible_pkg_mgr == 'apt'
- name: Write Unicode into /etc/environment - name: Write Unicode into /etc/environment
copy: copy:
dest: /etc/environment dest: /etc/environment
content: "UNICODE_SNOWMAN=\u2603\n" content: "UNICODE_SNOWMAN=\u2603\n"
mode: u=rw,go=r
- name: Install prebuilt 'doas' binary
unarchive:
dest: /
src: ../data/docker/doas-debian.tar.gz
- name: Make prebuilt 'doas' binary executable
file:
path: /usr/local/bin/doas
mode: 'u=rwxs,go=rx'
owner: root
group: root
- name: Install doas.conf - name: Install doas.conf
copy: copy:
@ -47,7 +116,6 @@
content: | content: |
permit :mitogen__group permit :mitogen__group
permit :root permit :root
mode: u=rw,go=
- name: Set root user password and shell - name: Set root user password and shell
user: user:
@ -59,7 +127,6 @@
file: file:
path: /var/run/sshd path: /var/run/sshd
state: directory state: directory
mode: u=rwx,go=rx
- name: Generate SSH host key - name: Generate SSH host key
command: ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key command: ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
@ -75,7 +142,6 @@
dest: /etc/sentinel dest: /etc/sentinel
content: | content: |
i-am-mitogen-test-docker-image i-am-mitogen-test-docker-image
mode: u=rw,go=r
- name: Ensure /etc/sudoers.d exists - name: Ensure /etc/sudoers.d exists
file: file:

@ -181,6 +181,6 @@
{% endfor %} {% endfor %}
validate: '/usr/sbin/visudo -cf %s' validate: '/usr/sbin/visudo -cf %s'
when: when:
- ansible_connection == "local" - ansible_virtualization_type != "docker"
roles: roles:
- role: user_policies - role: user_policies

@ -1,17 +1,12 @@
[defaults] [defaults]
any_errors_fatal = true
# Ansible >= 6 (ansible-core >= 2.13)
callback_result_format = yaml
deprecation_warnings = false deprecation_warnings = false
duplicate_dict_key = error
inventory = hosts.ini
strategy_plugins = ../../ansible_mitogen/plugins/strategy strategy_plugins = ../../ansible_mitogen/plugins/strategy
retry_files_enabled = false retry_files_enabled = false
display_args_to_stdout = True
no_target_syslog = True no_target_syslog = True
host_key_checking = False host_key_checking = False
stdout_callback = yaml
[inventory] [inventory]
any_unparsed_is_failed = true unparsed_is_fatal = true
host_pattern_mismatch = error
unparsed_is_failed = true

@ -1,33 +0,0 @@
DefaultRuntimeDir ${XDG_RUNTIME_DIR}
PidFile ${XDG_RUNTIME_DIR}/apache2.pid
LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so
LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so
LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
KeepAlive On
Listen 8090
<Directory />
Require all denied
AllowOverride None
</Directory>
<VirtualHost *:8090>
ServerName centos-vault-proxy
SSLProxyEngine On
CustomLog logs/access.log vhost_combined
ProxyPass "/" "https://vault.centos.org/"
ProxyPassReverse "https://vault.centos.org/" "/"
RedirectMatch "^/(.*)" "http://centos-vault-proxy:8090/$1"
</VirtualHost>
# /usr/sbin/apache2 -d . -f apache_proxy.conf -D FOREGROUND
# vim: syntax=apache

@ -1,18 +1,16 @@
ansible_version_major_minor: "{{ ansible_version.major }}.{{ ansible_version.minor }}" ansible_version_major_minor: "{{ ansible_version.major }}.{{ ansible_version.minor }}"
common_packages: common_packages:
- acl
- openssh-server - openssh-server
- rsync - rsync
- strace - strace
- sudo - sudo
container_image_name: "{{ container_registry }}/{{ inventory_hostname }}-test" container_image_name: "{{ container_registry }}/{{ inventory_hostname }}-test"
container_registry: ghcr.io/mitogen-hq container_registry: public.ecr.aws/n5z0e8q9
sudo_group: sudo_group:
MacOSX: admin MacOSX: admin
Debian: sudo Debian: sudo
Ubuntu: sudo Ubuntu: sudo
CentOS: wheel CentOS: wheel
AlmaLinux: wheel

@ -1,6 +0,0 @@
bootstrap_packages: [python3]
docker_base: almalinux:9
packages:
- perl-JSON
- procps-ng

@ -1,36 +1,6 @@
bootstrap_packages: [python-simplejson] bootstrap_packages: [python-simplejson]
docker_base: centos:5 docker_base: astj/centos5-vault
packages: packages:
- perl - perl
package_manager_repos:
- dest: /etc/yum.repos.d/CentOS-Base.repo
content: |
[base]
name=CentOS-$releasever - Base
baseurl=http://centos-vault-proxy:8090/5.11/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
[updates]
name=CentOS-$releasever - Updates
baseurl=http://centos-vault-proxy:8090/5.11/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
[extras]
name=CentOS-$releasever - Extras
baseurl=http://centos-vault-proxy:8090/5.11/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
- dest: /etc/yum.repos.d/libselinux.repo
content: |
[libselinux]
name=CentOS-$releasever - libselinux
baseurl=http://centos-vault-proxy:8090/5.11/centosplus/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
includepkgs=libselinux*

@ -1,27 +1,6 @@
bootstrap_packages: [python] bootstrap_packages: [python]
docker_base: centos:6 docker_base: moreati/centos6-vault
packages: packages:
- perl-JSON - perl-JSON
package_manager_repos:
- dest: /etc/yum.repos.d/CentOS-Base.repo
content: |
[base]
name=CentOS-$releasever - Base
baseurl=http://vault.centos.org/6.10/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
[updates]
name=CentOS-$releasever - Updates
baseurl=http://vault.centos.org/6.10/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
[extras]
name=CentOS-$releasever - Extras
baseurl=http://vault.centos.org/6.10/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

@ -6,24 +6,3 @@ packages:
- perl-JSON - perl-JSON
- python-virtualenv - python-virtualenv
- python3 - python3
package_manager_repos:
- dest: /etc/yum.repos.d/CentOS-Base.repo
content: |
[base]
name=CentOS-$releasever - Base
baseurl=http://vault.centos.org/$contentdir/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[updates]
name=CentOS-$releasever - Updates
baseurl=http://vault.centos.org/$contentdir/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[extras]
name=CentOS-$releasever - Extras
baseurl=http://vault.centos.org/$contentdir/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

@ -6,29 +6,5 @@ packages:
- perl-JSON - perl-JSON
- python2-virtualenv - python2-virtualenv
- python3-virtualenv - python3-virtualenv
- python36
package_manager_repos: - python38
- dest: /etc/yum.repos.d/CentOS-Linux-AppStream.repo
content: |
[appstream]
name=CentOS Linux $releasever - AppStream
baseurl=http://vault.centos.org/$contentdir/$releasever/AppStream/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
- dest: /etc/yum.repos.d/CentOS-Linux-BaseOS.repo
content: |
[baseos]
name=CentOS Linux $releasever - BaseOS
baseurl=http://vault.centos.org/$contentdir/$releasever/BaseOS/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
- dest: /etc/yum.repos.d/CentOS-Linux-Extras.repo
content: |
[extras]
name=CentOS Linux $releasever - Extras
baseurl=http://vault.centos.org/$contentdir/$releasever/extras/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

@ -1,4 +1,4 @@
bootstrap_packages: [python, python-apt] bootstrap_packages: [python]
docker_base: debian:10 docker_base: debian:10
@ -9,11 +9,3 @@ packages:
- python3 - python3
- python3-virtualenv - python3-virtualenv
- virtualenv - virtualenv
package_manager_repos:
- dest: /etc/apt/sources.list
content: |
deb http://archive.debian.org/debian/ buster main non-free contrib
deb http://archive.debian.org/debian/ buster-updates main non-free contrib
deb http://archive.debian.org/debian/ buster-proposed-updates main non-free contrib
deb http://security.debian.org/ buster/updates main non-free contrib

@ -1,18 +1,11 @@
bootstrap_packages: [python3, python3-apt] bootstrap_packages: [python3, python3-apt]
docker_base: debian:11 docker_base: debian:bullseye
packages: packages:
- doas
- libjson-perl - libjson-perl
- locales - locales
- python-is-python3 - python-is-python3
- python2 - python2
- python3-virtualenv - python3-virtualenv
- virtualenv - virtualenv
package_manager_keys:
- src: debian-archive-bullseye-automatic.gpg # Debian 11
dest: /etc/apt/trusted.gpg.d/
- src: debian-archive-bookworm-automatic.gpg # Debian 12
dest: /etc/apt/trusted.gpg.d/

@ -1,8 +0,0 @@
bootstrap_packages: [python3, python3-apt]
docker_base: debian:12
packages:
- libjson-perl
- locales
- opendoas
- virtualenv

@ -1,4 +1,4 @@
bootstrap_packages: [python, python-apt] bootstrap_packages: [python]
docker_base: debian:9 docker_base: debian:9
@ -9,10 +9,3 @@ packages:
- python3 - python3
- python3-virtualenv - python3-virtualenv
- virtualenv - virtualenv
package_manager_repos:
- dest: /etc/apt/sources.list
content: |
deb http://archive.debian.org/debian/ stretch main contrib non-free
deb http://archive.debian.org/debian/ stretch-proposed-updates main contrib non-free
deb http://archive.debian.org/debian-security stretch/updates main contrib non-free

@ -1,4 +1,4 @@
bootstrap_packages: [python, python-apt] bootstrap_packages: [python]
docker_base: ubuntu:16.04 docker_base: ubuntu:16.04

@ -1,4 +1,4 @@
bootstrap_packages: [python, python-apt] bootstrap_packages: [python]
docker_base: ubuntu:18.04 docker_base: ubuntu:18.04

@ -1,4 +1,4 @@
bootstrap_packages: [python3, python3-apt] bootstrap_packages: [python3]
docker_base: ubuntu:20.04 docker_base: ubuntu:20.04

@ -1,10 +0,0 @@
bootstrap_packages: [python3, python3-apt]
docker_base: ubuntu:22.04
packages:
- doas
- libjson-perl
- locales
- python2
- python3-virtualenv
- virtualenv

@ -1,9 +0,0 @@
bootstrap_packages: [python3, python3-apt]
docker_base: ubuntu:24.04
packages:
- libjson-perl
- locales
- opendoas
- python3-virtualenv
- virtualenv

@ -1,5 +1,4 @@
[all:children] [all:children]
alma
centos centos
debian debian
ubuntu ubuntu
@ -7,9 +6,6 @@ ubuntu
[all:vars] [all:vars]
ansible_connection = docker ansible_connection = docker
[alma]
alma9
[centos] [centos]
centos5 centos5
centos6 centos6
@ -20,37 +16,8 @@ centos8
debian9 debian9
debian10 debian10
debian11 debian11
debian12
[ubuntu] [ubuntu]
ubuntu1604 ubuntu1604
ubuntu1804 ubuntu1804
ubuntu2004 ubuntu2004
ubuntu2204
ubuntu2404
[ansible_2_3]
# Python 2.4 on targets
centos5
[ansible_5]
# Python 2.6 on targets
centos6
[ansible_9]
# Python 2.7 and/or 3.6 on targets
centos7
centos8
debian9
debian10
ubuntu1604
ubuntu1804
[ansible_11]
# Python >= 3.8 on targets
alma9
debian11
debian12
ubuntu2004
ubuntu2204
ubuntu2404

@ -1,2 +0,0 @@
bootstrap_packages: []
package_manager_repos: []

@ -1,3 +0,0 @@
- name: Bootstrap
raw: "{{ lookup('template', 'bootstrap.sh.j2') }}"
changed_when: true

@ -1,21 +0,0 @@
set -o errexit
set -o nounset
{% for item in package_manager_repos %}
cat << "EOF" > "{{ item.dest }}"
{{ item.content }}
EOF
{% endfor %}
{% if bootstrap_packages %}
if command -v apt-get; then
apt-get -y update
apt-get -y --no-install-recommends install {{ bootstrap_packages | join(' ') }}
elif command -v dnf; then
dnf -y install {{ bootstrap_packages | join(' ') }}
elif command -v yum; then
yum -y install {{ bootstrap_packages | join(' ') }}
else
exit 42
fi
{% endif %}

@ -1,6 +0,0 @@
- name: Update GRUB
command: update-grub
changed_when: true
- name: Reboot
reboot:

@ -1,27 +0,0 @@
# > If running `docker run --rm -it centos:centos6.7 bash` immediately exits
# > with status code 139, check to see if your system has disabled vsyscall:
# > ...
# > If you do not see a vsyscall mapping, and you need to run a CentOS 6
# > container, try adding vsyscall=emulated to the kernel options.
# > -- https://hub.docker.com/_/centos
- name: Check vsyscall enabled
command:
cmd: grep -c vsyscall /proc/self/maps
register: grep_self_maps_result
changed_when: false
check_mode: false
failed_when:
# 0 -> match, 1 -> no match, 2 -> error
- grep_self_maps_result.rc not in [0, 1]
- name: Enable vsyscall
lineinfile:
path: /etc/default/grub
regexp: '^GRUB_CMDLINE_LINUX_DEFAULT.+'
line: GRUB_CMDLINE_LINUX_DEFAULT="quiet vsyscall=emulate"
when:
- grep_self_maps_result.rc != 0
notify:
- Update GRUB
- Reboot

@ -1,14 +0,0 @@
common_packages: []
packages: []
packages_clean_command:
apt: apt-get clean
dnf: dnf clean all
yum: yum clean all
packages_cleanup_directories:
apt:
- /var/cache/apt
- /var/lib/apt/lists
dnf: []
yum: []

@ -1,35 +0,0 @@
- name: Ensure requisite apt packages are installed
apt:
name: "{{ common_packages + packages }}"
state: present
install_recommends: false
update_cache: true
when:
- ansible_pkg_mgr == 'apt'
- name: Ensure requisite yum packages are installed
yum:
name: "{{ common_packages + packages }}"
state: present
update_cache: true
when:
- ansible_pkg_mgr == 'yum'
- name: Ensure requisite dnf packages are installed
dnf:
name: "{{ common_packages + packages }}"
state: present
update_cache: true
when:
- ansible_pkg_mgr == 'dnf'
- name: Clean up package cache
command:
cmd: "{{ packages_clean_command[ansible_pkg_mgr] }}"
changed_when: true
- name: Clean up package directories
shell:
rm -rf {{ item }}/*
with_items: "{{ packages_cleanup_directories }}"
changed_when: true

@ -1,4 +1,2 @@
- name: Restart sshd - name: Restart sshd
command: "true" meta: noop
changed_when: false
check_mode: false

@ -1,17 +1,6 @@
#!/usr/bin/env ansible-playbook #!/usr/bin/env ansible-playbook
- name: Get base images - include_playbook: _container_create.yml
hosts: all - include_playbook: _container_setup.yml
# strategy: mitogen_free - include_playbook: _user_accounts.yml
gather_facts: false - include_playbook: _container_finalize.yml
tasks:
- name: Fetch container base images
docker_image:
name: "{{ docker_base }}"
source: pull # Added in Ansible 2.8, required circa 2.12
delegate_to: localhost
- import_playbook: _container_create.yml
- import_playbook: _container_setup.yml
- import_playbook: _user_accounts.yml
- import_playbook: _container_finalize.yml

@ -1,15 +0,0 @@
#!/usr/bin/env ansible-playbook
- name: Get base images
hosts: all
gather_facts: false
tasks:
- name: Fetch container base images
docker_image:
name: "{{ docker_base }}"
delegate_to: localhost
- include: _container_create.yml
- include: _container_setup.yml
- include: _user_accounts.yml
- include: _container_finalize.yml

@ -1,9 +1,7 @@
[tox] [tox]
envlist = envlist =
ansible2.3, ansible2.3,
ansible5 ansible2.10,
ansible9
ansible11
skipsdist = true skipsdist = true
[testenv] [testenv]
@ -15,47 +13,17 @@ basepython = python2
deps = deps =
ansible>=2.3,<2.4 ansible>=2.3,<2.4
docker-py>=1.7.0 docker-py>=1.7.0
mitogen~=0.2.0 mitogen>=0.2.10rc1,<0.3
install_command = install_command =
python -m pip --no-python-version-warning install {opts} {packages} python -m pip --no-python-version-warning install {opts} {packages}
commands = commands =
ansible-playbook -l 'localhost,ansible_2_3' setup_ansible2.3.yml ./setup.yml -i hosts.ini -l 'localhost,centos5' {posargs}
[testenv:ansible5] [testenv:ansible2.10]
basepython = python3 basepython = python3
deps = deps =
ansible~=5.0 ansible>=2.10,<2.11
docker>=1.8.0 docker>=1.8.0
mitogen~=0.3.0 mitogen>=0.3.0rc1,<0.4
passlib
setenv =
ANSIBLE_PYTHON_INTERPRETER=auto_silent
ANSIBLE_STDOUT_CALLBACK=yaml
commands =
ansible-playbook -l 'localhost,ansible_5' setup.yml
[testenv:ansible9]
basepython = python3
deps =
ansible~=9.0
docker>=1.8.0
mitogen~=0.3.0
passlib
setenv =
ANSIBLE_PYTHON_INTERPRETER=auto_silent
ANSIBLE_STDOUT_CALLBACK=yaml
commands =
ansible-playbook -l 'localhost,ansible_9' setup.yml
[testenv:ansible11]
basepython = python3
deps =
ansible~=11.0
docker>=1.8.0
mitogen~=0.3.0
passlib
setenv =
ANSIBLE_PYTHON_INTERPRETER=auto_silent
ANSIBLE_STDOUT_CALLBACK=yaml
commands = commands =
ansible-playbook -l 'localhost,ansible_11' setup.yml ./setup.yml -i hosts.ini -l '!centos5' {posargs}

@ -198,3 +198,21 @@ class ForwardTest(testlib.RouterMixin, testlib.TestCase):
self.assertEqual(2+os_fork, self.router.responder.good_load_module_count) self.assertEqual(2+os_fork, self.router.responder.good_load_module_count)
self.assertLess(10000, self.router.responder.good_load_module_size) self.assertLess(10000, self.router.responder.good_load_module_size)
self.assertGreater(40000, self.router.responder.good_load_module_size) self.assertGreater(40000, self.router.responder.good_load_module_size)
class BlacklistTest(testlib.TestCase):
@unittest.skip('implement me')
def test_whitelist_no_blacklist(self):
assert 0
@unittest.skip('implement me')
def test_whitelist_has_blacklist(self):
assert 0
@unittest.skip('implement me')
def test_blacklist_no_whitelist(self):
assert 0
@unittest.skip('implement me')
def test_blacklist_has_whitelist(self):
assert 0

@ -53,11 +53,11 @@ LOG = logging.getLogger(__name__)
DISTRO_SPECS = os.environ.get( DISTRO_SPECS = os.environ.get(
'MITOGEN_TEST_DISTRO_SPECS', 'MITOGEN_TEST_DISTRO_SPECS',
'alma9-py3 centos5 centos8-py3 debian9 debian12-py3 ubuntu1604 ubuntu2404-py3', 'centos6 centos8 debian9 debian11 ubuntu1604 ubuntu2004',
) )
IMAGE_TEMPLATE = os.environ.get( IMAGE_TEMPLATE = os.environ.get(
'MITOGEN_TEST_IMAGE_TEMPLATE', 'MITOGEN_TEST_IMAGE_TEMPLATE',
'ghcr.io/mitogen-hq/%(distro)s-test:2025.02', 'ghcr.io/mitogen-hq/%(distro)s-test:2021',
) )
TESTS_DIR = os.path.join(os.path.dirname(__file__)) TESTS_DIR = os.path.join(os.path.dirname(__file__))
@ -725,7 +725,6 @@ class DockerMixin(RouterMixin):
# - tests/testlib.py # - tests/testlib.py
'ssh_args': [ 'ssh_args': [
'-o', 'HostKeyAlgorithms +ssh-rsa', '-o', 'HostKeyAlgorithms +ssh-rsa',
'-o', 'KexAlgorithms +diffie-hellman-group1-sha1',
'-o', 'PubkeyAcceptedKeyTypes +ssh-rsa', '-o', 'PubkeyAcceptedKeyTypes +ssh-rsa',
], ],
'python_path': self.dockerized_ssh.python_path, 'python_path': self.dockerized_ssh.python_path,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save