[lxc-devel] [lxd/master] Better handle stdout/stderr during RunCommand

stgraber on Github lxc-bot at linuxcontainers.org
Thu Jul 11 18:12:59 UTC 2019


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/20190711/98831440/attachment-0001.bin>
-------------- next part --------------
From 56bddfc7868af7ee2030dd0b7e2eeb665beb2fd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 11 Jul 2019 11:33:35 -0400
Subject: [PATCH 1/2] shared: Better handle stdout/stderr in RunCommand
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/util.go | 32 ++++++++++++++++++++++++--------
 1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/shared/util.go b/shared/util.go
index d833d4e7f4..da6bd619cd 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -765,25 +765,41 @@ func RemoveDuplicatesFromString(s string, sep string) string {
 }
 
 type RunError struct {
-	msg string
-	Err error
+	msg    string
+	Err    error
+	Stdout string
+	Stderr string
 }
 
 func (e RunError) Error() string {
 	return e.msg
 }
 
-func RunCommand(name string, arg ...string) (string, error) {
-	output, err := exec.Command(name, arg...).CombinedOutput()
+func RunCommandSplit(name string, arg ...string) (string, string, error) {
+	cmd := exec.Command(name, arg...)
+
+	var stdout bytes.Buffer
+	var stderr bytes.Buffer
+	cmd.Stdout = &stdout
+	cmd.Stderr = &stderr
+
+	err := cmd.Run()
 	if err != nil {
 		err := RunError{
-			msg: fmt.Sprintf("Failed to run: %s %s: %s", name, strings.Join(arg, " "), strings.TrimSpace(string(output))),
-			Err: err,
+			msg:    fmt.Sprintf("Failed to run: %s %s: %s", name, strings.Join(arg, " "), strings.TrimSpace(string(stderr.Bytes()))),
+			Stdout: string(stdout.Bytes()),
+			Stderr: string(stderr.Bytes()),
+			Err:    err,
 		}
-		return string(output), err
+		return string(stdout.Bytes()), string(stderr.Bytes()), err
 	}
 
-	return string(output), nil
+	return string(stdout.Bytes()), string(stderr.Bytes()), nil
+}
+
+func RunCommand(name string, arg ...string) (string, error) {
+	stdout, _, err := RunCommandSplit(name, arg...)
+	return stdout, err
 }
 
 func RunCommandWithFds(stdin io.Reader, stdout io.Writer, name string, arg ...string) error {

From 9ecce230607eb7920ad5e3f13086e50c8b18d6d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 11 Jul 2019 12:27:44 -0400
Subject: [PATCH 2/2] lxd: Use RunCommandSplit when needed
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>
---
 lxd/container_lxc.go | 64 +++++++++++++-------------------------------
 lxd/seccomp.go       |  4 +--
 2 files changed, 20 insertions(+), 48 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 9f9f506189..934050cbef 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -2732,7 +2732,7 @@ func (c *containerLXC) detachInterfaceRename(netns string, ifName string, hostNa
 	lxdPID := os.Getpid()
 
 	// Run forknet detach
-	out, err := shared.RunCommand(
+	_, err := shared.RunCommand(
 		c.state.OS.ExecPath,
 		"forknet",
 		"detach",
@@ -2744,7 +2744,7 @@ func (c *containerLXC) detachInterfaceRename(netns string, ifName string, hostNa
 
 	// Process forknet detach response
 	if err != nil {
-		logger.Error("Error calling 'lxd forknet detach", log.Ctx{"container": c.name, "output": out, "netns": netns, "ifName": ifName, "hostName": hostName, "pid": lxdPID})
+		logger.Error("Error calling 'lxd forknet detach", log.Ctx{"container": c.name, "err": err, "netns": netns, "ifName": ifName, "hostName": hostName, "pid": lxdPID})
 	}
 
 	return nil
@@ -3173,20 +3173,12 @@ func (c *containerLXC) Start(stateful bool) error {
 	name := projectPrefix(c.Project(), c.name)
 
 	// Start the LXC container
-	out, err := shared.RunCommand(
+	_, err = shared.RunCommand(
 		c.state.OS.ExecPath,
 		"forkstart",
 		name,
 		c.state.OS.LxcPath,
 		configPath)
-
-	// Capture debug output
-	if out != "" {
-		for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
-			logger.Debugf("forkstart: %s", line)
-		}
-	}
-
 	if err != nil && !c.IsRunning() {
 		// Attempt to extract the LXC errors
 		lxcLog := ""
@@ -6328,8 +6320,7 @@ func (c *containerLXC) Migrate(args *CriuMigrationArgs) error {
 			finalStateDir = fmt.Sprintf("%s/%s", args.stateDir, args.dumpDir)
 		}
 
-		var out string
-		out, migrateErr = shared.RunCommand(
+		_, migrateErr = shared.RunCommand(
 			c.state.OS.ExecPath,
 			"forkmigrate",
 			c.name,
@@ -6338,12 +6329,6 @@ func (c *containerLXC) Migrate(args *CriuMigrationArgs) error {
 			finalStateDir,
 			fmt.Sprintf("%v", preservesInodes))
 
-		if out != "" {
-			for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
-				logger.Debugf("forkmigrate: %s", line)
-			}
-		}
-
 		if migrateErr == nil {
 			// Start proxy devices
 			err = c.restartProxyDevices()
@@ -6599,7 +6584,7 @@ func (c *containerLXC) FileExists(path string) error {
 	}
 
 	// Check if the file exists in the container
-	out, err := shared.RunCommand(
+	_, stderr, err := shared.RunCommandSplit(
 		c.state.OS.ExecPath,
 		"forkfile",
 		"exists",
@@ -6617,12 +6602,12 @@ func (c *containerLXC) FileExists(path string) error {
 	}
 
 	// Process forkcheckfile response
-	if out != "" {
-		if strings.HasPrefix(out, "error:") {
-			return fmt.Errorf(strings.TrimPrefix(strings.TrimSuffix(out, "\n"), "error: "))
+	if stderr != "" {
+		if strings.HasPrefix(stderr, "error:") {
+			return fmt.Errorf(strings.TrimPrefix(strings.TrimSuffix(stderr, "\n"), "error: "))
 		}
 
-		for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
+		for _, line := range strings.Split(strings.TrimRight(stderr, "\n"), "\n") {
 			logger.Debugf("forkcheckfile: %s", line)
 		}
 	}
@@ -6646,7 +6631,7 @@ func (c *containerLXC) FilePull(srcpath string, dstpath string) (int64, int64, o
 	}
 
 	// Get the file from the container
-	out, err := shared.RunCommand(
+	_, stderr, err := shared.RunCommandSplit(
 		c.state.OS.ExecPath,
 		"forkfile",
 		"pull",
@@ -6672,7 +6657,7 @@ func (c *containerLXC) FilePull(srcpath string, dstpath string) (int64, int64, o
 	var errStr string
 
 	// Process forkgetfile response
-	for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
+	for _, line := range strings.Split(strings.TrimRight(stderr, "\n"), "\n") {
 		if line == "" {
 			continue
 		}
@@ -6790,7 +6775,7 @@ func (c *containerLXC) FilePush(type_ string, srcpath string, dstpath string, ui
 	}
 
 	// Push the file to the container
-	out, err := shared.RunCommand(
+	_, stderr, err := shared.RunCommandSplit(
 		c.state.OS.ExecPath,
 		"forkfile",
 		"push",
@@ -6817,7 +6802,7 @@ func (c *containerLXC) FilePush(type_ string, srcpath string, dstpath string, ui
 	}
 
 	// Process forkgetfile response
-	for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
+	for _, line := range strings.Split(strings.TrimRight(stderr, "\n"), "\n") {
 		if line == "" {
 			continue
 		}
@@ -6859,7 +6844,7 @@ func (c *containerLXC) FileRemove(path string) error {
 	}
 
 	// Remove the file from the container
-	out, err := shared.RunCommand(
+	_, stderr, err := shared.RunCommandSplit(
 		c.state.OS.ExecPath,
 		"forkfile",
 		"remove",
@@ -6877,7 +6862,7 @@ func (c *containerLXC) FileRemove(path string) error {
 	}
 
 	// Process forkremovefile response
-	for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
+	for _, line := range strings.Split(strings.TrimRight(stderr, "\n"), "\n") {
 		if line == "" {
 			continue
 		}
@@ -7169,7 +7154,7 @@ func (c *containerLXC) networkState() map[string]api.ContainerStateNetwork {
 
 		// Process forkgetnet response
 		if err != nil {
-			logger.Error("Error calling 'lxd forkgetnet", log.Ctx{"container": c.name, "output": out, "pid": pid})
+			logger.Error("Error calling 'lxd forkgetnet", log.Ctx{"container": c.name, "err": err, "pid": pid})
 			return result
 		}
 
@@ -7344,13 +7329,7 @@ func (c *containerLXC) insertMountLXD(source, target, fstype string, flags int,
 	mntsrc := filepath.Join("/dev/.lxd-mounts", filepath.Base(tmpMount))
 	pidStr := fmt.Sprintf("%d", pid)
 
-	out, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxd-mount", pidStr, mntsrc, target)
-
-	if out != "" {
-		for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
-			logger.Debugf("forkmount: %s", line)
-		}
-	}
+	_, err = shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxd-mount", pidStr, mntsrc, target)
 	if err != nil {
 		return err
 	}
@@ -7408,14 +7387,7 @@ func (c *containerLXC) removeMount(mount string) error {
 	} else {
 		// Remove the mount from the container
 		pidStr := fmt.Sprintf("%d", pid)
-		out, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxd-umount", pidStr, mount)
-
-		if out != "" {
-			for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
-				logger.Debugf("forkumount: %s", line)
-			}
-		}
-
+		_, err := shared.RunCommand(c.state.OS.ExecPath, "forkmount", "lxd-umount", pidStr, mount)
 		if err != nil {
 			return err
 		}
diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index 6e5a497e17..3654ecb5e8 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -793,12 +793,12 @@ func (s *SeccompServer) doMknod(c container, dev types.Device, requestPID int) (
 
 	prefixPath = strings.TrimPrefix(prefixPath, rootPath)
 	dev["hostpath"] = filepath.Join(c.RootfsPath(), rootPath, prefixPath, dev["path"])
-	errnoMsg, err := shared.RunCommand(util.GetExecPath(),
+	_, stderr, err := shared.RunCommandSplit(util.GetExecPath(),
 		"forkmknod", dev["pid"], dev["path"],
 		dev["mode_t"], dev["dev_t"], dev["hostpath"],
 		fmt.Sprintf("%d", uid), fmt.Sprintf("%d", gid))
 	if err != nil {
-		tmp, err2 := strconv.Atoi(errnoMsg)
+		tmp, err2 := strconv.Atoi(stderr)
 		if err2 == nil {
 			goErrno = -tmp
 		}


More information about the lxc-devel mailing list