Browse code

Use a custom pipe instead of stdin for sync net namespace

Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume.charmes@docker.com> (github: creack)

Guillaume J. Charmes authored on 2014/02/21 10:58:13
Showing 3 changed files
... ...
@@ -22,16 +22,20 @@ func execCommand(container *libcontainer.Container, args []string) (int, error)
22 22
 		return -1, err
23 23
 	}
24 24
 
25
-	command := createCommand(container, console, args)
26 25
 	// create a pipe so that we can syncronize with the namespaced process and
27 26
 	// pass the veth name to the child
28
-	inPipe, err := command.StdinPipe()
27
+	r, w, err := os.Pipe()
29 28
 	if err != nil {
30 29
 		return -1, err
31 30
 	}
31
+	system.UsetCloseOnExec(r.Fd())
32
+
33
+	command := createCommand(container, console, r.Fd(), args)
34
+
32 35
 	if err := command.Start(); err != nil {
33 36
 		return -1, err
34 37
 	}
38
+
35 39
 	if err := writePidFile(command); err != nil {
36 40
 		command.Process.Kill()
37 41
 		return -1, err
... ...
@@ -52,11 +56,11 @@ func execCommand(container *libcontainer.Container, args []string) (int, error)
52 52
 		if err != nil {
53 53
 			return -1, err
54 54
 		}
55
-		sendVethName(vethPair, inPipe)
55
+		sendVethName(vethPair, w)
56 56
 	}
57 57
 
58 58
 	// Sync with child
59
-	inPipe.Close()
59
+	w.Close()
60 60
 
61 61
 	go io.Copy(os.Stdout, master)
62 62
 	go io.Copy(master, os.Stdin)
... ...
@@ -163,8 +167,8 @@ func deletePidFile() error {
163 163
 // createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
164 164
 // defined on the container's configuration and use the current binary as the init with the
165 165
 // args provided
166
-func createCommand(container *libcontainer.Container, console string, args []string) *exec.Cmd {
167
-	command := exec.Command("nsinit", append([]string{"-console", console, "init"}, args...)...)
166
+func createCommand(container *libcontainer.Container, console string, pipe uintptr, args []string) *exec.Cmd {
167
+	command := exec.Command("nsinit", append([]string{"-console", console, "-pipe", fmt.Sprint(pipe), "init"}, args...)...)
168 168
 	command.SysProcAttr = &syscall.SysProcAttr{
169 169
 		Cloneflags: uintptr(getNamespaceFlags(container.Namespaces)),
170 170
 	}
... ...
@@ -8,20 +8,21 @@ import (
8 8
 	"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
9 9
 	"github.com/dotcloud/docker/pkg/libcontainer/network"
10 10
 	"github.com/dotcloud/docker/pkg/system"
11
+	"io"
11 12
 	"io/ioutil"
12 13
 	"os"
13 14
 	"path/filepath"
14 15
 	"syscall"
15 16
 )
16 17
 
17
-func initCommand(container *libcontainer.Container, console string, args []string) error {
18
+func initCommand(container *libcontainer.Container, console string, pipe io.ReadCloser, args []string) error {
18 19
 	rootfs, err := resolveRootfs()
19 20
 	if err != nil {
20 21
 		return err
21 22
 	}
22 23
 
23 24
 	// We always read this as it is a way to sync with the parent as well
24
-	tempVethName, err := getVethName()
25
+	tempVethName, err := getVethName(pipe)
25 26
 	if err != nil {
26 27
 		return err
27 28
 	}
... ...
@@ -164,8 +165,10 @@ func setupVethNetwork(config *libcontainer.Network, tempVethName string) error {
164 164
 // getVethName reads from Stdin the temp veth name
165 165
 // sent by the parent processes after the veth pair
166 166
 // has been created and setup
167
-func getVethName() (string, error) {
168
-	data, err := ioutil.ReadAll(os.Stdin)
167
+func getVethName(pipe io.ReadCloser) (string, error) {
168
+	defer pipe.Close()
169
+
170
+	data, err := ioutil.ReadAll(pipe)
169 171
 	if err != nil {
170 172
 		return "", fmt.Errorf("error reading from stdin %s", err)
171 173
 	}
... ...
@@ -18,6 +18,7 @@ var (
18 18
 
19 19
 func main() {
20 20
 	console := flag.String("console", "", "Console (pty slave) name")
21
+	pipeFd := flag.Int("pipe", 0, "sync pipe fd")
21 22
 	flag.Parse()
22 23
 
23 24
 	container, err := loadContainer()
... ...
@@ -50,7 +51,7 @@ func main() {
50 50
 		if flag.NArg() < 2 {
51 51
 			log.Fatal(ErrWrongArguments)
52 52
 		}
53
-		if err := initCommand(container, *console, flag.Args()[1:]); err != nil {
53
+		if err := initCommand(container, *console, os.NewFile(uintptr(*pipeFd), "pipe"), flag.Args()[1:]); err != nil {
54 54
 			log.Fatal(err)
55 55
 		}
56 56
 	default: