Send initial data before calling select whenever possible
Without this, we could execute «ssh -q ...» and call select(), which would timeout after the default 10s, and only then send initial data. (This is a relic of the earlier change where we always ran ssh with -vvv, so the situation where it would sit quietly never happened in practice; but this would have been the right thing to do even then.)
This commit is contained in:
parent
c9a004227e
commit
587054db2a
1 changed files with 24 additions and 9 deletions
|
@ -436,6 +436,13 @@ class Connection(ConnectionBase):
|
||||||
for fd in rpipes:
|
for fd in rpipes:
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
# If we can send initial data without waiting for anything, we do so
|
||||||
|
# before we call select.
|
||||||
|
|
||||||
|
if states[state] == 'ready_to_send' and in_data:
|
||||||
|
self._send_initial_data(stdin, in_data)
|
||||||
|
state += 1
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
rfd, wfd, efd = select.select(rpipes, [], rpipes, timeout)
|
rfd, wfd, efd = select.select(rpipes, [], rpipes, timeout)
|
||||||
|
|
||||||
|
@ -518,18 +525,11 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
# Once we're sure that the privilege escalation prompt, if any, has
|
# Once we're sure that the privilege escalation prompt, if any, has
|
||||||
# been dealt with, we can send any initial data and start waiting
|
# been dealt with, we can send any initial data and start waiting
|
||||||
# for output. (Note that we have to close the process's stdin here,
|
# for output.
|
||||||
# otherwise, for example, "sftp -b -" will just hang forever waiting
|
|
||||||
# for more commands.)
|
|
||||||
|
|
||||||
if states[state] == 'ready_to_send':
|
if states[state] == 'ready_to_send':
|
||||||
if in_data:
|
if in_data:
|
||||||
self._display.debug('Sending initial data (%d bytes)' % len(in_data))
|
self._send_initial_data(stdin, in_data)
|
||||||
try:
|
|
||||||
stdin.write(in_data)
|
|
||||||
stdin.close()
|
|
||||||
except (OSError, IOError):
|
|
||||||
raise AnsibleConnectionFailure('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
|
|
||||||
state += 1
|
state += 1
|
||||||
|
|
||||||
# Now we just wait for the process to exit. Output is already being
|
# Now we just wait for the process to exit. Output is already being
|
||||||
|
@ -567,6 +567,21 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
return (p.returncode, stdout, stderr)
|
return (p.returncode, stdout, stderr)
|
||||||
|
|
||||||
|
def _send_initial_data(self, fh, in_data):
|
||||||
|
'''
|
||||||
|
Writes initial data to the stdin filehandle of the subprocess and closes
|
||||||
|
it. (The handle must be closed; otherwise, for example, "sftp -b -" will
|
||||||
|
just hang forever waiting for more commands.)
|
||||||
|
'''
|
||||||
|
|
||||||
|
self._display.debug('Sending initial data (%d bytes)' % len(in_data))
|
||||||
|
|
||||||
|
try:
|
||||||
|
fh.write(in_data)
|
||||||
|
fh.close()
|
||||||
|
except (OSError, IOError):
|
||||||
|
raise AnsibleConnectionFailure('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
|
||||||
|
|
||||||
# This is a separate method because we need to do the same thing for stdout
|
# This is a separate method because we need to do the same thing for stdout
|
||||||
# and stderr.
|
# and stderr.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue