[lxc-devel] [lxd/master] VM: Further attempts to fix VM exec instability
tomponline on Github
lxc-bot at linuxcontainers.org
Tue Feb 11 12:17:15 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 497 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200211/03e93b97/attachment.bin>
-------------- next part --------------
From 0d76248959f4b96ecbff4e8740d616455cb6a061 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 11 Feb 2020 12:13:32 +0000
Subject: [PATCH 1/3] shared/network: Don't log contents of file handle in
WebsocketRecvStream
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
shared/network.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/shared/network.go b/shared/network.go
index 71e5f09551..3a49052850 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -211,7 +211,7 @@ func WebsocketRecvStream(w io.Writer, conn *websocket.Conn) chan bool {
}
if err != nil {
- logger.Debugf("Got error getting next reader %s, %s", err, w)
+ logger.Debugf("Got error getting next reader %s", err)
break
}
From 5106f95ceb32b8a0603326906279f30e2d66deea Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 11 Feb 2020 12:13:57 +0000
Subject: [PATCH 2/3] shared/netutils/network/linux: Adds ability to switch
WebsocketExecMirror to use ReaderToChannel
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
shared/netutils/network_linux.go | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/shared/netutils/network_linux.go b/shared/netutils/network_linux.go
index cbea0423b3..93f0846768 100644
--- a/shared/netutils/network_linux.go
+++ b/shared/netutils/network_linux.go
@@ -171,14 +171,22 @@ func NetnsGetifaddrs(initPID int32) (map[string]api.InstanceStateNetwork, error)
return networks, nil
}
-func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, exited chan bool, fd int) (chan bool, chan bool) {
+// WebsocketExecMirror if supplied with pollFd then it uses polling on that descriptor.
+func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, exited chan bool, pollFd int) (chan bool, chan bool) {
readDone := make(chan bool, 1)
writeDone := make(chan bool, 1)
go shared.DefaultWriter(conn, w, writeDone)
go func(conn *websocket.Conn, r io.ReadCloser) {
- in := shared.ExecReaderToChannel(r, -1, exited, fd)
+ var in <-chan []byte
+ if pollFd > 0 {
+ in = shared.ExecReaderToChannel(r, -1, exited, pollFd)
+
+ } else {
+ in = shared.ReaderToChannel(r, -1)
+ }
+
for {
buf, ok := <-in
if !ok {
From 28c0f927e295e3bb5873ef780b478a86338c8fce Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 11 Feb 2020 12:14:41 +0000
Subject: [PATCH 3/3] lxd/container/exec: Switch WebsocketMirror to use
standard read mechanism for VMs
Closes PTY earlier so it doesn't block the mirror function.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd-agent/exec.go | 15 ++++++++-------
lxd/container_exec.go | 22 ++++++++++++++--------
2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/lxd-agent/exec.go b/lxd-agent/exec.go
index 1feddb8325..7bbc84643a 100644
--- a/lxd-agent/exec.go
+++ b/lxd-agent/exec.go
@@ -349,8 +349,9 @@ func (s *execWs) Do(op *operations.Operation) error {
conn := s.conns[0]
s.connsLock.Unlock()
- logger.Info("Started mirroring websocket")
- readDone, writeDone := netutils.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))
+ pollFD := int(ptys[0].Fd())
+ logger.Infof("Started mirroring websocket with FD %v", pollFD)
+ readDone, writeDone := netutils.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, pollFD)
<-readDone
<-writeDone
@@ -388,6 +389,11 @@ func (s *execWs) Do(op *operations.Operation) error {
tty.Close()
}
+ // Ensure PTYs are closed before websocket to end wgEOF.Wait().
+ for _, pty := range ptys {
+ pty.Close()
+ }
+
s.connsLock.Lock()
conn := s.conns[-1]
s.connsLock.Unlock()
@@ -401,13 +407,8 @@ func (s *execWs) Do(op *operations.Operation) error {
}
attachedChildIsDead <- true
-
wgEOF.Wait()
- for _, pty := range ptys {
- pty.Close()
- }
-
metadata := shared.Jmap{"return": cmdResult}
err = op.UpdateMetadata(metadata)
if err != nil {
diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index 2302ee54b3..0853b8b923 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -240,10 +240,16 @@ func (s *execWs) Do(op *operations.Operation) error {
conn := s.conns[0]
s.connsLock.Unlock()
- logger.Debugf("Started mirroring websocket")
- defer logger.Debugf("Finished mirroring websocket")
- readDone, writeDone := netutils.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))
+ pollFD := 0
+
+ // Use the polling mechanism for websocket mirror if local container, otherwise use reads.
+ if s.instance.Type() == instancetype.Container {
+ pollFD = int(ptys[0].Fd())
+ }
+ logger.Debugf("Started mirroring websocket with FD %v", pollFD)
+ defer logger.Debugf("Finished mirroring websocket")
+ readDone, writeDone := netutils.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, pollFD)
<-readDone
<-writeDone
conn.Close()
@@ -279,6 +285,11 @@ func (s *execWs) Do(op *operations.Operation) error {
tty.Close()
}
+ // Ensure PTYs are closed before websocket to end wgEOF.Wait().
+ for _, pty := range ptys {
+ pty.Close()
+ }
+
s.connsLock.Lock()
conn := s.conns[-1]
s.connsLock.Unlock()
@@ -292,13 +303,8 @@ func (s *execWs) Do(op *operations.Operation) error {
}
attachedChildIsDead <- true
-
wgEOF.Wait()
- for _, pty := range ptys {
- pty.Close()
- }
-
metadata := shared.Jmap{"return": cmdResult}
err = op.UpdateMetadata(metadata)
if err != nil {
More information about the lxc-devel
mailing list