libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject [2/2] git commit: Fix a deployment buffering issue spotted by @pquerna which could happen if the the executed command produced a lot of output.
Date Sat, 28 Dec 2013 23:53:01 GMT
Fix a deployment buffering issue spotted by @pquerna which could happen if the
the executed command produced a lot of output.


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/a053cde5
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/a053cde5
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/a053cde5

Branch: refs/heads/trunk
Commit: a053cde54fb6fffe8666aa01de46a354115f4f40
Parents: 6e53bff
Author: Tomaz Muraus <tomaz@apache.org>
Authored: Sun Dec 29 00:31:20 2013 +0100
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Sun Dec 29 00:43:12 2013 +0100

----------------------------------------------------------------------
 libcloud/compute/ssh.py | 52 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 43 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/a053cde5/libcloud/compute/ssh.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/ssh.py b/libcloud/compute/ssh.py
index 7cbcee6..88094a5 100644
--- a/libcloud/compute/ssh.py
+++ b/libcloud/compute/ssh.py
@@ -36,6 +36,11 @@ from os.path import split as psplit
 from os.path import join as pjoin
 
 from libcloud.utils.logging import ExtraLogFormatter
+from libcloud.utils.py3 import StringIO
+
+
+# Maximum number of bytes to read at once from a socket
+CHUNK_SIZE = 1024
 
 
 class BaseSSHClient(object):
@@ -254,24 +259,53 @@ class ParamikoSSHClient(BaseSSHClient):
 
         chan.exec_command(cmd)
 
-        stdin = chan.makefile('wb', bufsize)
-        stdout = chan.makefile('rb', bufsize)
-        stderr = chan.makefile_stderr('rb', bufsize)
+        stdout = StringIO()
+        stderr = StringIO()
 
+        # Create a stdin file and immediately close it to prevent any
+        # interactive script from hanging the process.
+        stdin = chan.makefile('wb', bufsize)
         stdin.close()
 
+        # Receive all the output
+        # Note: This is used instead of chan.makefile approach to prevent
+        # buffering issues and hanging if the executed command produces a lot
+        # of output.
+        while not chan.exit_status_ready():
+            if chan.recv_ready():
+                data = chan.recv(CHUNK_SIZE)
+
+                while data:
+                    stdout.write(data)
+                    ready = chan.recv_ready()
+
+                    if not ready:
+                        break
+
+                    data = chan.recv(CHUNK_SIZE)
+
+            if chan.recv_stderr_ready():
+                data = chan.recv_stderr(CHUNK_SIZE)
+
+                while data:
+                    stderr.write(data)
+                    ready = chan.recv_stderr_ready()
+
+                    if not ready:
+                        break
+
+                    data = chan.recv_stderr(CHUNK_SIZE)
+
         # Receive the exit status code of the command we ran.
-        # Note: If the command hasn't finished yet, this method will block
-        # until it does
         status = chan.recv_exit_status()
 
-        so = stdout.read()
-        se = stderr.read()
+        stdout = stdout.getvalue()
+        stderr = stderr.getvalue()
 
-        extra = {'_status': status, '_stdout': so, '_stderr': se}
+        extra = {'_status': status, '_stdout': stdout, '_stderr': stderr}
         self.logger.debug('Command finished', extra=extra)
 
-        return [so, se, status]
+        return [stdout, stderr, status]
 
     def close(self):
         self.logger.debug('Closing server connection')


Mime
View raw message