win_script: work when argument exceeds stdin buffer size (#33855)
* win_script: work when argument exceeds stdin buffer size * Added test for large argument being passed
This commit is contained in:
parent
e6d01ff7e3
commit
f0134079e3
3 changed files with 46 additions and 24 deletions
|
@ -22,8 +22,9 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleAction, AnsibleActionDone, AnsibleActionFail, AnsibleActionSkip
|
from ansible.errors import AnsibleError, AnsibleAction, AnsibleActionDone, AnsibleActionFail, AnsibleActionSkip
|
||||||
from ansible.module_utils._text import to_native, to_text
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
|
from ansible.plugins.shell.powershell import exec_wrapper
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -114,9 +115,14 @@ class ActionModule(ActionBase):
|
||||||
script_cmd = self._connection._shell.wrap_for_exec(script_cmd)
|
script_cmd = self._connection._shell.wrap_for_exec(script_cmd)
|
||||||
|
|
||||||
exec_data = None
|
exec_data = None
|
||||||
# HACK: come up with a sane way to pass around env outside the command
|
# WinRM requires a special wrapper to work with environment variables
|
||||||
if self._connection.transport == "winrm":
|
if self._connection.transport == "winrm":
|
||||||
exec_data = self._connection._create_raw_wrapper_payload(script_cmd, env_dict)
|
pay = self._connection._create_raw_wrapper_payload(script_cmd,
|
||||||
|
env_dict)
|
||||||
|
exec_data = exec_wrapper.replace(b"$json_raw = ''",
|
||||||
|
b"$json_raw = @'\r\n%s\r\n'@"
|
||||||
|
% to_bytes(pay))
|
||||||
|
script_cmd = "-"
|
||||||
|
|
||||||
result.update(self._low_level_execute_command(cmd=script_cmd, in_data=exec_data, sudoable=True, chdir=chdir))
|
result.update(self._low_level_execute_command(cmd=script_cmd, in_data=exec_data, sudoable=True, chdir=chdir))
|
||||||
|
|
||||||
|
|
|
@ -391,8 +391,6 @@ class Connection(ConnectionBase):
|
||||||
stdin_push_failed = False
|
stdin_push_failed = False
|
||||||
command_id = self.protocol.run_command(self.shell_id, to_bytes(command), map(to_bytes, args), console_mode_stdin=(stdin_iterator is None))
|
command_id = self.protocol.run_command(self.shell_id, to_bytes(command), map(to_bytes, args), console_mode_stdin=(stdin_iterator is None))
|
||||||
|
|
||||||
# TODO: try/except around this, so we can get/return the command result on a broken pipe or other failure (probably more useful than the 500 that
|
|
||||||
# comes from this)
|
|
||||||
try:
|
try:
|
||||||
if stdin_iterator:
|
if stdin_iterator:
|
||||||
for (data, is_last) in stdin_iterator:
|
for (data, is_last) in stdin_iterator:
|
||||||
|
@ -400,12 +398,9 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
display.warning("FATAL ERROR DURING FILE TRANSFER: %s" % format_exc())
|
display.warning("FATAL ERROR DURING FILE TRANSFER: %s" % to_text(ex))
|
||||||
stdin_push_failed = True
|
stdin_push_failed = True
|
||||||
|
|
||||||
if stdin_push_failed:
|
|
||||||
raise AnsibleError('winrm send_input failed')
|
|
||||||
|
|
||||||
# NB: this can hang if the receiver is still running (eg, network failed a Send request but the server's still happy).
|
# NB: this can hang if the receiver is still running (eg, network failed a Send request but the server's still happy).
|
||||||
# FUTURE: Consider adding pywinrm status check/abort operations to see if the target is still running after a failure.
|
# FUTURE: Consider adding pywinrm status check/abort operations to see if the target is still running after a failure.
|
||||||
resptuple = self.protocol.get_command_output(self.shell_id, command_id)
|
resptuple = self.protocol.get_command_output(self.shell_id, command_id)
|
||||||
|
@ -423,7 +418,11 @@ class Connection(ConnectionBase):
|
||||||
display.vvvvvv('WINRM STDERR %s' % to_text(response.std_err), host=self._winrm_host)
|
display.vvvvvv('WINRM STDERR %s' % to_text(response.std_err), host=self._winrm_host)
|
||||||
|
|
||||||
if stdin_push_failed:
|
if stdin_push_failed:
|
||||||
raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (response.std_out, response.std_err))
|
stderr = to_bytes(response.std_err, encoding='utf-8')
|
||||||
|
if self.is_clixml(stderr):
|
||||||
|
stderr = self.parse_clixml_stream(stderr)
|
||||||
|
|
||||||
|
raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (response.std_out, stderr))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
finally:
|
finally:
|
||||||
|
@ -456,7 +455,9 @@ class Connection(ConnectionBase):
|
||||||
'powershell_modules': {},
|
'powershell_modules': {},
|
||||||
'actions': ['exec'],
|
'actions': ['exec'],
|
||||||
'exec': to_text(base64.b64encode(to_bytes(leaf_exec))),
|
'exec': to_text(base64.b64encode(to_bytes(leaf_exec))),
|
||||||
'environment': environment
|
'environment': environment,
|
||||||
|
'min_ps_version': None,
|
||||||
|
'min_os_version': None
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.dumps(payload)
|
return json.dumps(payload)
|
||||||
|
|
|
@ -54,6 +54,24 @@
|
||||||
- "test_script_with_args_result is not failed"
|
- "test_script_with_args_result is not failed"
|
||||||
- "test_script_with_args_result is changed"
|
- "test_script_with_args_result is changed"
|
||||||
|
|
||||||
|
# Bug: https://github.com/ansible/ansible/issues/32850
|
||||||
|
- name: set fact of long string
|
||||||
|
set_fact:
|
||||||
|
long_string: "{{ lookup('pipe', 'printf \"a%.0s\" {1..1000}') }}"
|
||||||
|
|
||||||
|
- name: run test script with args that exceed the stdin buffer
|
||||||
|
script: test_script_with_args.ps1 {{ long_string }}
|
||||||
|
register: test_script_with_large_args_result
|
||||||
|
|
||||||
|
- name: check that script ran and received arguments correctly
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- test_script_with_large_args_result.rc == 0
|
||||||
|
- test_script_with_large_args_result.stdout == long_string + "\r\n"
|
||||||
|
- not test_script_with_large_args_result.stderr
|
||||||
|
- test_script_with_large_args_result is not failed
|
||||||
|
- test_script_with_large_args_result is changed
|
||||||
|
|
||||||
- name: run test script that takes parameters passed via splatting
|
- name: run test script that takes parameters passed via splatting
|
||||||
script: test_script_with_splatting.ps1 @{ This = 'this'; That = '{{ test_win_script_value }}'; Other = 'other'}
|
script: test_script_with_splatting.ps1 @{ This = 'this'; That = '{{ test_win_script_value }}'; Other = 'other'}
|
||||||
register: test_script_with_splatting_result
|
register: test_script_with_splatting_result
|
||||||
|
@ -201,20 +219,17 @@
|
||||||
- "test_script_bool_result.stdout_lines[0] == 'System.Boolean'"
|
- "test_script_bool_result.stdout_lines[0] == 'System.Boolean'"
|
||||||
- "test_script_bool_result.stdout_lines[1] == 'True'"
|
- "test_script_bool_result.stdout_lines[1] == 'True'"
|
||||||
|
|
||||||
# FIXME: re-enable this test once script can run under the wrapper with powershell
|
- name: run test script that uses envvars
|
||||||
#- name: run test script that uses envvars
|
script: test_script_with_env.ps1
|
||||||
# script: test_script_with_env.ps1
|
environment:
|
||||||
# environment:
|
taskenv: task
|
||||||
# taskenv: task
|
register: test_script_env_result
|
||||||
# register: test_script_env_result
|
|
||||||
#
|
|
||||||
#- name: ensure that script ran and that environment var was passed
|
|
||||||
# assert:
|
|
||||||
# that:
|
|
||||||
# - test_script_env_result is successful
|
|
||||||
# - test_script_env_result.stdout_lines[0] == 'task'
|
|
||||||
#
|
|
||||||
|
|
||||||
|
- name: ensure that script ran and that environment var was passed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- test_script_env_result is successful
|
||||||
|
- test_script_env_result.stdout_lines[0] == 'task'
|
||||||
|
|
||||||
# check mode
|
# check mode
|
||||||
- name: Run test script that creates a file in check mode
|
- name: Run test script that creates a file in check mode
|
||||||
|
|
Loading…
Reference in a new issue