Skip to content

Commit c39c475

Browse files
authored
Merge pull request #1215 from Nihlus/fix-connection-loader
ansible_mitogen: Fix usage of connection_loader__get.
2 parents 69a6173 + 211079f commit c39c475

File tree

8 files changed

+129
-36
lines changed

8 files changed

+129
-36
lines changed

ansible_mitogen/loaders.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,5 @@ def assert_supported_release():
9999
from ansible.plugins.loader import strategy_loader
100100

101101
# These are original, unwrapped implementations
102-
action_loader__get = action_loader.get
103-
connection_loader__get = connection_loader.get_with_context
102+
action_loader__get_with_context = action_loader.get_with_context
103+
connection_loader__get_with_context = connection_loader.get_with_context

ansible_mitogen/plugins/connection/mitogen_kubectl.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,25 @@
4646
import ansible_mitogen.loaders
4747

4848

49-
_get_result = ansible_mitogen.loaders.connection_loader__get(
50-
'kubectl',
51-
class_only=True,
52-
)
53-
54-
5549
class Connection(ansible_mitogen.connection.Connection):
5650
transport = 'kubectl'
51+
(vanilla_class, load_context) = ansible_mitogen.loaders.connection_loader__get_with_context(
52+
'kubectl',
53+
class_only=True,
54+
)
5755

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

6361
def __init__(self, *args, **kwargs):
64-
if not _get_result:
62+
if not Connection.vanilla_class:
6563
raise ansible.errors.AnsibleConnectionFailure(self.not_supported_msg)
6664
super(Connection, self).__init__(*args, **kwargs)
6765

6866
def get_extra_args(self):
69-
try:
70-
# Ansible < 2.10, _get_result is the connection class
71-
connection_options = _get_result.connection_options
72-
except AttributeError:
73-
# Ansible >= 2.10, _get_result is a get_with_context_result
74-
connection_options = _get_result.object.connection_options
67+
connection_options = Connection.vanilla_class.connection_options
7568
parameters = []
7669
for key in connection_options:
7770
task_var_name = 'ansible_%s' % key

ansible_mitogen/plugins/connection/mitogen_ssh.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060

