diff --git a/changelogs/fragments/86749-winrm-stdin-error-message.yml b/changelogs/fragments/86749-winrm-stdin-error-message.yml new file mode 100644 index 00000000000..2dc775c4a7f --- /dev/null +++ b/changelogs/fragments/86749-winrm-stdin-error-message.yml @@ -0,0 +1,2 @@ +minor_changes: + - winrm connection plugin - improved error message to include target host when stdin transfer fails (https://github.com/ansible/ansible/issues/86749) diff --git a/lib/ansible/plugins/connection/winrm.py b/lib/ansible/plugins/connection/winrm.py index df89bdcd1bc..6e77ae25025 100644 --- a/lib/ansible/plugins/connection/winrm.py +++ b/lib/ansible/plugins/connection/winrm.py @@ -620,7 +620,7 @@ class Connection(ConnectionBase): self._winrm_write_stdin(command_id, stdin_iterator) except Exception as ex: - display.error_as_warning("ERROR DURING WINRM SEND INPUT. Attempting to recover.", ex) + display.error_as_warning(f"ERROR DURING WINRM SEND INPUT TO {self._winrm_host}. Attempting to recover.", ex) stdin_push_failed = True # Even on a failure above we try at least once to get the output diff --git a/test/integration/targets/connection_winrm/action_plugins/test_stdin_failure.py b/test/integration/targets/connection_winrm/action_plugins/test_stdin_failure.py new file mode 100644 index 00000000000..1e30c63fe26 --- /dev/null +++ b/test/integration/targets/connection_winrm/action_plugins/test_stdin_failure.py @@ -0,0 +1,36 @@ +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import annotations + +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + """ + Custom action plugin to trip a failure using the winrm connection plugin. + This patches the connection's _winrm_write_stdin to fail deterministically. + """ + + def run(self, tmp=None, task_vars=None): + result = super(ActionModule, self).run(tmp, task_vars) + + connection = self._connection + original_write_stdin = connection._winrm_write_stdin + + def failing_write_stdin(_command_id, _stdin_iterator): + raise Exception("INJECTED TEST FAILURE: stdin write failed") + + try: + connection._winrm_write_stdin = failing_write_stdin + + # Execute a module that will use stdin (pipelining is on by default) + module_result = self._execute_module( + module_name='ansible.windows.win_ping', + module_args={}, + task_vars=task_vars, + ) + + result.update(module_result) + finally: + connection._winrm_write_stdin = original_write_stdin + + return result diff --git a/test/integration/targets/connection_winrm/tests.yml b/test/integration/targets/connection_winrm/tests.yml index ed54bb8366d..b065d152a77 100644 --- a/test/integration/targets/connection_winrm/tests.yml +++ b/test/integration/targets/connection_winrm/tests.yml @@ -81,3 +81,15 @@ assert: that: - stderr_clixml.stderr_lines == ['Test 🎵 _x005F_ _x005Z_.'] + + - name: Test stdin write failure error message + test_stdin_failure: + ignore_errors: true + register: stdin_write_fail + + - assert: + that: + - stdin_write_fail is failed + - stdin_write_fail.warnings | default([]) | select('search', warning_substring) | list | length > 0 + vars: + warning_substring: "ERROR DURING WINRM SEND INPUT TO "