diff --git a/ansible_mitogen/connection.py b/ansible_mitogen/connection.py index 4c1df1bd..1231acb5 100644 --- a/ansible_mitogen/connection.py +++ b/ansible_mitogen/connection.py @@ -890,6 +890,29 @@ class Connection(ansible.plugins.connection.ConnectionBase): self.binding.close() self.binding = None + def _mitogen_var_options(self, templar): + # Workaround for https://github.com/ansible/ansible/issues/84238 + var_names = C.config.get_plugin_vars('connection', self._load_name) + variables = templar.available_variables + var_options = { + var_name: templar.template(variables[var_name]) + for var_name in var_names + if var_name in variables + } + + if self.allow_extras: + extras_var_prefix = 'ansible_%s_' % self.extras_prefix + var_options['_extras'] = { + var_name: templar.template(variables[var_name]) + for var_name in variables + if var_name not in var_options + and var_name.startswith(extras_var_prefix) + } + else: + var_options['_extras'] = {} + + return var_options + reset_compat_msg = ( 'Mitogen only supports "reset_connection" on Ansible 2.5.6 or later' ) @@ -922,6 +945,19 @@ class Connection(ansible.plugins.connection.ConnectionBase): shared_loader_obj=0 ) + # Workaround for https://github.com/ansible/ansible/issues/84238 + try: + task, templar = self._play_context.vars.pop( + '_mitogen.smuggled.reset_connection', + ) + except KeyError: + pass + else: + self.set_options( + task_keys=task.dump_attrs(), + var_options=self._mitogen_var_options(templar), + ) + # Clear out state in case we were ever connected. self.close() diff --git a/ansible_mitogen/strategy.py b/ansible_mitogen/strategy.py index 0a98e316..c319f3e1 100644 --- a/ansible_mitogen/strategy.py +++ b/ansible_mitogen/strategy.py @@ -45,6 +45,7 @@ import ansible_mitogen.mixins import ansible_mitogen.process import ansible.executor.process.worker +import ansible.template import ansible.utils.sentinel @@ -326,3 +327,24 @@ class StrategyMixin(object): self._worker_model.on_strategy_complete() finally: ansible_mitogen.process.set_worker_model(None) + + def _smuggle_to_connction_reset(self, task, play_context, iterator, target_host): + # Workaround for https://github.com/ansible/ansible/issues/84238 + variables = self._variable_manager.get_vars( + play=iterator._play, host=target_host, task=task, + _hosts=self._hosts_cache, _hosts_all=self._hosts_cache_all, + ) + templar = ansible.template.Templar( + loader=self._loader, variables=variables, + ) + play_context.vars.update({ + '_mitogen.smuggled.reset_connection': (task, templar), + }) + + def _execute_meta(self, task, play_context, iterator, target_host): + if task.args['_raw_params'] == 'reset_connection': + self._smuggle_to_connction_reset(task, play_context, iterator, target_host) + + return super(StrategyMixin, self)._execute_meta( + task, play_context, iterator, target_host, + ) diff --git a/ansible_mitogen/transport_config.py b/ansible_mitogen/transport_config.py index 3e9b0610..97f1b2f0 100644 --- a/ansible_mitogen/transport_config.py +++ b/ansible_mitogen/transport_config.py @@ -511,7 +511,7 @@ class PlayContextSpec(Spec): return self._play_context.private_key_file def ssh_executable(self): - return C.config.get_config_value("ssh_executable", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {})) + return self._connection_option('ssh_executable') def timeout(self): return self._play_context.timeout diff --git a/docs/changelog.rst b/docs/changelog.rst index dcd40ca9..dd4d708d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -25,6 +25,10 @@ In progress (unreleased) (e.g. ``become_exe``). * :gh:issue:`1083` :mod:`ansible_mitogen`: Templated become executable arguments (e.g. ``become_flags``). +* :gh:issue:`1083` :mod:`ansible_mitogen`: Templated ssh executable + (``ansible_ssh_executable``). +* :gh:issue:`1083` :mod:`ansible_mitogen`: Fixed templated connection options + during a ``meta: reset_connection`` task. v0.3.15 (2024-10-28) diff --git a/tests/ansible/hosts/default.hosts b/tests/ansible/hosts/default.hosts index 97883db0..eb04cf90 100644 --- a/tests/ansible/hosts/default.hosts +++ b/tests/ansible/hosts/default.hosts @@ -46,6 +46,7 @@ ansible_user="{{ lookup('pipe', 'whoami') }}" tt-password ansible_password="{{ 'has_sudo_nopw_password' | trim }}" ansible_user=mitogen__has_sudo_nopw tt-port ansible_password=has_sudo_nopw_password ansible_port="{{ 22 | int }}" ansible_user=mitogen__has_sudo_nopw tt-remote-user ansible_password=has_sudo_nopw_password ansible_user="{{ 'mitogen__has_sudo_nopw' | trim }}" +tt-ssh-executable ansible_password=has_sudo_nopw_password ansible_ssh_executable="{{ 'ssh' | trim }}" ansible_user=mitogen__has_sudo_nopw [tt_targets_inventory:vars] ansible_host=localhost diff --git a/tests/ansible/integration/ssh/templated_by_play_taskvar.yml b/tests/ansible/integration/ssh/templated_by_play_taskvar.yml index fd4bc848..0662adcd 100644 --- a/tests/ansible/integration/ssh/templated_by_play_taskvar.yml +++ b/tests/ansible/integration/ssh/templated_by_play_taskvar.yml @@ -4,6 +4,7 @@ vars: ansible_password: "{{ 'has_sudo_nopw_password' | trim }}" ansible_port: "{{ hostvars[groups['test-targets'][0]].ansible_port | default(22) }}" + ansible_ssh_executable: "{{ 'ssh' | trim }}" ansible_user: "{{ 'mitogen__has_sudo_nopw' | trim }}" tasks: diff --git a/tests/ansible/templates/test-targets.j2 b/tests/ansible/templates/test-targets.j2 index e5c5e072..27949758 100644 --- a/tests/ansible/templates/test-targets.j2 +++ b/tests/ansible/templates/test-targets.j2 @@ -74,6 +74,7 @@ ansible_user=mitogen__has_sudo_nopw tt-password ansible_password="{{ '{{' }} 'has_sudo_nopw_password' | trim {{ '}}' }}" ansible_port={{ tt.port }} ansible_user=mitogen__has_sudo_nopw tt-port ansible_password=has_sudo_nopw_password ansible_port="{{ '{{' }} {{ tt.port }} | int {{ '}}' }}" ansible_user=mitogen__has_sudo_nopw tt-remote-user ansible_password=has_sudo_nopw_password ansible_port={{ tt.port }} ansible_user="{{ '{{' }} 'mitogen__has_sudo_nopw' | trim {{ '}}' }}" +tt-ssh-executable ansible_password=has_sudo_nopw_password ansible_port={{ tt.port }} ansible_ssh_executable="{{ '{{' }} 'ssh' | trim {{ '}}' }}" ansible_user=mitogen__has_sudo_nopw [tt_targets_inventory:vars] ansible_host={{ tt.hostname }}