[lxc-devel] [lxd/master] netcat: add new errno detection helpers, switch netcat over to them and implement netcat logging

brauner on Github lxc-bot at linuxcontainers.org
Thu Apr 20 12:44:41 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170420/6f62cc67/attachment.bin>
-------------- next part --------------
From 0683675013503d82e97e0a50773422077389d9f5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 20 Apr 2017 11:45:00 +0200
Subject: [PATCH 1/3] util_linux: add function to detect errno

Closes #2494.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 shared/util_linux.go | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/shared/util_linux.go b/shared/util_linux.go
index a01dbc1..519bb71 100644
--- a/shared/util_linux.go
+++ b/shared/util_linux.go
@@ -778,3 +778,23 @@ func LookupBlockDevByUUID(uuid string) (string, error) {
 
 	return detectedPath, nil
 }
+
+// Detect whether err is an errno.
+func GetErrno(err error) (errno error, iserrno bool) {
+	sysErr, ok := err.(*os.SyscallError)
+	if ok {
+		return sysErr.Err, true
+	}
+
+	pathErr, ok := err.(*os.PathError)
+	if ok {
+		return pathErr.Err, true
+	}
+
+	tmpErrno, ok := err.(syscall.Errno)
+	if ok {
+		return tmpErrno, true
+	}
+
+	return nil, false
+}

From c8aed1e471e6116f38695db4492a88aa030dce09 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 20 Apr 2017 14:12:18 +0200
Subject: [PATCH 2/3] netcat: switch to new helper

Closes #2494.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/main_netcat.go | 82 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 51 insertions(+), 31 deletions(-)

diff --git a/lxd/main_netcat.go b/lxd/main_netcat.go
index 7de62f8..aa86780 100644
--- a/lxd/main_netcat.go
+++ b/lxd/main_netcat.go
@@ -5,8 +5,11 @@ import (
 	"io"
 	"net"
 	"os"
+	"strings"
 	"sync"
 	"syscall"
+
+	"github.com/lxc/lxd/shared"
 )
 
 // Netcat is called with:
@@ -21,13 +24,47 @@ func cmdNetcat(args []string) error {
 		return fmt.Errorf("Bad arguments %q", args)
 	}
 
+	// The socket name on LXD instances prior to netcat log file is:
+	// 	/<some-tmp-path/lxd_rsync_<random-suffix>
+	// and on LXD instances with netcat log file:
+	// 	/<some-tmp-path/lxd_<ctName>_rsync_<random-suffix>
+	// Detect the latter case and create a netcat log
+	namestart := strings.LastIndex(args[1], "/lxd_")
+	nameend := strings.LastIndex(args[1], "_rsync_")
+	var logFile *os.File
+	var err error
+	if namestart > 0 && nameend > 0 {
+		namestart += len("/lxd_") - 1
+		if namestart != nameend {
+			ctName := args[1][namestart+1 : nameend]
+
+			logPath := shared.LogPath(ctName, "netcat.log")
+			if shared.PathExists(logPath) {
+				os.Remove(logPath)
+			}
+
+			logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
+			if err != nil {
+				logFile = nil
+			} else {
+				defer logFile.Close()
+			}
+		}
+	}
+
 	uAddr, err := net.ResolveUnixAddr("unix", args[1])
 	if err != nil {
+		if logFile != nil {
+			logFile.WriteString(fmt.Sprintf("Could not resolve unix domain socket \"%s\": %s.\n", args[1], err))
+		}
 		return err
 	}
 
 	conn, err := net.DialUnix("unix", nil, uAddr)
 	if err != nil {
+		if logFile != nil {
+			logFile.WriteString(fmt.Sprintf("Could not dial unix domain socket \"%s\": %s.\n", args[1], err))
+		}
 		return err
 	}
 
