Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
moreati committed Oct 4, 2024
1 parent 8862936 commit 5594afd
Show file tree
Hide file tree
Showing 24 changed files with 643 additions and 137 deletions.
34 changes: 26 additions & 8 deletions ansible_mitogen/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def _connect_local(spec):

def _connect_ssh(spec):
"""
Return ContextService arguments for an SSH connection.
Return :class:`ansible_mitogen.services.ContextService` arguments for an
SSH connection.
"""
if spec.host_key_checking():
check_host_keys = 'enforce'
Expand All @@ -130,6 +131,10 @@ def _connect_ssh(spec):
if private_key_file is not None:
private_key_file = os.path.expanduser(private_key_file)

#password = spec.password()
#if not password:
# raise ValueError('Expected truthy password, got: %r', password)

return {
'method': 'ssh',
'kwargs': {
Expand Down Expand Up @@ -158,6 +163,7 @@ def _connect_ssh(spec):
}
}


def _connect_buildah(spec):
"""
Return ContextService arguments for a Buildah connection.
Expand All @@ -173,6 +179,7 @@ def _connect_buildah(spec):
}
}


def _connect_docker(spec):
"""
Return ContextService arguments for a Docker connection.
Expand Down Expand Up @@ -276,6 +283,7 @@ def _connect_podman(spec):
}
}


def _connect_setns(spec, kind=None):
"""
Return ContextService arguments for a mitogen_setns connection.
Expand Down Expand Up @@ -642,13 +650,19 @@ def _fetch_task_var(task_vars, key):
if '{' in str(val) and key in SPECIAL_TASK_VARS:
# template every time rather than storing in a cache
# in case a different template value is used in a different task
val = self.templar.template(
val,
preserve_trailing_newlines=True,
escape_backslashes=False
)
try:
val = self.templar.template(
val,
preserve_trailing_newlines=True,
escape_backslashes=False
)
except AttributeError:
LOG.error('self.templar=%r, type is %r',
self.templar, type(self.templar))
raise
return val

LOG.debug('%r.get_task_var(key=%r, default=%r)', self, key, default)
task_vars = self._get_task_vars()
if self.delegate_to_hostname is None:
return _fetch_task_var(task_vars, key)
Expand Down Expand Up @@ -715,7 +729,8 @@ def _spec_from_via(self, proxied_inventory_name, via_spec):

def _stack_from_spec(self, spec, stack=(), seen_names=()):
"""
Return a tuple of ContextService parameter dictionaries corresponding
Return a tuple of :class:`ansible_mitogen.services.ContextService`
parameter dictionaries corresponding
to the connection described by `spec`, and any connection referenced by
its `mitogen_via` or `become` fields. Each element is a dict of the
form::
Expand All @@ -739,7 +754,7 @@ def _stack_from_spec(self, spec, stack=(), seen_names=()):
:param tuple seen_names:
Inventory hostnames from parent call (cycle detection).
:returns:
Tuple `(stack, seen_names)`.
Tuple `(parameter_dict, ...)`.
"""
if spec.inventory_name() in seen_names:
raise ansible.errors.AnsibleConnectionFailure(
Expand Down Expand Up @@ -858,6 +873,7 @@ def _put_connection(self):
cannot be called _reset() since that name is used as a public API by
Ansible 2.4 wait_for_connection plug-in.
"""
LOG.debug('%r._put_connection() self.context=%r', self, self.context)
if not self.context:
return

Expand All @@ -882,6 +898,7 @@ def close(self):
Ansible connection plugin method.
"""
LOG.debug('%r: closing connection', self)
self._put_connection()
if self.binding:
self.binding.close()
Expand All @@ -900,6 +917,7 @@ def reset(self):
Ansible connection plugin method.
"""
LOG.debug('%r: resetting connection', self)
if self._play_context.remote_addr is None:
# <2.5.6 incorrectly populate PlayContext for reset_connection
# https://github.com/ansible/ansible/issues/27520
Expand Down
21 changes: 15 additions & 6 deletions ansible_mitogen/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
import traceback

