[lxc-devel] [lxd/master] Bugfixes

stgraber on Github lxc-bot at linuxcontainers.org
Thu Jul 6 04:36:27 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170706/6d604262/attachment.bin>
-------------- next part --------------
From 441f13699411106ad27c5e24d0e691c9b86047c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 6 Jul 2017 00:24:17 -0400
Subject: [PATCH 1/2] client: Improve migration relay code
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This removes code duplication by adding a new function for migration
proxying and makes it more robust by validating things before starting
the proxy.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 client/lxd_containers.go | 147 +++++++++++++++++++++++++++++------------------
 1 file changed, 91 insertions(+), 56 deletions(-)

diff --git a/client/lxd_containers.go b/client/lxd_containers.go
index b627169db..9d4cb6bce 100644
--- a/client/lxd_containers.go
+++ b/client/lxd_containers.go
@@ -344,36 +344,11 @@ func (r *ProtocolLXD) CopyContainer(source ContainerServer, container api.Contai
 		}
 
 		// Launch the relay
-		dones := []chan bool{}
-		conns := []*websocket.Conn{}
-
-		for name := range sourceSecrets {
-			sourceConn, err := source.GetOperationWebsocket(op.ID, sourceSecrets[name])
-			if err != nil {
-				return nil, err
-			}
-
-			targetConn, err := r.GetOperationWebsocket(targetOp.ID, targetSecrets[name])
-			if err != nil {
-				return nil, err
-			}
-
-			conns = append(conns, sourceConn)
-			conns = append(conns, targetConn)
-			dones = append(dones, shared.WebsocketProxy(sourceConn, targetConn))
+		err = r.proxyMigration(targetOp, targetSecrets, source, op, sourceSecrets)
+		if err != nil {
+			return nil, err
 		}
 
-		// Wait for everything to be done
-		go func() {
-			for _, chDone := range dones {
-				<-chDone
-			}
-
-			for _, conn := range conns {
-				conn.Close()
-			}
-		}()
-
 		// Prepare a tracking operation
 		rop := RemoteOperation{
 			targetOp: targetOp,
@@ -399,6 +374,91 @@ func (r *ProtocolLXD) CopyContainer(source ContainerServer, container api.Contai
 	return r.tryCreateContainer(req, info.Addresses)
 }
 
+func (r *ProtocolLXD) proxyMigration(targetOp *Operation, targetSecrets map[string]string, source ContainerServer, sourceOp *Operation, sourceSecrets map[string]string) error {
+	// Sanity checks
+	for n := range targetSecrets {
+		_, ok := sourceSecrets[n]
+		if !ok {
+			return fmt.Errorf("Migration target expects the \"%s\" socket but source isn't providing it", n)
+		}
+	}
+
+	if targetSecrets["control"] == "" {
+		return fmt.Errorf("Migration target didn't setup the required \"control\" socket")
+	}
+
+	// Struct used to hold everything together
+	type proxy struct {
+		done       chan bool
+		sourceConn *websocket.Conn
+		targetConn *websocket.Conn
+	}
+
+	proxies := map[string]*proxy{}
+
+	// Connect the control socket
+	sourceConn, err := source.GetOperationWebsocket(sourceOp.ID, sourceSecrets["control"])
+	if err != nil {
+		return err
+	}
+
+	targetConn, err := r.GetOperationWebsocket(targetOp.ID, targetSecrets["control"])
+	if err != nil {
+		return err
+	}
+
+	proxies["control"] = &proxy{
+		done:       shared.WebsocketProxy(sourceConn, targetConn),
+		sourceConn: sourceConn,
+		targetConn: targetConn,
+	}
+
+	// Connect the data sockets
+	for name := range sourceSecrets {
+		if name == "control" {
+			continue
+		}
+
+		// Handle resets (used for multiple objects)
+		sourceConn, err := source.GetOperationWebsocket(sourceOp.ID, sourceSecrets[name])
+		if err != nil {
+			break
+		}
+
+		targetConn, err := r.GetOperationWebsocket(targetOp.ID, targetSecrets[name])
+		if err != nil {
+			break
+		}
+
+		proxies[name] = &proxy{
+			sourceConn: sourceConn,
+			targetConn: targetConn,
+			done:       shared.WebsocketProxy(sourceConn, targetConn),
+		}
+	}
+
+	// Cleanup once everything is done
+	go func() {
+		// Wait for control socket
+		<-proxies["control"].done
+		proxies["control"].sourceConn.Close()
+		proxies["control"].targetConn.Close()
+
+		// Then deal with the others
+		for name, proxy := range proxies {
+			if name == "control" {
+				continue
+			}
+
+			<-proxy.done
+			proxy.sourceConn.Close()
+			proxy.targetConn.Close()
+		}
+	}()
+
+	return nil
+}
+
 // UpdateContainer updates the container definition
 func (r *ProtocolLXD) UpdateContainer(name string, container api.ContainerPut, ETag string) (*Operation, error) {
 	// Send the request
@@ -991,36 +1051,11 @@ func (r *ProtocolLXD) CopyContainerSnapshot(source ContainerServer, snapshot api
 		}
 
 		// Launch the relay
-		dones := []chan bool{}
-		conns := []*websocket.Conn{}
-
-		for name := range sourceSecrets {
-			sourceConn, err := source.GetOperationWebsocket(op.ID, sourceSecrets[name])
-			if err != nil {
-				return nil, err
-			}
-
-			targetConn, err := r.GetOperationWebsocket(targetOp.ID, targetSecrets[name])
-			if err != nil {
-				return nil, err
-			}
-
-			conns = append(conns, sourceConn)
-			conns = append(conns, targetConn)
-			dones = append(dones, shared.WebsocketProxy(sourceConn, targetConn))
+		err = r.proxyMigration(targetOp, targetSecrets, source, op, sourceSecrets)
+		if err != nil {
+			return nil, err
 		}
 
-		// Wait for everything to be done
-		go func() {
-			for _, chDone := range dones {
-				<-chDone
-			}
-
-			for _, conn := range conns {
-				conn.Close()
-			}
-		}()
-
 		// Prepare a tracking operation
 		rop := RemoteOperation{
 			targetOp: targetOp,

From 5eeaa93fe5430d0110420ff44aec49298177d875 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 6 Jul 2017 00:25:41 -0400
Subject: [PATCH 2/2] shared: Websocket proxy should proxy everything
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/network.go | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/shared/network.go b/shared/network.go
index 4cf7af81b..a2ee54740 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -234,35 +234,21 @@ func WebsocketProxy(source *websocket.Conn, target *websocket.Conn) chan bool {
 	forward := func(in *websocket.Conn, out *websocket.Conn, ch chan bool) {
 		for {
 			mt, r, err := in.NextReader()
-			if mt == websocket.CloseMessage {
-				logger.Debugf("Got close message for reader")
-				break
-			}
-
-			if mt == websocket.TextMessage {
-				logger.Debugf("got message barrier")
-				break
-			}
-
 			if err != nil {
-				logger.Debugf("Got error getting next reader %s", err)
 				break
 			}
 
-			w, err := out.NextWriter(websocket.BinaryMessage)
+			w, err := out.NextWriter(mt)
 			if err != nil {
-				logger.Debugf("Got error getting next writer %s", err)
 				break
 			}
 
 			_, err = io.Copy(w, r)
 			w.Close()
 			if err != nil {
-				logger.Debugf("Got err writing %s", err)
 				break
 			}
 		}
-		out.WriteMessage(websocket.TextMessage, []byte{})
 
 		ch <- true
 	}
@@ -275,8 +261,13 @@ func WebsocketProxy(source *websocket.Conn, target *websocket.Conn) chan bool {
 
 	ch := make(chan bool)
 	go func() {
-		<-chSend
-		<-chRecv
+		select {
+		case <-chSend:
+		case <-chRecv:
+		}
+
+		source.Close()
+		target.Close()
 
 		ch <- true
 	}()


More information about the lxc-devel mailing list