6161
class Connection(ansible_mitogen.connection.Connection):
6262
transport = 'ssh'
63-
vanilla_class = ansible_mitogen.loaders.connection_loader__get(
63+
(vanilla_class, load_context) = ansible_mitogen.loaders.connection_loader__get_with_context(
6464
'ssh',
6565
class_only=True,
6666
)

ansible_mitogen/strategy.py

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import ansible.executor.process.worker
4848
import ansible.template
4949
import ansible.utils.sentinel
50+
import ansible.playbook.play_context
51+
import ansible.plugins.loader
5052

5153

5254
def _patch_awx_callback():
@@ -76,12 +78,12 @@ def patch_add_local(self, **kwargs):
7678
_patch_awx_callback()
7779

7880

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

94-
klass = ansible_mitogen.loaders.action_loader__get(name, **get_kwargs)
96+
(klass, context) = ansible_mitogen.loaders.action_loader__get_with_context(
97+
name,
98+
**get_kwargs
99+
)
100+
95101
if klass:
96102
bases = (ansible_mitogen.mixins.ActionModuleMixin, klass)
97103
adorned_klass = type(str(name), bases, {})
98104
if kwargs.get('class_only'):
99-
return adorned_klass
100-
return adorned_klass(*args, **kwargs)
105+
return ansible.plugins.loader.get_with_context_result(
106+
adorned_klass,
107+
context
108+
)
109+
110+
return ansible.plugins.loader.get_with_context_result(
111+
adorned_klass(*args, **kwargs),
112+
context
113+
)
114+
115+
return ansible.plugins.loader.get_with_context_result(None, context)
101116

102117

103118
REDIRECTED_CONNECTION_PLUGINS = (
@@ -115,15 +130,26 @@ def wrap_action_loader__get(name, *args, **kwargs):
115130
)
116131

117132

118-
def wrap_connection_loader__get(name, *args, **kwargs):
133+
def wrap_connection_loader__get_with_context(name, *args, **kwargs):
119134
"""
120-
While a Mitogen strategy is active, rewrite connection_loader.get() calls
121-
for some transports into requests for a compatible Mitogen transport.
135+
While a Mitogen strategy is active, rewrite
136+
connection_loader.get_with_context() calls for some transports into
137+
requests for a compatible Mitogen transport.
122138
"""
123-
if name in REDIRECTED_CONNECTION_PLUGINS:
139+
is_play_using_mitogen_connection = None
140+
if len(args) > 0 and isinstance(args[0], ansible.playbook.play_context.PlayContext):
141+
play_context = args[0]
142+
is_play_using_mitogen_connection = play_context.connection in REDIRECTED_CONNECTION_PLUGINS
143+
144+
# assume true if we're not in a play context since we're using a Mitogen strategy
145+
if is_play_using_mitogen_connection is None:
146+
is_play_using_mitogen_connection = True
147+
148+
redirect_connection = name in REDIRECTED_CONNECTION_PLUGINS and is_play_using_mitogen_connection
149+
if redirect_connection:
124150
name = 'mitogen_' + name
125151

126-
return ansible_mitogen.loaders.connection_loader__get(name, *args, **kwargs)
152+
return ansible_mitogen.loaders.connection_loader__get_with_context(name, *args, **kwargs)
127153

128154

129155
def wrap_worker__run(self):
@@ -173,8 +199,8 @@ def _install_wrappers(self):
173199
Install our PluginLoader monkey patches and update global variables
174200
with references to the real functions.
175201
"""
176-
ansible_mitogen.loaders.action_loader.get = wrap_action_loader__get
177-
ansible_mitogen.loaders.connection_loader.get_with_context = wrap_connection_loader__get
202+
ansible_mitogen.loaders.action_loader.get_with_context = wrap_action_loader__get_with_context
203+
ansible_mitogen.loaders.connection_loader.get_with_context = wrap_connection_loader__get_with_context
178204

179205
global worker__run
180206
worker__run = ansible.executor.process.worker.WorkerProcess.run
@@ -184,11 +210,11 @@ def _remove_wrappers(self):
184210
"""
185211
Uninstall the PluginLoader monkey patches.
186212
"""
187-
ansible_mitogen.loaders.action_loader.get = (
188-
ansible_mitogen.loaders.action_loader__get
213+
ansible_mitogen.loaders.action_loader.get_with_context = (
214+
ansible_mitogen.loaders.action_loader__get_with_context
189215
)
190216
ansible_mitogen.loaders.connection_loader.get_with_context = (
191-
ansible_mitogen.loaders.connection_loader__get
217+
ansible_mitogen.loaders.connection_loader__get_with_context
192218
)
193219
ansible.executor.process.worker.WorkerProcess.run = worker__run
194220

tests/ansible/regression/all.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- import_playbook: issue_591__setuptools_cwd_crash.yml
1414
- import_playbook: issue_615__streaming_transfer.yml
1515
- import_playbook: issue_655__wait_for_connection_error.yml
16+
- import_playbook: issue_766__get_with_context.yml
1617
- import_playbook: issue_776__load_plugins_called_twice.yml
1718
- import_playbook: issue_952__ask_become_pass.yml
1819
- import_playbook: issue_1066__add_host__host_key_checking.yml

tests/ansible/regression/issue_655__wait_for_connection_error.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
tasks:
1212
- meta: end_play
1313
when:
14-
# Podman versions available in Homebrew have dropped macOS 12 support.
14+
# Podman versions available in Homebrew require macOS 13+ (Ventura).
15+
# https://formulae.brew.sh/formula/podman
16+
# See also
17+
# - issue_766__get_with_context.yml
1518
- ansible_facts.system == 'Darwin'
1619
- ansible_facts.distribution_version is version('13.0', '<', strict=True)
1720

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# https://github.com/mitogen-hq/mitogen/issues/776
2+
---
3+
- name: regression/issue_766__get_with_context.yml
4+
hosts: localhost
5+
# Gather facts to use *and* to trigger any "could not recover task_vars" error
6+
# https://github.com/mitogen-hq/mitogen/pull/1215#issuecomment-2596421111
7+
gather_facts: true
8+
vars:
9+
netconf_container_image: ghcr.io/mitogen-hq/sysrepo-netopeer2:latest
10+
netconf_container_name: sysprep
11+
netconf_container_port: 8030
12+
13+
tasks:
14+
- meta: end_play
15+
when:
16+
# Podman can be installed on macOS, but authenticating to gchr.io isn't
17+
# worth the trouble right now.
18+
# See also
19+
# - issue_655__wait_for_connection_error.yml
20+
- ansible_facts.system == 'Darwin'
21+
22+
- meta: end_play
23+
when:
24+
# A failure during the ansible.netcommon.netconf_get task, when run
25+
# with Ansible 4 (ansible-core 2.11) & associated collections.
26+
# ansible.module_utils.connection.ConnectionError: Method not found
27+
# https://github.com/mitogen-hq/mitogen/actions/runs/12854359099/job/35838635886
28+
- ansible_version.full is version('2.11', '>=', strict=True)
29+
- ansible_version.full is version('2.12', '<', strict=True)
30+
31+
- block:
32+
- name: Start container
33+
command:
34+
cmd: >-
35+
podman run
36+
--name "{{ netconf_container_name }}"
37+
--detach
38+
--rm
39+
--publish "{{ netconf_container_port }}:830"
40+
"{{ netconf_container_image }}"
41+
changed_when: true
42+
43+
- name: Wait for container
44+
# TODO robust condition. wait_for + search_regex? wait_for_connection?
45+
wait_for:
46+
timeout: 5
47+
48+
- name: Get running configuration and state data
49+
vars:
50+
ansible_connection: netconf
51+
ansible_user: netconf
52+
ansible_password: netconf
53+
ansible_port: "{{ netconf_container_port }}"
54+
ansible_host_key_checking: false
55+
ansible_python_interpreter: "{{ ansible_playbook_python }}"
56+
ansible.netcommon.netconf_get:
57+
58+
always:
59+
- name: Cleanup container
60+
command:
61+
cmd: podman stop "{{ netconf_container_name }}"
62+
changed_when: true
63+
tags:
64+
- issue_766

tests/ansible/requirements.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
paramiko==2.3.2 # Last 2.6-compat version.
1+
paramiko==2.12.0; python_version <= '2.7'
2+
paramiko==3.5.0; python_version >= '3.6'
3+
24
# Incompatible with pip >= 72, due to removal of `setup.py test`:
35
# ModuleNotFoundError: No module named 'setuptools.command.test'
46
# https://github.com/pypa/setuptools/issues/4519
57
hdrhistogram==0.6.1
8+
9+
ncclient==0.6.13; python_version <= '2.7'
10+
ncclient==0.6.16; python_version > '2.7'
11+
612
PyYAML==3.11; python_version < '2.7'
713
PyYAML==5.3.1; python_version >= '2.7' # Latest release (Jan 2021)

0 commit comments

Comments
 (0)