import ansible
import ansible.constants
import ansible.plugins
import ansible.plugins.action
import ansible.utils.unsafe_proxy
import ansible.vars.clean
Expand Down Expand Up @@ -452,19 +450,24 @@ def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
Override the base implementation by simply calling
target.exec_command() in the target context.
"""
LOG.debug('_low_level_execute_command(%r, in_data=%r, exe=%r, dir=%r)',
cmd, type(in_data), executable, chdir)
LOG.debug(
'_low_level_execute_command(cmd=%r, sudoable=%r, in_data is %r, executable=%r, encoding_errors=%r, chdir=%r)',
cmd, sudoable, type(in_data), executable, encoding_errors, chdir,
)

if executable is None: # executable defaults to False
executable = self._play_context.executable
LOG.debug('_low_level_execute_command() executable -> %r', executable)
if executable:
cmd = executable + ' -c ' + shlex_quote(cmd)
LOG.debug('_low_level_execute_command() cmd -> %r', cmd)

# TODO: HACK: if finding python interpreter then we need to keep
# calling exec_command until we run into the right python we'll use
# chicken-and-egg issue, mitogen needs a python to run low_level_execute_command
# which is required by Ansible's discover_interpreter function
if self._finding_python_interpreter:
# FIXME Use Ansible INTERPRETER_PYTHON_FALLBACK
possible_pythons = [
'/usr/bin/python',
'python3',
Expand All @@ -482,6 +485,7 @@ def _low_level_execute_command(self, cmd, sudoable=True, in_data=None,
possible_pythons = ['python']

def _run_cmd():
LOG.debug('_low_level_execute_command()._run_cmd(): using %r', self._connection)
return self._connection.exec_command(
cmd=cmd,
in_data=in_data,
Expand All @@ -491,10 +495,13 @@ def _run_cmd():

for possible_python in possible_pythons:
try:
LOG.debug('_low_level_execute_command(): trying %s', possible_python)
self._possible_python_interpreter = possible_python
rc, stdout, stderr = _run_cmd()
LOG.debug('_low_level_execute_command(): got rc=%d, stdout=%r, stderr=%r', rc, stdout, stderr)
# TODO: what exception is thrown?
except:
except BaseException as exc:
LOG.debug('%r._low_level_execute_command for possible_python=%r: %s, %r', self, possible_python, type(exc), exc)
# we've reached the last python attempted and failed
# TODO: could use enumerate(), need to check which version of python first had it though
if possible_python == 'python':
Expand All @@ -503,10 +510,12 @@ def _run_cmd():
continue

stdout_text = to_text(stdout, errors=encoding_errors)
stderr_text = to_text(stderr, errors=encoding_errors)

return {
'rc': rc,
'stdout': stdout_text,
'stdout_lines': stdout_text.splitlines(),
'stderr': stderr,
'stderr': stderr_text,
'stderr_lines': stderr_text.splitlines(),
}
6 changes: 2 additions & 4 deletions ansible_mitogen/plugins/connection/mitogen_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@
import sys

try:
import ansible_mitogen.connection
import ansible_mitogen
except ImportError:
base_dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.abspath(os.path.join(base_dir, '../../..')))
del base_dir
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))

import ansible_mitogen.connection
import ansible_mitogen.process
Expand Down
39 changes: 9 additions & 30 deletions ansible_mitogen/plugins/connection/mitogen_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,56 +32,35 @@
import os.path
import sys

from ansible.plugins.connection.ssh import (
Connection as _ansible_ssh_Connection,
DOCUMENTATION as _ansible_ssh_DOCUMENTATION,
)

DOCUMENTATION = """
name: mitogen_ssh
author: David Wilson <[email protected]>
connection: mitogen_ssh
short_description: Connect over SSH via Mitogen
description:
- This connects using an OpenSSH client controlled by the Mitogen for
Ansible extension. It accepts every option the vanilla ssh plugin
accepts.
version_added: "2.5"
options:
ssh_args:
type: str
vars:
- name: ssh_args
- name: ansible_ssh_args
- name: ansible_mitogen_ssh_args
ssh_common_args:
type: str
vars:
- name: ssh_args
- name: ansible_ssh_common_args
- name: ansible_mitogen_ssh_common_args
ssh_extra_args:
type: str
vars:
- name: ssh_args
- name: ansible_ssh_extra_args
- name: ansible_mitogen_ssh_extra_args
"""
""" + _ansible_ssh_DOCUMENTATION.partition('options:\n')[2]

try:
import ansible_mitogen
except ImportError:
base_dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.abspath(os.path.join(base_dir, '../../..')))
del base_dir
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))

import ansible_mitogen.connection
import ansible_mitogen.loaders


class Connection(ansible_mitogen.connection.Connection):
transport = 'ssh'
vanilla_class = ansible_mitogen.loaders.connection_loader__get(
'ssh',
class_only=True,
)

@staticmethod
def _create_control_path(*args, **kwargs):
"""Forward _create_control_path() to the implementation in ssh.py."""
# https://github.com/dw/mitogen/issues/342
return Connection.vanilla_class._create_control_path(*args, **kwargs)
return _ansible_ssh_Connection._create_control_path(*args, **kwargs)
10 changes: 4 additions & 6 deletions ansible_mitogen/plugins/strategy/mitogen.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@
# debuggers and isinstance() work predictably.
#

BASE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), '../../..')
)

if BASE_DIR not in sys.path:
sys.path.insert(0, BASE_DIR)
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))

import ansible_mitogen.strategy
import ansible.plugins.strategy.linear
Expand Down
10 changes: 4 additions & 6 deletions ansible_mitogen/plugins/strategy/mitogen_linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@
# debuggers and isinstance() work predictably.
#

BASE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), '../../..')
)

if BASE_DIR not in sys.path:
sys.path.insert(0, BASE_DIR)
try:
import ansible_mitogen
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '../../../..')))

import ansible_mitogen.loaders
import ansible_mitogen.strategy
Expand Down
8 changes: 8 additions & 0 deletions ansible_mitogen/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
__metaclass__ = type

import os
import logging
import signal
import threading

Expand All @@ -48,6 +49,9 @@
import ansible.utils.sentinel


LOG = logging.getLogger(__name__)


def _patch_awx_callback():
"""
issue #400: AWX loads a display callback that suffers from thread-safety
Expand Down Expand Up @@ -326,3 +330,7 @@ def run(self, iterator, play_context, result=0):
self._worker_model.on_strategy_complete()
finally:
ansible_mitogen.process.set_worker_model(None)

def _execute_meta(self, task, play_context, iterator, target_host):
LOG.debug('%r._execute_meta(task=%r/%r, play_context=%r, iterator=%r, target_host=%r/%r):', self, type(task), task, play_context, iterator, type(target_host), target_host)
return super(StrategyMixin, self)._execute_meta(task, play_context, iterator, target_host)
Loading

0 comments on commit 5594afd

Please sign in to comment.