Skip to content

Commit

Permalink
Merge pull request #1224 from moreati/release-v0.3.22
Browse files Browse the repository at this point in the history
Release v0.3.21
  • Loading branch information
moreati authored Jan 20, 2025
2 parents 161a231 + 0ebbb06 commit b8c876d
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 38 deletions.
4 changes: 2 additions & 2 deletions ansible_mitogen/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,5 @@ def assert_supported_release():
from ansible.plugins.loader import strategy_loader

# These are original, unwrapped implementations
action_loader__get = action_loader.get
connection_loader__get = connection_loader.get_with_context
action_loader__get_with_context = action_loader.get_with_context
connection_loader__get_with_context = connection_loader.get_with_context
41 changes: 41 additions & 0 deletions ansible_mitogen/planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,47 @@ def get_module_deps(self):
'firewalld', # issue #570: ansible module_utils caches dbus conn
'ansible.legacy.dnf', # issue #776
'ansible.builtin.dnf', # issue #832
'freeipa.ansible_freeipa.ipaautomember', # issue #1216
'freeipa.ansible_freeipa.ipaautomountkey',
'freeipa.ansible_freeipa.ipaautomountlocation',
'freeipa.ansible_freeipa.ipaautomountmap',
'freeipa.ansible_freeipa.ipacert',
'freeipa.ansible_freeipa.ipaconfig',
'freeipa.ansible_freeipa.ipadelegation',
'freeipa.ansible_freeipa.ipadnsconfig',
'freeipa.ansible_freeipa.ipadnsforwardzone',
'freeipa.ansible_freeipa.ipadnsrecord',
'freeipa.ansible_freeipa.ipadnszone',
'freeipa.ansible_freeipa.ipagroup',
'freeipa.ansible_freeipa.ipahbacrule',
'freeipa.ansible_freeipa.ipahbacsvc',
'freeipa.ansible_freeipa.ipahbacsvcgroup',
'freeipa.ansible_freeipa.ipahost',
'freeipa.ansible_freeipa.ipahostgroup',
'freeipa.ansible_freeipa.idoverridegroup',
'freeipa.ansible_freeipa.idoverrideuser',
'freeipa.ansible_freeipa.idp',
'freeipa.ansible_freeipa.idrange',
'freeipa.ansible_freeipa.idview',
'freeipa.ansible_freeipa.ipalocation',
'freeipa.ansible_freeipa.ipanetgroup',
'freeipa.ansible_freeipa.ipapermission',
'freeipa.ansible_freeipa.ipaprivilege',
'freeipa.ansible_freeipa.ipapwpolicy',
'freeipa.ansible_freeipa.iparole',
'freeipa.ansible_freeipa.ipaselfservice',
'freeipa.ansible_freeipa.ipaserver',
'freeipa.ansible_freeipa.ipaservice',
'freeipa.ansible_freeipa.ipaservicedelegationrule',
'freeipa.ansible_freeipa.ipaservicedelegationtarget',
'freeipa.ansible_freeipa.ipasudocmd',
'freeipa.ansible_freeipa.ipasudocmdgroup',
'freeipa.ansible_freeipa.ipasudorule',
'freeipa.ansible_freeipa.ipatopologysegment',
'freeipa.ansible_freeipa.ipatopologysuffix',
'freeipa.ansible_freeipa.ipatrust',
'freeipa.ansible_freeipa.ipauser',
'freeipa.ansible_freeipa.ipavault',
])

def should_fork(self):
Expand Down
19 changes: 6 additions & 13 deletions ansible_mitogen/plugins/connection/mitogen_kubectl.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,25 @@
import ansible_mitogen.loaders


_get_result = ansible_mitogen.loaders.connection_loader__get(
'kubectl',
class_only=True,
)


class Connection(ansible_mitogen.connection.Connection):
transport = 'kubectl'
(vanilla_class, load_context) = ansible_mitogen.loaders.connection_loader__get_with_context(
'kubectl',
class_only=True,
)

not_supported_msg = (
'The "mitogen_kubectl" plug-in requires a version of Ansible '
'that ships with the "kubectl" connection plug-in.'
)

