Browse code

Merge pull request #8988 from crosbymichael/update-libcontainer-nov1

Update libcontainer to fd6df76562137aa3b18e44b790c

Michael Crosby authored on 2014/11/07 04:02:29
Showing 35 changed files
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"github.com/docker/docker/pkg/reexec"
14 14
 	"github.com/docker/libcontainer"
15 15
 	"github.com/docker/libcontainer/namespaces"
16
-	"github.com/docker/libcontainer/syncpipe"
17 16
 )
18 17
 
19 18
 func init() {
... ...
@@ -48,12 +47,7 @@ func initializer() {
48 48
 		writeError(err)
49 49
 	}
50 50
 
51
-	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(*pipe))
52
-	if err != nil {
53
-		writeError(err)
54
-	}
55
-
56
-	if err := namespaces.Init(container, rootfs, *console, syncPipe, flag.Args()); err != nil {
51
+	if err := namespaces.Init(container, rootfs, *console, os.NewFile(uintptr(*pipe), "child"), flag.Args()); err != nil {
57 52
 		writeError(err)
58 53
 	}
59 54
 
... ...
@@ -3,10 +3,10 @@
3 3
 package native
4 4
 
5 5
 import (
6
+	"encoding/json"
6 7
 	"os"
7 8
 
8 9
 	"github.com/docker/libcontainer"
9
-	"github.com/docker/libcontainer/syncpipe"
10 10
 )
11 11
 
12 12
 func findUserArgs() []string {
... ...
@@ -21,15 +21,9 @@ func findUserArgs() []string {
21 21
 // loadConfigFromFd loads a container's config from the sync pipe that is provided by
22 22
 // fd 3 when running a process
23 23
 func loadConfigFromFd() (*libcontainer.Config, error) {
24
-	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
25
-	if err != nil {
26
-		return nil, err
27
-	}
28
-
29 24
 	var config *libcontainer.Config
30
-	if err := syncPipe.ReadFromParent(&config); err != nil {
25
+	if err := json.NewDecoder(os.NewFile(3, "child")).Decode(&config); err != nil {
31 26
 		return nil, err
32 27
 	}
33
-
34 28
 	return config, nil
35 29
 }
... ...
@@ -66,7 +66,7 @@ if [ "$1" = '--go' ]; then
66 66
 	mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
67 67
 fi
68 68
 
69
-clone git github.com/docker/libcontainer f60d7b9195f8dc0b5d343abbc3293da7c17bb11c
69
+clone git github.com/docker/libcontainer fd6df76562137aa3b18e44b790cb484fe2b6fa0b
70 70
 # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
71 71
 rm -rf src/github.com/docker/libcontainer/vendor
72 72
 eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
73 73
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+package logrus
1
+
2
+import (
3
+	"testing"
4
+	"time"
5
+)
6
+
7
+// smallFields is a small size data set for benchmarking
8
+var smallFields = Fields{
9
+	"foo":   "bar",
10
+	"baz":   "qux",
11
+	"one":   "two",
12
+	"three": "four",
13
+}
14
+
15
+// largeFields is a large size data set for benchmarking
16
+var largeFields = Fields{
17
+	"foo":       "bar",
18
+	"baz":       "qux",
19
+	"one":       "two",
20
+	"three":     "four",
21
+	"five":      "six",
22
+	"seven":     "eight",
23
+	"nine":      "ten",
24
+	"eleven":    "twelve",
25
+	"thirteen":  "fourteen",
26
+	"fifteen":   "sixteen",
27
+	"seventeen": "eighteen",
28
+	"nineteen":  "twenty",
29
+	"a":         "b",
30
+	"c":         "d",
31
+	"e":         "f",
32
+	"g":         "h",
33
+	"i":         "j",
34
+	"k":         "l",
35
+	"m":         "n",
36
+	"o":         "p",
37
+	"q":         "r",
38
+	"s":         "t",
39
+	"u":         "v",
40
+	"w":         "x",
41
+	"y":         "z",
42
+	"this":      "will",
43
+	"make":      "thirty",
44
+	"entries":   "yeah",
45
+}
46
+
47
+func BenchmarkSmallTextFormatter(b *testing.B) {
48
+	doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
49
+}
50
+
51
+func BenchmarkLargeTextFormatter(b *testing.B) {
52
+	doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
53
+}
54
+
55
+func BenchmarkSmallColoredTextFormatter(b *testing.B) {
56
+	doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
57
+}
58
+
59
+func BenchmarkLargeColoredTextFormatter(b *testing.B) {
60
+	doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
61
+}
62
+
63
+func BenchmarkSmallJSONFormatter(b *testing.B) {
64
+	doBenchmark(b, &JSONFormatter{}, smallFields)
65
+}
66
+
67
+func BenchmarkLargeJSONFormatter(b *testing.B) {
68
+	doBenchmark(b, &JSONFormatter{}, largeFields)
69
+}
70
+
71
+func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
72
+	entry := &Entry{
73
+		Time:    time.Time{},
74
+		Level:   InfoLevel,
75
+		Message: "message",
76
+		Data:    fields,
77
+	}
78
+	var d []byte
79
+	var err error
80
+	for i := 0; i < b.N; i++ {
81
+		d, err = formatter.Format(entry)
82
+		if err != nil {
83
+			b.Fatal(err)
84
+		}
85
+		b.SetBytes(int64(len(d)))
86
+	}
87
+}
0 88
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
1
+
2
+[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
3
+
4
+In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
5
+
6
+## Usage
7
+
8
+You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
9
+
10
+For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
11
+
12
+```go
13
+import (
14
+  "log/syslog"
15
+  "github.com/Sirupsen/logrus"
16
+  "github.com/Sirupsen/logrus/hooks/papertrail"
17
+)
18
+
19
+func main() {
20
+  log       := logrus.New()
21
+  hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
22
+
23
+  if err == nil {
24
+    log.Hooks.Add(hook)
25
+  }
26
+}
27
+```
0 28
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+package logrus_papertrail
1
+
2
+import (
3
+	"fmt"
4
+	"net"
5
+	"os"
6
+	"time"
7
+
8
+	"github.com/Sirupsen/logrus"
9
+)
10
+
11
+const (
12
+	format = "Jan 2 15:04:05"
13
+)
14
+
15
+// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
16
+type PapertrailHook struct {
17
+	Host    string
18
+	Port    int
19
+	AppName string
20
+	UDPConn net.Conn
21
+}
22
+
23
+// NewPapertrailHook creates a hook to be added to an instance of logger.
24
+func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
25
+	conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
26
+	return &PapertrailHook{host, port, appName, conn}, err
27
+}
28
+
29
+// Fire is called when a log event is fired.
30
+func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
31
+	date := time.Now().Format(format)
32
+	payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Data["level"], entry.Message)
33
+
34
+	bytesWritten, err := hook.UDPConn.Write([]byte(payload))
35
+	if err != nil {
36
+		fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
37
+		return err
38
+	}
39
+
40
+	return nil
41
+}
42
+
43
+// Levels returns the available logging levels.
44
+func (hook *PapertrailHook) Levels() []logrus.Level {
45
+	return []logrus.Level{
46
+		logrus.PanicLevel,
47
+		logrus.FatalLevel,
48
+		logrus.ErrorLevel,
49
+		logrus.WarnLevel,
50
+		logrus.InfoLevel,
51
+		logrus.DebugLevel,
52
+	}
53
+}
0 54
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+package logrus_papertrail
1
+
2
+import (
3
+	"fmt"
4
+	"testing"
5
+
6
+	"github.com/Sirupsen/logrus"
7
+	"github.com/stvp/go-udp-testing"
8
+)
9
+
10
+func TestWritingToUDP(t *testing.T) {
11
+	port := 16661
12
+	udp.SetAddr(fmt.Sprintf(":%d", port))
13
+
14
+	hook, err := NewPapertrailHook("localhost", port, "test")
15
+	if err != nil {
16
+		t.Errorf("Unable to connect to local UDP server.")
17
+	}
18
+
19
+	log := logrus.New()
20
+	log.Hooks.Add(hook)
21
+
22
+	udp.ShouldReceive(t, "foo", func() {
23
+		log.Info("foo")
24
+	})
25
+}
0 26
new file mode 100755
... ...
@@ -0,0 +1,9 @@
0
+image: dockercore/libcontainer
1
+script:
2
+# Setup the DockerInDocker environment.
3
+  - /dind
4
+  - sed -i 's!docker/docker!docker/libcontainer!' /go/src/github.com/docker/docker/hack/make/.validate
5
+  - bash /go/src/github.com/docker/docker/hack/make/validate-dco
6
+  - bash /go/src/github.com/docker/docker/hack/make/validate-gofmt
7
+  - export GOPATH="$GOPATH:/go:$(pwd)/vendor" # Drone mucks with our GOPATH
8
+  - make direct-test
0 9
deleted file mode 100644
... ...
@@ -1,36 +0,0 @@
1
-language: go
2
-go: 1.3
3
-
4
-# let us have pretty experimental Docker-based Travis workers
5
-sudo: false
6
-
7
-env:
8
-    - TRAVIS_GLOBAL_WTF=1
9
-    - _GOOS=linux _GOARCH=amd64 CGO_ENABLED=1
10
-    - _GOOS=linux _GOARCH=amd64 CGO_ENABLED=0
11
-#    - _GOOS=linux _GOARCH=386 CGO_ENABLED=1 # TODO add this once Travis can handle it (https://github.com/travis-ci/travis-ci/issues/2207#issuecomment-49625061)
12
-    - _GOOS=linux _GOARCH=386 CGO_ENABLED=0
13
-    - _GOOS=linux _GOARCH=arm CGO_ENABLED=0
14
-
15
-install:
16
-    - go get code.google.com/p/go.tools/cmd/cover
17
-    - mkdir -pv "${GOPATH%%:*}/src/github.com/docker" && [ -d "${GOPATH%%:*}/src/github.com/docker/libcontainer" ] || ln -sv "$(readlink -f .)" "${GOPATH%%:*}/src/github.com/docker/libcontainer"
18
-    - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then
19
-          gvm cross "$_GOOS" "$_GOARCH";
20
-          export GOOS="$_GOOS" GOARCH="$_GOARCH";
21
-      fi
22
-    - export GOPATH="$GOPATH:$(pwd)/vendor"
23
-    - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then go env; fi
24
-    - go get -d -v ./... # TODO remove this if /docker/docker gets purged from our includes
25
-    - if [ "$TRAVIS_GLOBAL_WTF" ]; then
26
-          export DOCKER_PATH="${GOPATH%%:*}/src/github.com/docker/docker";
27
-          mkdir -p "$DOCKER_PATH/hack/make";
28
-          ( cd "$DOCKER_PATH/hack/make" && wget -c 'https://raw.githubusercontent.com/docker/docker/master/hack/make/'{.validate,validate-dco,validate-gofmt} );
29
-          sed -i 's!docker/docker!docker/libcontainer!' "$DOCKER_PATH/hack/make/.validate";
30
-      fi
31
-
32
-script:
33
-    - if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-dco"; fi
34
-    - if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-gofmt"; fi
35
-    - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then make direct-build; fi
36
-    - if [ -z "$TRAVIS_GLOBAL_WTF" -a "$GOARCH" != 'arm' ]; then make direct-test-short; fi
... ...
@@ -2,5 +2,4 @@ Michael Crosby <michael@docker.com> (@crosbymichael)
2 2
 Rohit Jnagal <jnagal@google.com> (@rjnagal)
3 3
 Victor Marmol <vmarmol@google.com> (@vmarmol)
4 4
 Mrunal Patel <mpatel@redhat.com> (@mrunalp)
5
-.travis.yml: Tianon Gravi <admwiggin@gmail.com> (@tianon)
6 5
 update-vendor.sh: Tianon Gravi <admwiggin@gmail.com> (@tianon)
... ...
@@ -1,4 +1,4 @@
1
-## libcontainer - reference implementation for containers [![Build Status](https://travis-ci.org/docker/libcontainer.png?branch=master)](https://travis-ci.org/docker/libcontainer)
1
+## libcontainer - reference implementation for containers [![Build Status](https://ci.dockerproject.com/github.com/docker/libcontainer/status.svg?branch=master)](https://ci.dockerproject.com/github.com/docker/libcontainer) 
2 2
 
3 3
 ### Note on API changes:
4 4
 
... ...
@@ -57,7 +57,7 @@ func TestGetCgroupParamsInt(t *testing.T) {
57 57
 	if err != nil {
58 58
 		t.Fatal(err)
59 59
 	} else if value != 0 {
60
-		t.Fatalf("Expected %d to equal %f", value, 0)
60
+		t.Fatalf("Expected %d to equal %d", value, 0)
61 61
 	}
62 62
 
63 63
 	// Success with negative values lesser than min int64
... ...
@@ -70,7 +70,7 @@ func TestGetCgroupParamsInt(t *testing.T) {
70 70
 	if err != nil {
71 71
 		t.Fatal(err)
72 72
 	} else if value != 0 {
73
-		t.Fatalf("Expected %d to equal %f", value, 0)
73
+		t.Fatalf("Expected %d to equal %d", value, 0)
74 74
 	}
75 75
 
76 76
 	// Not a float.
... ...
@@ -43,6 +43,13 @@ var (
43 43
 	}
44 44
 )
45 45
 
46
+func newProp(name string, units interface{}) systemd.Property {
47
+	return systemd.Property{
48
+		Name:  name,
49
+		Value: dbus.MakeVariant(units),
50
+	}
51
+}
52
+
46 53
 func UseSystemd() bool {
47 54
 	s, err := os.Stat("/run/systemd/system")
48 55
 	if err != nil || !s.IsDir() {
... ...
@@ -99,27 +106,27 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
99 99
 	}
100 100
 
101 101
 	properties = append(properties,
102
-		systemd.Property{"Slice", dbus.MakeVariant(slice)},
103
-		systemd.Property{"Description", dbus.MakeVariant("docker container " + c.Name)},
104
-		systemd.Property{"PIDs", dbus.MakeVariant([]uint32{uint32(pid)})},
102
+		systemd.PropSlice(slice),
103
+		systemd.PropDescription("docker container "+c.Name),
104
+		newProp("PIDs", []uint32{uint32(pid)}),
105 105
 	)
106 106
 
107 107
 	// Always enable accounting, this gets us the same behaviour as the fs implementation,
108 108
 	// plus the kernel has some problems with joining the memory cgroup at a later time.
109 109
 	properties = append(properties,
110
-		systemd.Property{"MemoryAccounting", dbus.MakeVariant(true)},
111
-		systemd.Property{"CPUAccounting", dbus.MakeVariant(true)},
112
-		systemd.Property{"BlockIOAccounting", dbus.MakeVariant(true)})
110
+		newProp("MemoryAccounting", true),
111
+		newProp("CPUAccounting", true),
112
+		newProp("BlockIOAccounting", true))
113 113
 
114 114
 	if c.Memory != 0 {
115 115
 		properties = append(properties,
116
-			systemd.Property{"MemoryLimit", dbus.MakeVariant(uint64(c.Memory))})
116
+			newProp("MemoryLimit", uint64(c.Memory)))
117 117
 	}
118 118
 	// TODO: MemoryReservation and MemorySwap not available in systemd
119 119
 
120 120
 	if c.CpuShares != 0 {
121 121
 		properties = append(properties,
122
-			systemd.Property{"CPUShares", dbus.MakeVariant(uint64(c.CpuShares))})
122
+			newProp("CPUShares", uint64(c.CpuShares)))
123 123
 	}
