Browse code

Update libcontainaer to d00b8369852285d6a830a8d3b9

Fixes #12015

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit d12fef1515cb3f0938ea6ed8cab8351e2df2753e)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <jess@docker.com> (github: jfrazelle)

Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <hugs@docker.com> (github: jfrazelle)

Michael Crosby authored on 2015/04/03 06:12:14
Showing 9 changed files
... ...
@@ -75,7 +75,7 @@ rm -rf src/github.com/docker/distribution
75 75
 mkdir -p src/github.com/docker/distribution
76 76
 mv tmp-digest src/github.com/docker/distribution/digest
77 77
 
78
-clone git github.com/docker/libcontainer c8512754166539461fd860451ff1a0af7491c197
78
+clone git github.com/docker/libcontainer d00b8369852285d6a830a8d3b966608b2ed89705
79 79
 # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
80 80
 rm -rf src/github.com/docker/libcontainer/vendor
81 81
 eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli' | grep -v 'github.com/Sirupsen/logrus')"
... ...
@@ -67,12 +67,12 @@ func generateProfile(out io.Writer) error {
67 67
 	data := &data{
68 68
 		Name: "docker-default",
69 69
 	}
70
-	if tuntablesExists() {
70
+	if tunablesExists() {
71 71
 		data.Imports = append(data.Imports, "#include <tunables/global>")
72 72
 	} else {
73 73
 		data.Imports = append(data.Imports, "@{PROC}=/proc/")
74 74
 	}
75
-	if abstrctionsEsists() {
75
+	if abstractionsExists() {
76 76
 		data.InnerImports = append(data.InnerImports, "#include <abstractions/base>")
77 77
 	}
78 78
 	if err := compiled.Execute(out, data); err != nil {
... ...
@@ -82,13 +82,13 @@ func generateProfile(out io.Writer) error {
82 82
 }
83 83
 
84 84
 // check if the tunables/global exist
85
-func tuntablesExists() bool {
85
+func tunablesExists() bool {
86 86
 	_, err := os.Stat("/etc/apparmor.d/tunables/global")
87 87
 	return err == nil
88 88
 }
89 89
 
90 90
 // check if abstractions/base exist
91
-func abstrctionsEsists() bool {
91
+func abstractionsExists() bool {
92 92
 	_, err := os.Stat("/etc/apparmor.d/abstractions/base")
93 93
 	return err == nil
94 94
 }
... ...
@@ -1,6 +1,7 @@
1 1
 package fs
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"strings"
5 6
 	"time"
6 7
 
... ...
@@ -41,6 +42,10 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
41 41
 			}
42 42
 			time.Sleep(1 * time.Millisecond)
43 43
 		}
44
+	case configs.Undefined:
45
+		return nil
46
+	default:
47
+		return fmt.Errorf("Invalid argument '%s' to freezer.state", string(cgroup.Freezer))
44 48
 	}
45 49
 
46 50
 	return nil
47 51
new file mode 100644
... ...
@@ -0,0 +1,45 @@
0
+package fs
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/docker/libcontainer/configs"
6
+)
7
+
8
+func TestFreezerSetState(t *testing.T) {
9
+	helper := NewCgroupTestUtil("freezer", t)
10
+	defer helper.cleanup()
11
+
12
+	helper.writeFileContents(map[string]string{
13
+		"freezer.state": string(configs.Frozen),
14
+	})
15
+
16
+	helper.CgroupData.c.Freezer = configs.Thawed
17
+	freezer := &FreezerGroup{}
18
+	if err := freezer.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
19
+		t.Fatal(err)
20
+	}
21
+
22
+	value, err := getCgroupParamString(helper.CgroupPath, "freezer.state")
23
+	if err != nil {
24
+		t.Fatalf("Failed to parse freezer.state - %s", err)
25
+	}
26
+	if value != string(configs.Thawed) {
27
+		t.Fatal("Got the wrong value, set freezer.state failed.")
28
+	}
29
+}
30
+
31
+func TestFreezerSetInvalidState(t *testing.T) {
32
+	helper := NewCgroupTestUtil("freezer", t)
33
+	defer helper.cleanup()
34
+
35
+	const (
36
+		invalidArg configs.FreezerState = "Invalid"
37
+	)
38
+
39
+	helper.CgroupData.c.Freezer = invalidArg
40
+	freezer := &FreezerGroup{}
41
+	if err := freezer.Set(helper.CgroupPath, helper.CgroupData.c); err == nil {
42
+		t.Fatal("Failed to return invalid argument error")
43
+	}
44
+}
... ...
@@ -218,16 +218,7 @@ func (m *Manager) Apply(pid int) error {
218 218
 	}
219 219
 
220 220
 	paths := make(map[string]string)
221
-	for _, sysname := range []string{
222
-		"devices",
223
-		"memory",
224
-		"cpu",
225
-		"cpuset",
226
-		"cpuacct",
227
-		"blkio",
228
-		"perf_event",
229
-		"freezer",
230
-	} {
221
+	for sysname := range subsystems {
231 222
 		subsystemPath, err := getSubsystemPath(m.Cgroups, sysname)
232 223
 		if err != nil {
233 224
 			// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
... ...
@@ -140,7 +140,9 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
140 140
 		cmd.SysProcAttr = &syscall.SysProcAttr{}
141 141
 	}
142 142
 	cmd.ExtraFiles = []*os.File{childPipe}
143
-	cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL
143
+	// NOTE: when running a container with no PID namespace and the parent process spawning the container is
144
+	// PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason
145
+	// even with the parent still running.
144 146
 	if c.config.ParentDeathSignal > 0 {
145 147
 		cmd.SysProcAttr.Pdeathsig = syscall.Signal(c.config.ParentDeathSignal)
146 148
 	}
... ...
@@ -69,7 +69,8 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
69 69
 		}, nil
70 70
 	case initStandard:
71 71
 		return &linuxStandardInit{
72
-			config: config,
72
+			parentPid: syscall.Getppid(),
73
+			config:    config,
73 74
 		}, nil
74 75
 	}
75 76
 	return nil, fmt.Errorf("unknown init type %q", t)
... ...
@@ -5,13 +5,15 @@ It is able to spawn new containers or join existing containers.
5 5
 
6 6
 ### How to build?
7 7
 
8
-First to add the `libcontainer/vendor` into your GOPATH. It's because something related with this [issue](https://github.com/docker/libcontainer/issues/210).
8
+First add the `libcontainer/vendor` into your GOPATH. It's because libcontainer
9
+vendors all its dependencies, so it can be built predictably.
9 10
 
10 11
 ```
11 12
 export GOPATH=$GOPATH:/your/path/to/libcontainer/vendor
12 13
 ```
13 14
 
14
-Then get into the nsinit folder and get the imported file. Use `make` command to make the nsinit binary.
15
+Then get into the nsinit folder and get the imported file. Use `make` command
16
+to make the nsinit binary.
15 17
 
16 18
 ```
17 19
 cd libcontainer/nsinit
... ...
@@ -19,7 +21,8 @@ go get
19 19
 make
20 20
 ```
21 21
 
22
-We have finished compiling the nsinit package, but a root filesystem must be provided for use along with a container configuration file.
22
+We have finished compiling the nsinit package, but a root filesystem must be
23
+provided for use along with a container configuration file.
23 24
 
24 25
 Choose a proper place to run your container. For example we use `/busybox`.
25 26
 
... ...
@@ -28,30 +31,37 @@ mkdir /busybox
28 28
 curl -sSL 'https://github.com/jpetazzo/docker-busybox/raw/buildroot-2014.11/rootfs.tar' | tar -xC /busybox
29 29
 ```
30 30
 
31
-Then you may need to write a configure file named `container.json` in the `/busybox` folder.
32
-Environment, networking, and different capabilities for the container are specified in this file.
33
-The configuration is used for each process executed inside the container
34
-See the `sample_configs` folder for examples of what the container configuration should look like.
31
+Then you may need to write a configuration file named `container.json` in the
32
+`/busybox` folder. Environment, networking, and different capabilities for
33
+the container are specified in this file. The configuration is used for each
34
+process executed inside the container.
35
+
36
+See the `sample_configs` folder for examples of what the container configuration
37
+should look like.
35 38
 
36 39
 ```
37 40
 cp libcontainer/sample_configs/minimal.json /busybox/container.json
38 41
 cd /busybox
39 42
 ```
40 43
 
41
-Now the nsinit is ready to work.
42
-To execute `/bin/bash` in the current directory as a container just run the following **as root**:
44
+You can customize `container.json` per your needs. After that, nsinit is
45
+ready to work.
46
+
47
+To execute `/bin/bash` in the current directory as a container just run the
48
+following **as root**:
49
+
43 50
 ```bash
44
-nsinit exec --tty /bin/bash
51
+nsinit exec --tty --config container.json /bin/bash
45 52
 ```
46 53
 
47
-If you wish to spawn another process inside the container while your 
48
-current bash session is running, run the same command again to 
49
-get another bash shell (or change the command).  If the original 
50
-process (PID 1) dies, all other processes spawned inside the container 
51
-will be killed and the namespace will be removed. 
54
+If you wish to spawn another process inside the container while your current
55
+bash session is running, run the same command again to get another bash shell
56
+(or change the command).  If the original process (PID 1) dies, all other
57
+processes spawned inside the container will be killed and the namespace will
58
+be removed. 
52 59
 
53
-You can identify if a process is running in a container by 
54
-looking to see if `state.json` is in the root of the directory.
60
+You can identify if a process is running in a container by looking to see if
61
+`state.json` is in the root of the directory.
55 62
    
56
-You may also specify an alternate root place where 
57
-the `container.json` file is read and where the `state.json` file will be saved.
63
+You may also specify an alternate root directory from where the `container.json`
64
+file is read and where the `state.json` file will be saved.
... ...
@@ -13,7 +13,8 @@ import (
13 13
 )
14 14
 
15 15
 type linuxStandardInit struct {
16
-	config *initConfig
16
+	parentPid int
17
+	config    *initConfig
17 18
 }
18 19
 
19 20
 func (l *linuxStandardInit) Init() error {
... ...
@@ -85,9 +86,10 @@ func (l *linuxStandardInit) Init() error {
85 85
 	if err := pdeath.Restore(); err != nil {
86 86
 		return err
87 87
 	}
88
-	// Signal self if parent is already dead. Does nothing if running in a new
89
-	// PID namespace, as Getppid will always return 0.
90
-	if syscall.Getppid() == 1 {
88
+	// compare the parent from the inital start of the init process and make sure that it did not change.
89
+	// if the parent changes that means it died and we were reparened to something else so we should
90
+	// just kill ourself and not cause problems for someone else.
91
+	if syscall.Getppid() != l.parentPid {
91 92
 		return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
92 93
 	}
93 94
 	return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())