def __init__(self, *args, **kwargs):
if not _get_result:
if not Connection.vanilla_class:
raise ansible.errors.AnsibleConnectionFailure(self.not_supported_msg)
super(Connection, self).__init__(*args, **kwargs)

def get_extra_args(self):
try:
# Ansible < 2.10, _get_result is the connection class
connection_options = _get_result.connection_options
except AttributeError:
# Ansible >= 2.10, _get_result is a get_with_context_result
connection_options = _get_result.object.connection_options
connection_options = Connection.vanilla_class.connection_options
parameters = []
for key in connection_options:
task_var_name = 'ansible_%s' % key
Expand Down
2 changes: 1 addition & 1 deletion ansible_mitogen/plugins/connection/mitogen_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

class Connection(ansible_mitogen.connection.Connection):
transport = 'ssh'
vanilla_class = ansible_mitogen.loaders.connection_loader__get(
(vanilla_class, load_context) = ansible_mitogen.loaders.connection_loader__get_with_context(
'ssh',
class_only=True,
)
Expand Down
62 changes: 44 additions & 18 deletions ansible_mitogen/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
import ansible.executor.process.worker
import ansible.template
import ansible.utils.sentinel
import ansible.playbook.play_context
import ansible.plugins.loader


def _patch_awx_callback():
Expand Down Expand Up @@ -76,12 +78,12 @@ def patch_add_local(self, **kwargs):
_patch_awx_callback()


def wrap_action_loader__get(name, *args, **kwargs):
def wrap_action_loader__get_with_context(name, *args, **kwargs):
"""
While the mitogen strategy is active, trap action_loader.get() calls,
augmenting any fetched class with ActionModuleMixin, which replaces various
helper methods inherited from ActionBase with implementations that avoid
the use of shell fragments wherever possible.
While the mitogen strategy is active, trap action_loader.get_with_context()
calls, augmenting any fetched class with ActionModuleMixin, which replaces
various helper methods inherited from ActionBase with implementations that
avoid the use of shell fragments wherever possible.
This is used instead of static subclassing as it generalizes to third party
action plugins outside the Ansible tree.
Expand All @@ -91,13 +93,26 @@ def wrap_action_loader__get(name, *args, **kwargs):
name = 'mitogen_' + name
get_kwargs['collection_list'] = kwargs.pop('collection_list', None)

klass = ansible_mitogen.loaders.action_loader__get(name, **get_kwargs)
(klass, context) = ansible_mitogen.loaders.action_loader__get_with_context(
name,
**get_kwargs
)

if klass:
bases = (ansible_mitogen.mixins.ActionModuleMixin, klass)
adorned_klass = type(str(name), bases, {})
if kwargs.get('class_only'):
return adorned_klass
return adorned_klass(*args, **kwargs)
return ansible.plugins.loader.get_with_context_result(
adorned_klass,
context
)

return ansible.plugins.loader.get_with_context_result(
adorned_klass(*args, **kwargs),
context
)

return ansible.plugins.loader.get_with_context_result(None, context)


REDIRECTED_CONNECTION_PLUGINS = (
Expand All @@ -115,15 +130,26 @@ def wrap_action_loader__get(name, *args, **kwargs):
)


def wrap_connection_loader__get(name, *args, **kwargs):
def wrap_connection_loader__get_with_context(name, *args, **kwargs):
"""
While a Mitogen strategy is active, rewrite connection_loader.get() calls
for some transports into requests for a compatible Mitogen transport.
While a Mitogen strategy is active, rewrite
connection_loader.get_with_context() calls for some transports into
requests for a compatible Mitogen transport.
"""
if name in REDIRECTED_CONNECTION_PLUGINS:
is_play_using_mitogen_connection = None
if len(args) > 0 and isinstance(args[0], ansible.playbook.play_context.PlayContext):
play_context = args[0]
is_play_using_mitogen_connection = play_context.connection in REDIRECTED_CONNECTION_PLUGINS

# assume true if we're not in a play context since we're using a Mitogen strategy
if is_play_using_mitogen_connection is None:
is_play_using_mitogen_connection = True

redirect_connection = name in REDIRECTED_CONNECTION_PLUGINS and is_play_using_mitogen_connection
if redirect_connection:
name = 'mitogen_' + name

return ansible_mitogen.loaders.connection_loader__get(name, *args, **kwargs)
return ansible_mitogen.loaders.connection_loader__get_with_context(name, *args, **kwargs)


def wrap_worker__run(self):
Expand Down Expand Up @@ -173,8 +199,8 @@ def _install_wrappers(self):
Install our PluginLoader monkey patches and update global variables
with references to the real functions.
"""
ansible_mitogen.loaders.action_loader.get = wrap_action_loader__get
ansible_mitogen.loaders.connection_loader.get_with_context = wrap_connection_loader__get
ansible_mitogen.loaders.action_loader.get_with_context = wrap_action_loader__get_with_context
ansible_mitogen.loaders.connection_loader.get_with_context = wrap_connection_loader__get_with_context

global worker__run
worker__run = ansible.executor.process.worker.WorkerProcess.run
Expand All @@ -184,11 +210,11 @@ def _remove_wrappers(self):
"""
Uninstall the PluginLoader monkey patches.
"""
ansible_mitogen.loaders.action_loader.get = (
ansible_mitogen.loaders.action_loader__get
ansible_mitogen.loaders.action_loader.get_with_context = (
ansible_mitogen.loaders.action_loader__get_with_context
)
ansible_mitogen.loaders.connection_loader.get_with_context = (
ansible_mitogen.loaders.connection_loader__get
ansible_mitogen.loaders.connection_loader__get_with_context
)
ansible.executor.process.worker.WorkerProcess.run = worker__run

Expand Down
11 changes: 11 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ To avail of fixes in an unreleased version, please download a ZIP file
`directly from GitHub <https://github.com/mitogen-hq/mitogen/>`_.


v0.3.21 (2025-01-20)
--------------------

* :gh:issue:`1209` docs: Fix Netlify build of website
* :gh:issue:`1216` :mod:`ansible_mitogen`: Add all ansible_freeipa modules to
the always-fork list.
* :gh:issue:`766` :mod:`ansible_mitogen`: Fix ""could not recover task_vars"
and "get_with_context_result object has no attribute _create_control_path"
when using ``kubectl``, ``netconf``, or ``network_cli`` connection plugins.


v0.3.20 (2025-01-07)
--------------------

Expand Down
15 changes: 14 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import re
import sys

sys.path.append('.')

VERSION = '0.3.9'

def changelog_version(path, encoding='utf-8'):
version_pattern = re.compile(
r'^v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)',
re.MULTILINE,
)

with open(path, encoding=encoding) as f:
match = version_pattern.search(f.read())
return match.group('version')


VERSION = changelog_version('changelog.rst')

author = u'Network Genomics'
copyright = u'2021, the Mitogen authors'
Expand Down
2 changes: 2 additions & 0 deletions docs/contributors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ sponsorship and outstanding future-thinking of its early adopters.
<li><a href="https://www.epartment.nl/">Epartment</a></li>
<li><a href="http://andrianaivo.org/">Fidy Andrianaivo</a> &mdash; <em>never let a human do an ansible job ;)</em></li>
<li><a href="https://www.channable.com">rkrzr</a></li>
<li><a href="https://github.com/Nihlus">Jarl Gullberg</a></li>
<li>jgadling</li>
<li>John F Wall &mdash; <em>Making Ansible Great with Massive Parallelism</em></li>
<li><a href="https://github.com/jrosser">Jonathan Rosser</a></li>
Expand All @@ -132,6 +133,7 @@ sponsorship and outstanding future-thinking of its early adopters.
<li><a href="https://github.com/lberruti">Luca Berruti</li>
<li>Lewis Bellwood &mdash; <em>Happy to be apart of a great project.</em></li>
<li>luto</li>
<li><a href="https://github.com/markafarrell">@markafarrell</a></li>
<li><a href="https://mayeu.me/">Mayeu a.k.a Matthieu Maury</a></li>
<li><a href="https://github.com/madsi1m">Michael D'Silva</a></li>
<li><a href="https://github.com/mordekasg">mordek</a></li>
Expand Down
2 changes: 2 additions & 0 deletions docs/netlify.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build.environment]
PYTHON_VERSION = "3.8"
2 changes: 1 addition & 1 deletion mitogen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@


