The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/pylxd/pull/363

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
For the container execute command, if the command executed has pauses in
the output text, the websocket will send binary messages.  These were
interpreted as the stream being completed, and pylxd closed the
websocket, thus losing the rest of the output.

Delving into the code indicated some very strange behaviour across the
threads, so as part of solving the problem, this has been cleaned up as
well.

Closes: #362
From 8010a87cae33bd56c17986f98c3a75ddab3f04dd Mon Sep 17 00:00:00 2001
From: Alex Kavanagh <alex.kavan...@canonical.com>
Date: Fri, 17 May 2019 16:00:00 +0100
Subject: [PATCH] Fix execute command missing output with pauses in output text

For the container execute command, if the command executed has pauses in
the output text, the websocket will send binary messages.  These were
interpreted as the stream being completed, and pylxd closed the
websocket, thus losing the rest of the output.

Delving into the code indicated some very strange behaviour across the
threads, so as part of solving the problem, this has been cleaned up as
well.

Closes: #362
---
 pylxd/models/container.py | 38 +++++++++++++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 7 deletions(-)

diff --git a/pylxd/models/container.py b/pylxd/models/container.py
index cbd8206f..4c4f91e3 100644
--- a/pylxd/models/container.py
+++ b/pylxd/models/container.py
@@ -353,7 +353,7 @@ def unfreeze(self, timeout=30, force=True, wait=False):
     def execute(
             self, commands, environment={}, encoding=None, decode=True,
             stdin_payload=None, stdin_encoding="utf-8",
-            stdout_handler=None, stderr_handler=None
+            stdout_handler=None, stderr_handler=None,
     ):
         """Execute a command on the container.
 
@@ -430,8 +430,17 @@ def execute(
                     break
                 time.sleep(.5)  # pragma: no cover
 
-            while len(manager.websockets.values()) > 0:
-                time.sleep(.1)  # pragma: no cover
+            try:
+                stdin.close()
+            except BrokenPipeError:
+                pass
+
+            stdout.finish_soon()
+            stderr.finish_soon()
+            manager.close_all()
+
+            while not stdout.finished or not stderr.finished:
+                time.sleep(.1)  # progma: no cover
 
             manager.stop()
             manager.join()
@@ -618,6 +627,9 @@ def __init__(self, manager, *args, **kwargs):
         self.encoding = kwargs.pop('encoding', None)
         self.handler = kwargs.pop('handler', None)
         self.message_encoding = None
+        self.finish_off = False
+        self.finished = False
+        self.last_message_empty = False
         super(_CommandWebsocketClient, self).__init__(*args, **kwargs)
 
     def handshake_ok(self):
@@ -626,15 +638,27 @@ def handshake_ok(self):
 
     def received_message(self, message):
         if message.data is None or len(message.data) == 0:
-            self.manager.remove(self)
-            return
+            self.last_message_empty = True
+            if self.finish_off:
+                self.finished = True
+                return
+        else:
+            self.last_message_empty = False
         if message.encoding and self.message_encoding is None:
             self.message_encoding = message.encoding
         if self.handler:
             self.handler(self._maybe_decode(message.data))
         self.buffer.append(message.data)
-        if isinstance(message, BinaryMessage):
-            self.manager.remove(self)
+        if self.finish_off and isinstance(message, BinaryMessage):
+            self.finished = True
+
+    def closed(self, code, reason=None):
+        self.finished = True
+
+    def finish_soon(self):
+        self.finish_off = True
+        if self.last_message_empty:
+            self.finished = True
 
     def _maybe_decode(self, buffer):
         if self.decode and buffer is not None:
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to