summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjasdeep-hundal <jasdeep.singh.hundal@gmail.com>2016-10-27 12:36:56 -0700
committerToshio Kuratomi <a.badger@gmail.com>2016-11-01 07:53:04 -0700
commit6adbc7d64abf2a89019320116270b15f7c42d48d (patch)
tree28607b6407c5d8616737ece13f086b752bb7d201
parent325bf617e9c7be163cc7454f4f7d75f9ed6d44a5 (diff)
downloadansible-6adbc7d64abf2a89019320116270b15f7c42d48d.tar.gz
Fix OpenSSH-related ssh process exit race
Mitigate the effects of observing the ssh process still running after seeing an EOF on stdout when using OpenSSH with ControlPersist, since it does not close the stderr file descriptor in this case. (cherry picked from commit 679da00236297e6c5010346b815b7342ea90e543)
-rw-r--r--lib/ansible/plugins/connection/ssh.py25
1 files changed, 13 insertions, 12 deletions
diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py
index f4a6e34fb6..0c18b983a5 100644
--- a/lib/ansible/plugins/connection/ssh.py
+++ b/lib/ansible/plugins/connection/ssh.py
@@ -451,6 +451,14 @@ class Connection(ConnectionBase):
b_chunk = p.stdout.read()
if b_chunk == b'':
rpipes.remove(p.stdout)
+ # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
+ # first connection goes into the background and we never see EOF
+ # on stderr. If we see EOF on stdout, lower the select timeout
+ # to reduce the time wasted selecting on stderr if we observe
+ # that the process has not yet existed after this EOF. Otherwise
+ # we may spend a long timeout period waiting for an EOF that is
+ # not going to arrive until the persisted connection closes.
+ timeout = 1
b_tmp_stdout += b_chunk
display.debug("stdout chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk)))
@@ -534,18 +542,11 @@ class Connection(ConnectionBase):
if p.poll() is not None:
if not rpipes or not rfd:
break
-
- # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
- # first connection goes into the background and we never see EOF
- # on stderr. If we see EOF on stdout and the process has exited,
- # we're probably done. We call select again with a zero timeout,
- # just to make certain we don't miss anything that may have been
- # written to stderr between the time we called select() and when
- # we learned that the process had finished.
-
- if p.stdout not in rpipes:
- timeout = 0
- continue
+ # We should not see further writes to the stdout/stderr file
+ # descriptors after the process has closed, set the select
+ # timeout to gather any last writes we may have missed.
+ timeout = 0
+ continue
# If the process has not yet exited, but we've already read EOF from
# its stdout and stderr (and thus removed both from rpipes), we can