#: Library version as a tuple.
__version__ = (0, 3, 20)
__version__ = (0, 3, 21)


#: This is :data:`False` in slave contexts. Previously it was used to prevent
Expand Down
2 changes: 2 additions & 0 deletions netlify.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build.environment]
PYTHON_VERSION = "3.8"
1 change: 1 addition & 0 deletions tests/ansible/regression/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- import_playbook: issue_591__setuptools_cwd_crash.yml
- import_playbook: issue_615__streaming_transfer.yml
- import_playbook: issue_655__wait_for_connection_error.yml
- import_playbook: issue_766__get_with_context.yml
- import_playbook: issue_776__load_plugins_called_twice.yml
- import_playbook: issue_952__ask_become_pass.yml
- import_playbook: issue_1066__add_host__host_key_checking.yml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
tasks:
- meta: end_play
when:
# Podman versions available in Homebrew have dropped macOS 12 support.
# Podman versions available in Homebrew require macOS 13+ (Ventura).
# https://formulae.brew.sh/formula/podman
# See also
# - issue_766__get_with_context.yml
- ansible_facts.system == 'Darwin'
- ansible_facts.distribution_version is version('13.0', '<', strict=True)

Expand Down
64 changes: 64 additions & 0 deletions tests/ansible/regression/issue_766__get_with_context.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# https://github.com/mitogen-hq/mitogen/issues/776
---
- name: regression/issue_766__get_with_context.yml
hosts: localhost
# Gather facts to use *and* to trigger any "could not recover task_vars" error
# https://github.com/mitogen-hq/mitogen/pull/1215#issuecomment-2596421111
gather_facts: true
vars:
netconf_container_image: ghcr.io/mitogen-hq/sysrepo-netopeer2:latest
netconf_container_name: sysprep
netconf_container_port: 8030

