[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