winrm - Handle task timeout (#82784) (#82862)

When using winrm over HTTP with message encryption enabled and a task
has timed out the connection plugin will fail to cleanup the WinRM
command. This will change that exception into a warning as a timeout is
already an exception event and a failure to clean the operation should
not override the timeout error shown.

(cherry picked from commit 8aecd1f9b2)
pull/83043/head
Jordan Borean 8 months ago committed by GitHub
parent 78615d0317
commit 10005e883e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,2 @@
bugfixes:
- winrm - Do not raise another exception during cleanup when a task is timed out - https://github.com/ansible/ansible/issues/81095

@ -177,7 +177,7 @@ from ansible.utils.display import Display
try: try:
import winrm import winrm
from winrm import Response from winrm import Response
from winrm.exceptions import WinRMError, WinRMOperationTimeoutError from winrm.exceptions import WinRMError, WinRMOperationTimeoutError, WinRMTransportError
from winrm.protocol import Protocol from winrm.protocol import Protocol
import requests.exceptions import requests.exceptions
HAS_WINRM = True HAS_WINRM = True
@ -582,7 +582,19 @@ class Connection(ConnectionBase):
raise AnsibleConnectionFailure('winrm connection error: %s' % to_native(exc)) raise AnsibleConnectionFailure('winrm connection error: %s' % to_native(exc))
finally: finally:
if command_id: if command_id:
# Due to a bug in how pywinrm works with message encryption we
# ignore a 400 error which can occur when a task timeout is
# set and the code tries to clean up the command. This happens
# as the cleanup msg is sent over a new socket but still uses
# the already encrypted payload bound to the other socket
# causing the server to reply with 400 Bad Request.
try:
self.protocol.cleanup_command(self.shell_id, command_id) self.protocol.cleanup_command(self.shell_id, command_id)
except WinRMTransportError as e:
if e.code != 400:
raise
display.warning("Failed to cleanup running WinRM command, resources might still be in use on the target server")
def _connect(self): def _connect(self):

@ -30,3 +30,15 @@
- win_ssh_async.rc == 0 - win_ssh_async.rc == 0
- win_ssh_async.stdout == "café\n" - win_ssh_async.stdout == "café\n"
- win_ssh_async.stderr == "" - win_ssh_async.stderr == ""
# Ensures the connection plugin can handle a timeout
# without raising another error.
- name: run command with timeout
win_shell: Start-Sleep -Seconds 10
timeout: 5
register: timeout_cmd
ignore_errors: true
- assert:
that:
- timeout_cmd.msg == 'The win_shell action failed to execute in the expected time frame (5) and was terminated'

@ -26,3 +26,15 @@
that: that:
- winrm_copy_empty is changed - winrm_copy_empty is changed
- winrm_copy_empty_actual.stat.size == 0 - winrm_copy_empty_actual.stat.size == 0
# Ensures the connection plugin can handle a timeout
# without raising another error.
- name: run command with timeout
win_shell: Start-Sleep -Seconds 10
timeout: 5
register: timeout_cmd
ignore_errors: true
- assert:
that:
- timeout_cmd.msg == 'The win_shell action failed to execute in the expected time frame (5) and was terminated'

Loading…
Cancel
Save