tasks:
- meta: end_play
when:
# Podman can be installed on macOS, but authenticating to gchr.io isn't
# worth the trouble right now.
# See also
# - issue_655__wait_for_connection_error.yml
- ansible_facts.system == 'Darwin'

- meta: end_play
when:
# A failure during the ansible.netcommon.netconf_get task, when run
# with Ansible 4 (ansible-core 2.11) & associated collections.
# ansible.module_utils.connection.ConnectionError: Method not found
# https://github.com/mitogen-hq/mitogen/actions/runs/12854359099/job/35838635886
- ansible_version.full is version('2.11', '>=', strict=True)
- ansible_version.full is version('2.12', '<', strict=True)

- block:
- name: Start container
command:
cmd: >-
podman run
--name "{{ netconf_container_name }}"
--detach
--rm
--publish "{{ netconf_container_port }}:830"
"{{ netconf_container_image }}"
changed_when: true

- name: Wait for container
# TODO robust condition. wait_for + search_regex? wait_for_connection?
wait_for:
timeout: 5

- name: Get running configuration and state data
vars:
ansible_connection: netconf
ansible_user: netconf
ansible_password: netconf
ansible_port: "{{ netconf_container_port }}"
ansible_host_key_checking: false
ansible_python_interpreter: "{{ ansible_playbook_python }}"
ansible.netcommon.netconf_get:

always:
- name: Cleanup container
command:
cmd: podman stop "{{ netconf_container_name }}"
changed_when: true
tags:
- issue_766
8 changes: 7 additions & 1 deletion tests/ansible/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
paramiko==2.3.2 # Last 2.6-compat version.
paramiko==2.12.0; python_version <= '2.7'
paramiko==3.5.0; python_version >= '3.6'

# Incompatible with pip >= 72, due to removal of `setup.py test`:
# ModuleNotFoundError: No module named 'setuptools.command.test'
# https://github.com/pypa/setuptools/issues/4519
hdrhistogram==0.6.1

ncclient==0.6.13; python_version <= '2.7'
ncclient==0.6.16; python_version > '2.7'

PyYAML==3.11; python_version < '2.7'
PyYAML==5.3.1; python_version >= '2.7' # Latest release (Jan 2021)

0 comments on commit b8c876d

Please sign in to comment.