124 124
 
125 125
 	if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
... ...
@@ -103,7 +103,7 @@ func getDeviceNodes(path string) ([]*Device, error) {
103 103
 		switch {
104 104
 		case f.IsDir():
105 105
 			switch f.Name() {
106
-			case "pts", "shm", "fd":
106
+			case "pts", "shm", "fd", "mqueue":
107 107
 				continue
108 108
 			default:
109 109
 				sub, err := getDeviceNodes(filepath.Join(path, f.Name()))
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"runtime"
7 7
 
8 8
 	"github.com/docker/libcontainer/namespaces"
9
-	"github.com/docker/libcontainer/syncpipe"
10 9
 )
11 10
 
12 11
 // init runs the libcontainer initialization code because of the busybox style needs
... ...
@@ -27,12 +26,7 @@ func init() {
27 27
 		log.Fatal(err)
28 28
 	}
29 29
 
30
-	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
31
-	if err != nil {
32
-		log.Fatalf("unable to create sync pipe: %s", err)
33
-	}
34
-
35
-	if err := namespaces.Init(container, rootfs, "", syncPipe, os.Args[3:]); err != nil {
30
+	if err := namespaces.Init(container, rootfs, "", os.NewFile(3, "pipe"), os.Args[3:]); err != nil {
36 31
 		log.Fatalf("unable to initialize for container: %s", err)
37 32
 	}
38 33
 	os.Exit(1)
... ...
@@ -43,3 +43,15 @@ func ReserveLabel(label string) error {
43 43
 func UnreserveLabel(label string) error {
44 44
 	return nil
45 45
 }
46
+
47
+// DupSecOpt takes an process label and returns security options that
48
+// can be used to set duplicate labels on future container processes
49
+func DupSecOpt(src string) []string {
50
+	return nil
51
+}
52
+
53
+// DisableSecOpt returns a security opt that can disable labeling
54
+// support for future container processes
55
+func DisableSecOpt() []string {
56
+	return nil
57
+}
... ...
@@ -17,7 +17,6 @@ func InitLabels(options []string) (string, string, error) {
17 17
 	if !selinux.SelinuxEnabled() {
18 18
 		return "", "", nil
19 19
 	}
20
-	var err error
21 20
 	processLabel, mountLabel := selinux.GetLxcContexts()
22 21
 	if processLabel != "" {
23 22
 		pcon := selinux.NewContext(processLabel)
... ...
@@ -38,7 +37,7 @@ func InitLabels(options []string) (string, string, error) {
38 38
 		processLabel = pcon.Get()
39 39
 		mountLabel = mcon.Get()
40 40
 	}
41
-	return processLabel, mountLabel, err
41
+	return processLabel, mountLabel, nil
42 42
 }
43 43
 
44 44
 // DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
... ...
@@ -130,3 +129,15 @@ func UnreserveLabel(label string) error {
130 130
 	selinux.FreeLxcContexts(label)
131 131
 	return nil
132 132
 }
133
+
134
+// DupSecOpt takes an process label and returns security options that
135
+// can be used to set duplicate labels on future container processes
136
+func DupSecOpt(src string) []string {
137
+	return selinux.DupSecOpt(src)
138
+}
139
+
140
+// DisableSecOpt returns a security opt that can disable labeling
141
+// support for future container processes
142
+func DisableSecOpt() []string {
143
+	return selinux.DisableSecOpt()
144
+}
... ...
@@ -3,6 +3,7 @@
3 3
 package label
4 4
 
5 5
 import (
6
+	"strings"
6 7
 	"testing"
7 8
 
8 9
 	"github.com/docker/libcontainer/selinux"
... ...
@@ -33,7 +34,7 @@ func TestInit(t *testing.T) {
33 33
 			t.Fatal(err)
34 34
 		}
35 35
 		if plabel != "user_u:user_r:user_t:s0:c1,c15" || mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15" {
36
-			t.Log("InitLabels User Failed")
36
+			t.Log("InitLabels User Match Failed")
37 37
 			t.Log(plabel, mlabel)
38 38
 			t.Fatal(err)
39 39
 		}
... ...
@@ -46,3 +47,43 @@ func TestInit(t *testing.T) {
46 46
 		}
47 47
 	}
48 48
 }
49
+func TestDuplicateLabel(t *testing.T) {
50
+	secopt := DupSecOpt("system_u:system_r:svirt_lxc_net_t:s0:c1,c2")
51
+	t.Log(secopt)
52
+	for _, opt := range secopt {
53
+		con := strings.SplitN(opt, ":", 3)
54
+		if len(con) != 3 || con[0] != "label" {
55
+			t.Errorf("Invalid DupSecOpt return value")
56
+			continue
57
+		}
58
+		if con[1] == "user" {
59
+			if con[2] != "system_u" {
60
+				t.Errorf("DupSecOpt Failed user incorrect")
61
+			}
62
+			continue
63
+		}
64
+		if con[1] == "role" {
65
+			if con[2] != "system_r" {
66
+				t.Errorf("DupSecOpt Failed role incorrect")
67
+			}
68
+			continue
69
+		}
70
+		if con[1] == "type" {
71
+			if con[2] != "svirt_lxc_net_t" {
72
+				t.Errorf("DupSecOpt Failed type incorrect")
73
+			}
74
+			continue
75
+		}
76
+		if con[1] == "level" {
77
+			if con[2] != "s0:c1,c2" {
78
+				t.Errorf("DupSecOpt Failed level incorrect")
79
+			}
80
+			continue
81
+		}
82
+		t.Errorf("DupSecOpt Failed invalid field %q", con[1])
83
+	}
84
+	secopt = DisableSecOpt()
85
+	if secopt[0] != "label:disable" {
86
+		t.Errorf("DisableSecOpt Failed level incorrect")
87
+	}
88
+}
... ...
@@ -97,7 +97,7 @@ func InitializeMountNamespace(rootfs, console string, sysReadonly bool, mountCon
97 97
 	return nil
98 98
 }
99 99
 
100
-// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
100
+// mountSystem sets up linux specific system mounts like mqueue, sys, proc, shm, and devpts
101 101
 // inside the mount namespace
102 102
 func mountSystem(rootfs string, sysReadonly bool, mountConfig *MountConfig) error {
103 103
 	for _, m := range newSystemMounts(rootfs, mountConfig.MountLabel, sysReadonly) {
... ...
@@ -168,6 +168,7 @@ func newSystemMounts(rootfs, mountLabel string, sysReadonly bool) []mount {
168 168
 		{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
169 169
 		{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: label.FormatMountLabel("mode=755", mountLabel)},
170 170
 		{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1777,size=65536k", mountLabel)},
171
+		{source: "mqueue", path: filepath.Join(rootfs, "dev", "mqueue"), device: "mqueue", flags: defaultMountFlags},
171 172
 		{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: label.FormatMountLabel("newinstance,ptmxmode=0666,mode=620,gid=5", mountLabel)},
172 173
 	}
173 174
 
... ...
@@ -3,6 +3,7 @@
3 3
 package namespaces
4 4
 
5 5
 import (
6
+	"encoding/json"
6 7
 	"io"
7 8
 	"os"
8 9
 	"os/exec"
... ...
@@ -13,7 +14,6 @@ import (
13 13
 	"github.com/docker/libcontainer/cgroups/fs"
14 14
 	"github.com/docker/libcontainer/cgroups/systemd"
15 15
 	"github.com/docker/libcontainer/network"
16
-	"github.com/docker/libcontainer/syncpipe"
17 16
 	"github.com/docker/libcontainer/system"
18 17
 )
19 18
 
... ...
@@ -22,19 +22,17 @@ import (
22 22
 // Exec performs setup outside of a namespace so that a container can be
23 23
 // executed.  Exec is a high level function for working with container namespaces.
24 24
 func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
25
-	var (
26
-		err error
27
-	)
25
+	var err error
28 26
 
29 27
 	// create a pipe so that we can syncronize with the namespaced process and
30
-	// pass the veth name to the child
31
-	syncPipe, err := syncpipe.NewSyncPipe()
28
+	// pass the state and configuration to the child process
29
+	parent, child, err := newInitPipe()
32 30
 	if err != nil {
33 31
 		return -1, err
34 32
 	}
35
-	defer syncPipe.Close()
33
+	defer parent.Close()
36 34
 
37
-	command := createCommand(container, console, dataPath, os.Args[0], syncPipe.Child(), args)
35
+	command := createCommand(container, console, dataPath, os.Args[0], child, args)
38 36
 	// Note: these are only used in non-tty mode
39 37
 	// if there is a tty for the container it will be opened within the namespace and the
40 38
 	// fds will be duped to stdin, stdiout, and stderr
... ...
@@ -43,39 +41,47 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
43 43
 	command.Stderr = stderr
44 44
 
45 45
 	if err := command.Start(); err != nil {
46
+		child.Close()
46 47
 		return -1, err
47 48
 	}
49
+	child.Close()
48 50
 
49
-	// Now we passed the pipe to the child, close our side
50
-	syncPipe.CloseChild()
51
+	terminate := func(terr error) (int, error) {
52
+		// TODO: log the errors for kill and wait
53
+		command.Process.Kill()
54
+		command.Wait()
55
+		return -1, terr
56
+	}
51 57
 
52 58
 	started, err := system.GetProcessStartTime(command.Process.Pid)
53 59
 	if err != nil {
54
-		return -1, err
60
+		return terminate(err)
55 61
 	}
56 62
 
57 63
 	// Do this before syncing with child so that no children
58 64
 	// can escape the cgroup
59 65
 	cgroupRef, err := SetupCgroups(container, command.Process.Pid)
60 66
 	if err != nil {
61
-		command.Process.Kill()
62
-		command.Wait()
63
-		return -1, err
67
+		return terminate(err)
64 68
 	}
65 69
 	defer cgroupRef.Cleanup()
66 70
 
67 71
 	cgroupPaths, err := cgroupRef.Paths()
68 72
 	if err != nil {
69
-		command.Process.Kill()
70
-		command.Wait()
71
-		return -1, err
73
+		return terminate(err)
72 74
 	}
73 75
 
74 76
 	var networkState network.NetworkState
75
-	if err := InitializeNetworking(container, command.Process.Pid, syncPipe, &networkState); err != nil {
76
-		command.Process.Kill()
77
-		command.Wait()
78
-		return -1, err
77
+	if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil {
78
+		return terminate(err)
79
+	}
80
+	// send the state to the container's init process then shutdown writes for the parent
81
+	if err := json.NewEncoder(parent).Encode(networkState); err != nil {
82
+		return terminate(err)
83
+	}
84
+	// shutdown writes for the parent side of the pipe
85
+	if err := syscall.Shutdown(int(parent.Fd()), syscall.SHUT_WR); err != nil {
86
+		return terminate(err)
79 87
 	}
80 88
 
81 89
 	state := &libcontainer.State{
... ...
@@ -86,17 +92,18 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
86 86
 	}
87 87
 
88 88
 	if err := libcontainer.SaveState(dataPath, state); err != nil {
89
-		command.Process.Kill()
90
-		command.Wait()
91
-		return -1, err
89
+		return terminate(err)
92 90
 	}
93 91
 	defer libcontainer.DeleteState(dataPath)
94 92
 
95
-	// Sync with child
96
-	if err := syncPipe.ReadFromChild(); err != nil {
97
-		command.Process.Kill()
98
-		command.Wait()
99
-		return -1, err
93
+	// wait for the child process to fully complete and receive an error message
94
+	// if one was encoutered
95
+	var ierr *initError
96
+	if err := json.NewDecoder(parent).Decode(&ierr); err != nil && err != io.EOF {
97
+		return terminate(err)
98
+	}
99
+	if ierr != nil {
100
+		return terminate(ierr)
100 101
 	}
101 102
 
102 103
 	if startCallback != nil {
... ...
@@ -108,7 +115,6 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
108 108
 			return -1, err
109 109
 		}
110 110
 	}
111
-
112 111
 	return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
113 112
 }
114 113
 
... ...
@@ -129,16 +135,6 @@ func DefaultCreateCommand(container *libcontainer.Config, console, dataPath, ini
129 129
 		"data_path=" + dataPath,
130 130
 	}
131 131
 
132
-	/*
133
-	   TODO: move user and wd into env
134
-	   if user != "" {
135
-	       env = append(env, "user="+user)
136
-	   }
137
-	   if workingDir != "" {
138
-	       env = append(env, "wd="+workingDir)
139
-	   }
140
-	*/
141
-
142 132
 	command := exec.Command(init, append([]string{"init", "--"}, args...)...)
143 133
 	// make sure the process is executed inside the context of the rootfs
144 134
 	command.Dir = container.RootFs
... ...
@@ -173,7 +169,7 @@ func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgro
173 173
 
174 174
 // InitializeNetworking creates the container's network stack outside of the namespace and moves
175 175
 // interfaces into the container's net namespaces if necessary
176
-func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *syncpipe.SyncPipe, networkState *network.NetworkState) error {
176
+func InitializeNetworking(container *libcontainer.Config, nspid int, networkState *network.NetworkState) error {
177 177
 	for _, config := range container.Networks {
178 178
 		strategy, err := network.GetStrategy(config.Type)
179 179
 		if err != nil {
... ...
@@ -183,18 +179,5 @@ func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *syncp
183 183
 			return err
184 184
 		}
185 185
 	}
186
-	return pipe.SendToChild(networkState)
187
-}
188
-
189
-// GetNamespaceFlags parses the container's Namespaces options to set the correct
190
-// flags on clone, unshare, and setns
191
-func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
192
-	for key, enabled := range namespaces {
193
-		if enabled {
194
-			if ns := GetNamespace(key); ns != nil {
195
-				flag |= ns.Value
196
-			}
197
-		}
198
-	}
199
-	return flag
186
+	return nil
200 187
 }
... ...
@@ -3,6 +3,7 @@
3 3
 package namespaces
4 4
 
5 5
 import (
6
+	"encoding/json"
6 7
 	"fmt"
7 8
 	"io"
8 9
 	"os"
... ...
@@ -15,7 +16,6 @@ import (
15 15
 	"github.com/docker/libcontainer/apparmor"
16 16
 	"github.com/docker/libcontainer/cgroups"
17 17
 	"github.com/docker/libcontainer/label"
18
-	"github.com/docker/libcontainer/syncpipe"
19 18
 	"github.com/docker/libcontainer/system"
20 19
 )
21 20
 
... ...
@@ -41,11 +41,11 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
41 41
 		}
42 42
 	}
43 43
 
44
-	pipe, err := syncpipe.NewSyncPipe()
44
+	parent, child, err := newInitPipe()
45 45
 	if err != nil {
46 46
 		return -1, err
47 47
 	}
48
-	defer pipe.Close()
48
+	defer parent.Close()
49 49
 
50 50
 	// Note: these are only used in non-tty mode
51 51
 	// if there is a tty for the container it will be opened within the namespace and the
... ...
@@ -53,23 +53,28 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
53 53
 	cmd.Stdin = stdin
54 54
 	cmd.Stdout = stdout
55 55
 	cmd.Stderr = stderr
56
-
57
-	cmd.ExtraFiles = []*os.File{pipe.Child()}
56
+	cmd.ExtraFiles = []*os.File{child}
58 57
 
59 58
 	if err := cmd.Start(); err != nil {
59
+		child.Close()
60 60
 		return -1, err
61 61
 	}
62
-	pipe.CloseChild()
62
+	child.Close()
63
+
64
+	terminate := func(terr error) (int, error) {
65
+		// TODO: log the errors for kill and wait
66
+		cmd.Process.Kill()
67
+		cmd.Wait()
68
+		return -1, terr
69
+	}
63 70
 
64 71
 	// Enter cgroups.
65 72
 	if err := EnterCgroups(state, cmd.Process.Pid); err != nil {
66
-		return -1, err
73
+		return terminate(err)
67 74
 	}
68 75
 
69
-	if err := pipe.SendToChild(container); err != nil {
70
-		cmd.Process.Kill()
71
-		cmd.Wait()
72
-		return -1, err
76
+	if err := json.NewEncoder(parent).Encode(container); err != nil {
77
+		return terminate(err)
73 78
 	}
74 79
 
75 80
 	if startCallback != nil {
... ...
@@ -81,7 +86,6 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
81 81
 			return -1, err
82 82
 		}
83 83
 	}
84
-
85 84
 	return cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
86 85
 }
87 86
 
... ...
@@ -3,7 +3,9 @@
3 3
 package namespaces
4 4
 
5 5
 import (
6
+	"encoding/json"
6 7
 	"fmt"
8
+	"io/ioutil"
7 9
 	"os"
8 10
 	"strings"
9 11
 	"syscall"
... ...
@@ -18,7 +20,6 @@ import (
18 18
 	"github.com/docker/libcontainer/network"
19 19
 	"github.com/docker/libcontainer/security/capabilities"
20 20
 	"github.com/docker/libcontainer/security/restrict"
21
-	"github.com/docker/libcontainer/syncpipe"
22 21
 	"github.com/docker/libcontainer/system"
23 22
 	"github.com/docker/libcontainer/user"
24 23
 	"github.com/docker/libcontainer/utils"
... ...
@@ -30,11 +31,22 @@ import (
30 30
 // and other options required for the new container.
31 31
 // The caller of Init function has to ensure that the go runtime is locked to an OS thread
32 32
 // (using runtime.LockOSThread) else system calls like setns called within Init may not work as intended.
33
-func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *syncpipe.SyncPipe, args []string) (err error) {
33
+func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, pipe *os.File, args []string) (err error) {
34 34
 	defer func() {
35
+		// if we have an error during the initialization of the container's init then send it back to the
36
+		// parent process in the form of an initError.
35 37
 		if err != nil {
36
-			syncPipe.ReportChildError(err)
38
+			// ensure that any data sent from the parent is consumed so it doesn't
39
+			// receive ECONNRESET when the child writes to the pipe.
40
+			ioutil.ReadAll(pipe)
41
+			if err := json.NewEncoder(pipe).Encode(initError{
42
+				Message: err.Error(),
43
+			}); err != nil {
44
+				panic(err)
45
+			}
37 46
 		}
47
+		// ensure that this pipe is always closed
48
+		pipe.Close()
38 49
 	}()
39 50
 
40 51
 	rootfs, err := utils.ResolveRootfs(uncleanRootfs)
... ...
@@ -50,7 +62,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn
50 50
 
51 51
 	// We always read this as it is a way to sync with the parent as well
52 52
 	var networkState *network.NetworkState
53
-	if err := syncPipe.ReadFromParent(&networkState); err != nil {
53
+	if err := json.NewDecoder(pipe).Decode(&networkState); err != nil {
54 54
 		return err
55 55
 	}
56 56
 
... ...
@@ -164,11 +176,11 @@ func SetupUser(u string) error {
164 164
 		return fmt.Errorf("setgroups %s", err)
165 165
 	}
166 166
 
167
-	if err := syscall.Setgid(gid); err != nil {
167
+	if err := system.Setgid(gid); err != nil {
168 168
 		return fmt.Errorf("setgid %s", err)
169 169
 	}
170 170
 
171
-	if err := syscall.Setuid(uid); err != nil {
171
+	if err := system.Setuid(uid); err != nil {
172 172
 		return fmt.Errorf("setuid %s", err)
173 173
 	}
174 174
 
175 175
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+// +build linux
1
+
2
+package namespaces
3
+
4
+import (
5
+	"os"
6
+	"syscall"
7
+)
8
+
9
+type initError struct {
10
+	Message string `json:"message,omitempty"`
11
+}
12
+
13
+func (i initError) Error() string {
14
+	return i.Message
15
+}
16
+
17
+// New returns a newly initialized Pipe for communication between processes
18
+func newInitPipe() (parent *os.File, child *os.File, err error) {
19
+	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
20
+	if err != nil {
21
+		return nil, nil, err
22
+	}
23
+	return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
24
+}
25
+
26
+// GetNamespaceFlags parses the container's Namespaces options to set the correct
27
+// flags on clone, unshare, and setns
28
+func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
29
+	for key, enabled := range namespaces {
30
+		if enabled {
31
+			if ns := GetNamespace(key); ns != nil {
32
+				flag |= ns.Value
33
+			}
34
+		}
35
+	}
36
+	return flag
37
+}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"math/rand"
8 8
 	"net"
9 9
 	"os"
10
+	"path/filepath"
10 11
 	"sync/atomic"
11 12
 	"syscall"
12 13
 	"unsafe"
... ...
@@ -1204,6 +1205,28 @@ func SetMacAddress(name, addr string) error {
1204 1204
 	return nil
1205 1205
 }
1206 1206
 
1207
+func SetHairpinMode(iface *net.Interface, enabled bool) error {
1208
+	sysPath := filepath.Join("/sys/class/net", iface.Name, "brport/hairpin_mode")
1209
+
1210
+	sysFile, err := os.OpenFile(sysPath, os.O_WRONLY, 0)
1211
+	if err != nil {
1212
+		return err
1213
+	}
1214
+	defer sysFile.Close()
1215
+
1216
+	var writeVal []byte
1217
+	if enabled {
1218
+		writeVal = []byte("1")
1219
+	} else {
1220
+		writeVal = []byte("0")
1221
+	}
1222
+	if _, err := sysFile.Write(writeVal); err != nil {
1223
+		return err
1224
+	}
1225
+
1226
+	return nil
1227
+}
1228
+
1207 1229
 func ChangeName(iface *net.Interface, newName string) error {
1208 1230
 	if len(newName) >= IFNAMSIZ {
1209 1231
 		return fmt.Errorf("Interface name %s too long", newName)
... ...
@@ -1224,5 +1247,6 @@ func ChangeName(iface *net.Interface, newName string) error {
1224 1224
 	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
1225 1225
 		return errno
1226 1226
 	}
1227
+
1227 1228
 	return nil
1228 1229
 }
... ...
@@ -116,7 +116,7 @@ func TestNetworkSetMacAddress(t *testing.T) {
116 116
 	ifcBeforeSet := readLink(t, tl.name)
117 117
 
118 118
 	if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil {
119
-		t.Fatalf("Could not set %s MAC address on %#v interface: err", macaddr, tl, err)
119
+		t.Fatalf("Could not set %s MAC address on %#v interface: %s", macaddr, tl, err)
120 120
 	}
121 121
 
122 122
 	ifcAfterSet := readLink(t, tl.name)
... ...
@@ -140,7 +140,7 @@ func TestNetworkSetMTU(t *testing.T) {
140 140
 	ifcBeforeSet := readLink(t, tl.name)
141 141
 
142 142
 	if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil {
143
-		t.Fatalf("Could not set %d MTU on %#v interface: err", mtu, tl, err)
143
+		t.Fatalf("Could not set %d MTU on %#v interface: %s", mtu, tl, err)
144 144
 	}
145 145
 
146 146
 	ifcAfterSet := readLink(t, tl.name)
... ...
@@ -95,3 +95,11 @@ func SetMtu(name string, mtu int) error {
95 95
 	}
96 96
 	return netlink.NetworkSetMTU(iface, mtu)
97 97
 }
98
+
99
+func SetHairpinMode(name string, enabled bool) error {
100
+	iface, err := net.InterfaceByName(name)
101
+	if err != nil {
102
+		return err
103
+	}
104
+	return netlink.SetHairpinMode(iface, enabled)
105
+}
... ...
@@ -39,6 +39,9 @@ func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error {
39 39
 	if err := SetMtu(name1, n.Mtu); err != nil {
40 40
 		return err
41 41
 	}
42
+	if err := SetHairpinMode(name1, true); err != nil {
43
+		return err
44
+	}
42 45
 	if err := InterfaceUp(name1); err != nil {
43 46
 		return err
44 47
 	}
... ...
@@ -8,7 +8,6 @@ import (
8 8
 
9 9
 	"github.com/codegangsta/cli"
10 10
 	"github.com/docker/libcontainer/namespaces"
11
-	"github.com/docker/libcontainer/syncpipe"
12 11
 )
13 12
 
14 13
 var (
... ...
@@ -41,12 +40,8 @@ func initAction(context *cli.Context) {
41 41
 		log.Fatal(err)
42 42
 	}
43 43
 
44
-	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(pipeFd))
45
-	if err != nil {
46
-		log.Fatalf("unable to create sync pipe: %s", err)
47
-	}
48
-
49
-	if err := namespaces.Init(container, rootfs, console, syncPipe, []string(context.Args())); err != nil {
44
+	pipe := os.NewFile(uintptr(pipeFd), "pipe")
45
+	if err := namespaces.Init(container, rootfs, console, pipe, []string(context.Args())); err != nil {
50 46
 		log.Fatalf("unable to initialize for container: %s", err)
51 47
 	}
52 48
 }
... ...
@@ -8,7 +8,6 @@ import (
8 8
 
9 9
 	"github.com/codegangsta/cli"
10 10
 	"github.com/docker/libcontainer"
11
-	"github.com/docker/libcontainer/syncpipe"
12 11
 )
13 12
 
14 13
 // rFunc is a function registration for calling after an execin
... ...
@@ -59,16 +58,13 @@ func findUserArgs() []string {
59 59
 // loadConfigFromFd loads a container's config from the sync pipe that is provided by
60 60
 // fd 3 when running a process
61 61
 func loadConfigFromFd() (*libcontainer.Config, error) {
62
-	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
63
-	if err != nil {
64
-		return nil, err
65
-	}
62
+	pipe := os.NewFile(3, "pipe")
63
+	defer pipe.Close()
66 64
 
67 65
 	var config *libcontainer.Config
68
-	if err := syncPipe.ReadFromParent(&config); err != nil {
66
+	if err := json.NewDecoder(pipe).Decode(&config); err != nil {
69 67
 		return nil, err
70 68
 	}
71
-
72 69
 	return config, nil
73 70
 }
74 71
 
... ...
@@ -434,3 +434,28 @@ func Chcon(fpath string, scon string, recurse bool) error {
434 434
 
435 435
 	return Setfilecon(fpath, scon)
436 436
 }
437
+
438
+// DupSecOpt takes an SELinux process label and returns security options that
439
+// can will set the SELinux Type and Level for future container processes
440
+func DupSecOpt(src string) []string {
441
+	if src == "" {
442
+		return nil
443
+	}
444
+	con := NewContext(src)
445
+	if con["user"] == "" ||
446
+		con["role"] == "" ||
447
+		con["type"] == "" ||
448
+		con["level"] == "" {
449
+		return nil
450
+	}
451
+	return []string{"label:user:" + con["user"],
452
+		"label:role:" + con["role"],
453
+		"label:type:" + con["type"],
454
+		"label:level:" + con["level"]}
455
+}
456
+
457
+// DisableSecOpt returns a security opt that can be used to disabling SELinux
458
+// labeling support for future container processes
459
+func DisableSecOpt() []string {
460
+	return []string{"label:disable"}
461
+}
... ...
@@ -42,7 +42,7 @@ func TestSELinux(t *testing.T) {
42 42
 		t.Log("getenforce ", selinux.SelinuxGetEnforce())
43 43
 		t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
44 44
 		pid := os.Getpid()
45
-		t.Log("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
45
+		t.Logf("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
46 46
 		err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
47 47
 		if err == nil {
48 48
 			t.Log(selinux.Getfscreatecon())
49 49
deleted file mode 100644
... ...
@@ -1,105 +0,0 @@
1
-package syncpipe
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"io/ioutil"
7
-	"os"
8
-	"syscall"
9
-)
10
-
11
-// SyncPipe allows communication to and from the child processes
12
-// to it's parent and allows the two independent processes to
13
-// syncronize their state.
14
-type SyncPipe struct {
15
-	parent, child *os.File
16
-}
17
-
18
-func NewSyncPipeFromFd(parentFd, childFd uintptr) (*SyncPipe, error) {
19
-	s := &SyncPipe{}
20
-
21
-	if parentFd > 0 {
22
-		s.parent = os.NewFile(parentFd, "parentPipe")
23
-	} else if childFd > 0 {
24
-		s.child = os.NewFile(childFd, "childPipe")
25
-	} else {
26
-		return nil, fmt.Errorf("no valid sync pipe fd specified")
27
-	}
28
-
29
-	return s, nil
30
-}
31
-
32
-func (s *SyncPipe) Child() *os.File {
33
-	return s.child
34
-}
35
-
36
-func (s *SyncPipe) Parent() *os.File {
37
-	return s.parent
38
-}
39
-
40
-func (s *SyncPipe) SendToChild(v interface{}) error {
41
-	data, err := json.Marshal(v)
42
-	if err != nil {
43
-		return err
44
-	}
45
-
46
-	s.parent.Write(data)
47
-
48
-	return syscall.Shutdown(int(s.parent.Fd()), syscall.SHUT_WR)
49
-}
50
-
51
-func (s *SyncPipe) ReadFromChild() error {
52
-	data, err := ioutil.ReadAll(s.parent)
53
-	if err != nil {
54
-		return err
55
-	}
56
-
57
-	if len(data) > 0 {
58
-		return fmt.Errorf("%s", data)
59
-	}
60
-
61
-	return nil
62
-}
63
-
64
-func (s *SyncPipe) ReadFromParent(v interface{}) error {
65
-	data, err := ioutil.ReadAll(s.child)
66
-	if err != nil {
67
-		return fmt.Errorf("error reading from sync pipe %s", err)
68
-	}
69
-
70
-	if len(data) > 0 {
71
-		if err := json.Unmarshal(data, v); err != nil {
72
-			return err
73
-		}
74
-	}
75
-
76
-	return nil
77
-}
78
-
79
-func (s *SyncPipe) ReportChildError(err error) {
80
-	// ensure that any data sent from the parent is consumed so it doesn't
81
-	// receive ECONNRESET when the child writes to the pipe.
82
-	ioutil.ReadAll(s.child)
83
-
84
-	s.child.Write([]byte(err.Error()))
85
-	s.CloseChild()
86
-}
87
-
88
-func (s *SyncPipe) Close() error {
89
-	if s.parent != nil {
90
-		s.parent.Close()
91
-	}
92
-
93
-	if s.child != nil {
94
-		s.child.Close()
95
-	}
96
-
97
-	return nil
98
-}
99
-
100
-func (s *SyncPipe) CloseChild() {
101
-	if s.child != nil {
102
-		s.child.Close()
103
-		s.child = nil
104
-	}
105
-}
106 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-package syncpipe
2
-
3
-import (
4
-	"os"
5
-	"syscall"
6
-)
7
-
8
-func NewSyncPipe() (s *SyncPipe, err error) {
9
-	s = &SyncPipe{}
10
-
11
-	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
12
-	if err != nil {
13
-		return nil, err
14
-	}
15
-
16
-	s.child = os.NewFile(uintptr(fds[0]), "child syncpipe")
17
-	s.parent = os.NewFile(uintptr(fds[1]), "parent syncpipe")
18
-
19
-	return s, nil
20
-}
21 1
deleted file mode 100644
... ...
@@ -1,72 +0,0 @@
1
-package syncpipe
2
-
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"testing"
7
-)
8
-
9
-type testStruct struct {
10
-	Name string
11
-}
12
-
13
-func TestSendErrorFromChild(t *testing.T) {
14
-	pipe, err := NewSyncPipe()
15
-	if err != nil {
16
-		t.Fatal(err)
17
-	}
18
-	defer func() {
19
-		if err := pipe.Close(); err != nil {
20
-			t.Fatal(err)
21
-		}
22
-	}()
23
-
24
-	childfd, err := syscall.Dup(int(pipe.Child().Fd()))
25
-	if err != nil {
26
-		t.Fatal(err)
27
-	}
28
-	childPipe, _ := NewSyncPipeFromFd(0, uintptr(childfd))
29
-
30
-	pipe.CloseChild()
31
-	pipe.SendToChild(nil)
32
-
33
-	expected := "something bad happened"
34
-	childPipe.ReportChildError(fmt.Errorf(expected))
35
-
36
-	childError := pipe.ReadFromChild()
37
-	if childError == nil {
38
-		t.Fatal("expected an error to be returned but did not receive anything")
39
-	}
40
-
41
-	if childError.Error() != expected {
42
-		t.Fatalf("expected %q but received error message %q", expected, childError.Error())
43
-	}
44
-}
45
-
46
-func TestSendPayloadToChild(t *testing.T) {
47
-	pipe, err := NewSyncPipe()
48
-	if err != nil {
49
-		t.Fatal(err)
50
-	}
51
-
52
-	defer func() {
53
-		if err := pipe.Close(); err != nil {
54
-			t.Fatal(err)
55
-		}
56
-	}()
57
-
58
-	expected := "libcontainer"
59
-
60
-	if err := pipe.SendToChild(testStruct{Name: expected}); err != nil {
61
-		t.Fatal(err)
62
-	}
63
-
64
-	var s *testStruct
65
-	if err := pipe.ReadFromParent(&s); err != nil {
66
-		t.Fatal(err)
67
-	}
68
-
69
-	if s.Name != expected {
70
-		t.Fatalf("expected name %q but received %q", expected, s.Name)
71
-	}
72
-}
... ...
@@ -1,4 +1,5 @@
1 1
 // +build linux,amd64
2
+
2 3
 package system
3 4
 
4 5
 import (