@@ -35,13 +72,19 @@ func cmdNetcat(args []string) error {
 	wg.Add(1)
 
 	go func() {
-		io.Copy(eagainWriter{os.Stdout}, eagainReader{conn})
+		_, err := io.Copy(eagainWriter{os.Stdout}, eagainReader{conn})
+		if err != nil && logFile != nil {
+			logFile.WriteString(fmt.Sprintf("Error while copying from stdout to unix domain socket \"%s\": %s.\n", args[1], err))
+		}
 		conn.Close()
 		wg.Done()
 	}()
 
 	go func() {
-		io.Copy(conn, os.Stdin)
+		_, err := io.Copy(eagainWriter{conn}, eagainReader{os.Stdin})
+		if err != nil && logFile != nil {
+			logFile.WriteString(fmt.Sprintf("Error while copying from unix domain socket \"%s\" to stdin: %s.\n", args[1], err))
+		}
 	}()
 
 	wg.Wait()
@@ -54,27 +97,15 @@ type eagainReader struct {
 }
 
 func (er eagainReader) Read(p []byte) (int, error) {
-	// keep retrying on EAGAIN
 again:
 	n, err := er.r.Read(p)
 	if err == nil {
 		return n, nil
 	}
 
-	var errno error
-	// EAGAIN errors can hide in os.PathError. My best explanation for this
-	// weirdness is that os.Stdout refers to /dev/stdout which is a path.
-	sysErr, ok := err.(*os.PathError)
-	if ok {
-		errno = sysErr.Err
-	} else {
-		tmpErrno, ok := err.(syscall.Errno)
-		if ok {
-			errno = tmpErrno
-		}
-	}
-
-	if errno == syscall.EAGAIN {
+	// keep retrying on EAGAIN
+	errno, ok := shared.GetErrno(err)
+	if ok && errno == syscall.EAGAIN {
 		goto again
 	}
 
@@ -86,26 +117,15 @@ type eagainWriter struct {
 }
 
 func (ew eagainWriter) Write(p []byte) (int, error) {
-	// keep retrying on EAGAIN
 again:
 	n, err := ew.w.Write(p)
 	if err == nil {
 		return n, nil
 	}
 
-	var errno error
-	// EAGAIN errors can hide in os.PathError. My best explanation for this
-	// weirdness is that os.Stdout refers to /dev/stdout which is a path.
-	sysErr, ok := err.(*os.PathError)
-	if ok {
-		errno = sysErr.Err
-	} else {
-		tmpErrno, ok := err.(syscall.Errno)
-		if ok {
-			errno = tmpErrno
-		}
-	}
-	if errno == syscall.EAGAIN {
+	// keep retrying on EAGAIN
+	errno, ok := shared.GetErrno(err)
+	if ok && errno == syscall.EAGAIN {
 		goto again
 	}
 

From 9ce1ac2c5faf8fee0f3ab7399b3f220f864320a3 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 20 Apr 2017 14:13:10 +0200
Subject: [PATCH 3/3] netcat: implement logging

Closes #2494.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/migrate.go           | 3 ++-
 lxd/rsync.go             | 9 +++++----
 lxd/storage_migration.go | 8 +++++---
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/lxd/migrate.go b/lxd/migrate.go
index 1a8ad44..bba9a77 100644
--- a/lxd/migrate.go
+++ b/lxd/migrate.go
@@ -522,7 +522,8 @@ func (s *migrationSourceWs) Do(migrateOp *operation) error {
 		 * no reason to do these in parallel. In the future when we're using
 		 * p.haul's protocol, it will make sense to do these in parallel.
 		 */
-		err = RsyncSend(shared.AddSlash(checkpointDir), s.criuConn, nil, bwlimit)
+		ctName := s.container.Name()
+		err = RsyncSend(ctName, shared.AddSlash(checkpointDir), s.criuConn, nil, bwlimit)
 		if err != nil {
 			return abort(err)
 		}
diff --git a/lxd/rsync.go b/lxd/rsync.go
index 44775f4..6d262fe 100644
--- a/lxd/rsync.go
+++ b/lxd/rsync.go
@@ -43,12 +43,13 @@ func rsyncLocalCopy(source string, dest string, bwlimit string) (string, error)
 		dest)
 }
 
-func rsyncSendSetup(path string, bwlimit string) (*exec.Cmd, net.Conn, io.ReadCloser, error) {
+func rsyncSendSetup(name string, path string, bwlimit string) (*exec.Cmd, net.Conn, io.ReadCloser, error) {
 	/*
 	 * It's sort of unfortunate, but there's no library call to get a
 	 * temporary name, so we get the file and close it and use its name.
 	 */
-	f, err := ioutil.TempFile("", "lxd_rsync_")
+	tmp := fmt.Sprintf("lxd_%s_rsync_", name)
+	f, err := ioutil.TempFile("", tmp)
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -124,8 +125,8 @@ func rsyncSendSetup(path string, bwlimit string) (*exec.Cmd, net.Conn, io.ReadCl
 
 // RsyncSend sets up the sending half of an rsync, to recursively send the
 // directory pointed to by path over the websocket.
-func RsyncSend(path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, bwlimit string) error {
-	cmd, dataSocket, stderr, err := rsyncSendSetup(path, bwlimit)
+func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, bwlimit string) error {
+	cmd, dataSocket, stderr, err := rsyncSendSetup(name, path, bwlimit)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/storage_migration.go b/lxd/storage_migration.go
index b207374..ba0babd 100644
--- a/lxd/storage_migration.go
+++ b/lxd/storage_migration.go
@@ -41,6 +41,7 @@ func (s rsyncStorageSourceDriver) Snapshots() []container {
 }
 
 func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *operation, bwlimit string) error {
+	ctName := s.container.Name()
 	for _, send := range s.snapshots {
 		ourStart, err := send.StorageStart()
 		if err != nil {
@@ -52,19 +53,20 @@ func (s rsyncStorageSourceDriver) SendWhileRunning(conn *websocket.Conn, op *ope
 
 		path := send.Path()
 		wrapper := StorageProgressReader(op, "fs_progress", send.Name())
-		err = RsyncSend(shared.AddSlash(path), conn, wrapper, bwlimit)
+		err = RsyncSend(ctName, shared.AddSlash(path), conn, wrapper, bwlimit)
 		if err != nil {
 			return err
 		}
 	}
 
 	wrapper := StorageProgressReader(op, "fs_progress", s.container.Name())
-	return RsyncSend(shared.AddSlash(s.container.Path()), conn, wrapper, bwlimit)
+	return RsyncSend(ctName, shared.AddSlash(s.container.Path()), conn, wrapper, bwlimit)
 }
 
 func (s rsyncStorageSourceDriver) SendAfterCheckpoint(conn *websocket.Conn, bwlimit string) error {
+	ctName := s.container.Name()
 	// resync anything that changed between our first send and the checkpoint
-	return RsyncSend(shared.AddSlash(s.container.Path()), conn, nil, bwlimit)
+	return RsyncSend(ctName, shared.AddSlash(s.container.Path()), conn, nil, bwlimit)
 }
 
 func (s rsyncStorageSourceDriver) Cleanup() {


More information about the lxc-devel mailing list