Signed-off-by: Michael Crosby <michael@docker.com>
| ... | ... |
@@ -63,4 +63,4 @@ mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar |
| 63 | 63 |
|
| 64 | 64 |
clone git github.com/godbus/dbus v1 |
| 65 | 65 |
clone git github.com/coreos/go-systemd v2 |
| 66 |
-clone git github.com/docker/libcontainer bc06326a5e7decdc4191d1367de8439b9d83c450 |
|
| 66 |
+clone git github.com/docker/libcontainer 68ea1234a0b046803aacb2562df0da12eec2b2f9 |
| 67 | 67 |
deleted file mode 100644 |
| ... | ... |
@@ -1,73 +0,0 @@ |
| 1 |
-package fs |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "log" |
|
| 6 |
- "testing" |
|
| 7 |
- |
|
| 8 |
- "github.com/docker/libcontainer/cgroups" |
|
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-func blkioStatEntryEquals(expected, actual []cgroups.BlkioStatEntry) error {
|
|
| 12 |
- if len(expected) != len(actual) {
|
|
| 13 |
- return fmt.Errorf("blkioStatEntries length do not match")
|
|
| 14 |
- } |
|
| 15 |
- for i, expValue := range expected {
|
|
| 16 |
- actValue := actual[i] |
|
| 17 |
- if expValue != actValue {
|
|
| 18 |
- return fmt.Errorf("Expected blkio stat entry %v but found %v", expValue, actValue)
|
|
| 19 |
- } |
|
| 20 |
- } |
|
| 21 |
- return nil |
|
| 22 |
-} |
|
| 23 |
- |
|
| 24 |
-func expectBlkioStatsEquals(t *testing.T, expected, actual cgroups.BlkioStats) {
|
|
| 25 |
- if err := blkioStatEntryEquals(expected.IoServiceBytesRecursive, actual.IoServiceBytesRecursive); err != nil {
|
|
| 26 |
- log.Printf("blkio IoServiceBytesRecursive do not match - %s\n", err)
|
|
| 27 |
- t.Fail() |
|
| 28 |
- } |
|
| 29 |
- |
|
| 30 |
- if err := blkioStatEntryEquals(expected.IoServicedRecursive, actual.IoServicedRecursive); err != nil {
|
|
| 31 |
- log.Printf("blkio IoServicedRecursive do not match - %s\n", err)
|
|
| 32 |
- t.Fail() |
|
| 33 |
- } |
|
| 34 |
- |
|
| 35 |
- if err := blkioStatEntryEquals(expected.IoQueuedRecursive, actual.IoQueuedRecursive); err != nil {
|
|
| 36 |
- log.Printf("blkio IoQueuedRecursive do not match - %s\n", err)
|
|
| 37 |
- t.Fail() |
|
| 38 |
- } |
|
| 39 |
- |
|
| 40 |
- if err := blkioStatEntryEquals(expected.SectorsRecursive, actual.SectorsRecursive); err != nil {
|
|
| 41 |
- log.Printf("blkio SectorsRecursive do not match - %s\n", err)
|
|
| 42 |
- t.Fail() |
|
| 43 |
- } |
|
| 44 |
-} |
|
| 45 |
- |
|
| 46 |
-func expectThrottlingDataEquals(t *testing.T, expected, actual cgroups.ThrottlingData) {
|
|
| 47 |
- if expected != actual {
|
|
| 48 |
- log.Printf("Expected throttling data %v but found %v\n", expected, actual)
|
|
| 49 |
- t.Fail() |
|
| 50 |
- } |
|
| 51 |
-} |
|
| 52 |
- |
|
| 53 |
-func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats) {
|
|
| 54 |
- if expected.Usage != actual.Usage {
|
|
| 55 |
- log.Printf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage)
|
|
| 56 |
- t.Fail() |
|
| 57 |
- } |
|
| 58 |
- if expected.MaxUsage != actual.MaxUsage {
|
|
| 59 |
- log.Printf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage)
|
|
| 60 |
- t.Fail() |
|
| 61 |
- } |
|
| 62 |
- for key, expValue := range expected.Stats {
|
|
| 63 |
- actValue, ok := actual.Stats[key] |
|
| 64 |
- if !ok {
|
|
| 65 |
- log.Printf("Expected memory stat key %s not found\n", key)
|
|
| 66 |
- t.Fail() |
|
| 67 |
- } |
|
| 68 |
- if expValue != actValue {
|
|
| 69 |
- log.Printf("Expected memory stat value %d but found %d\n", expValue, actValue)
|
|
| 70 |
- t.Fail() |
|
| 71 |
- } |
|
| 72 |
- } |
|
| 73 |
-} |
| 74 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,73 @@ |
| 0 |
+package fs |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "log" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/libcontainer/cgroups" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func blkioStatEntryEquals(expected, actual []cgroups.BlkioStatEntry) error {
|
|
| 11 |
+ if len(expected) != len(actual) {
|
|
| 12 |
+ return fmt.Errorf("blkioStatEntries length do not match")
|
|
| 13 |
+ } |
|
| 14 |
+ for i, expValue := range expected {
|
|
| 15 |
+ actValue := actual[i] |
|
| 16 |
+ if expValue != actValue {
|
|
| 17 |
+ return fmt.Errorf("Expected blkio stat entry %v but found %v", expValue, actValue)
|
|
| 18 |
+ } |
|
| 19 |
+ } |
|
| 20 |
+ return nil |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+func expectBlkioStatsEquals(t *testing.T, expected, actual cgroups.BlkioStats) {
|
|
| 24 |
+ if err := blkioStatEntryEquals(expected.IoServiceBytesRecursive, actual.IoServiceBytesRecursive); err != nil {
|
|
| 25 |
+ log.Printf("blkio IoServiceBytesRecursive do not match - %s\n", err)
|
|
| 26 |
+ t.Fail() |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ if err := blkioStatEntryEquals(expected.IoServicedRecursive, actual.IoServicedRecursive); err != nil {
|
|
| 30 |
+ log.Printf("blkio IoServicedRecursive do not match - %s\n", err)
|
|
| 31 |
+ t.Fail() |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ if err := blkioStatEntryEquals(expected.IoQueuedRecursive, actual.IoQueuedRecursive); err != nil {
|
|
| 35 |
+ log.Printf("blkio IoQueuedRecursive do not match - %s\n", err)
|
|
| 36 |
+ t.Fail() |
|
| 37 |
+ } |
|
| 38 |
+ |
|
| 39 |
+ if err := blkioStatEntryEquals(expected.SectorsRecursive, actual.SectorsRecursive); err != nil {
|
|
| 40 |
+ log.Printf("blkio SectorsRecursive do not match - %s\n", err)
|
|
| 41 |
+ t.Fail() |
|
| 42 |
+ } |
|
| 43 |
+} |
|
| 44 |
+ |
|
| 45 |
+func expectThrottlingDataEquals(t *testing.T, expected, actual cgroups.ThrottlingData) {
|
|
| 46 |
+ if expected != actual {
|
|
| 47 |
+ log.Printf("Expected throttling data %v but found %v\n", expected, actual)
|
|
| 48 |
+ t.Fail() |
|
| 49 |
+ } |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats) {
|
|
| 53 |
+ if expected.Usage != actual.Usage {
|
|
| 54 |
+ log.Printf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage)
|
|
| 55 |
+ t.Fail() |
|
| 56 |
+ } |
|
| 57 |
+ if expected.MaxUsage != actual.MaxUsage {
|
|
| 58 |
+ log.Printf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage)
|
|
| 59 |
+ t.Fail() |
|
| 60 |
+ } |
|
| 61 |
+ for key, expValue := range expected.Stats {
|
|
| 62 |
+ actValue, ok := actual.Stats[key] |
|
| 63 |
+ if !ok {
|
|
| 64 |
+ log.Printf("Expected memory stat key %s not found\n", key)
|
|
| 65 |
+ t.Fail() |
|
| 66 |
+ } |
|
| 67 |
+ if expValue != actValue {
|
|
| 68 |
+ log.Printf("Expected memory stat value %d but found %d\n", expValue, actValue)
|
|
| 69 |
+ t.Fail() |
|
| 70 |
+ } |
|
| 71 |
+ } |
|
| 72 |
+} |
| 0 | 73 |
deleted file mode 100644 |
| ... | ... |
@@ -1,60 +0,0 @@ |
| 1 |
-/* |
|
| 2 |
-Utility for testing cgroup operations. |
|
| 3 |
- |
|
| 4 |
-Creates a mock of the cgroup filesystem for the duration of the test. |
|
| 5 |
-*/ |
|
| 6 |
-package fs |
|
| 7 |
- |
|
| 8 |
-import ( |
|
| 9 |
- "fmt" |
|
| 10 |
- "io/ioutil" |
|
| 11 |
- "os" |
|
| 12 |
- "testing" |
|
| 13 |
-) |
|
| 14 |
- |
|
| 15 |
-type cgroupTestUtil struct {
|
|
| 16 |
- // data to use in tests. |
|
| 17 |
- CgroupData *data |
|
| 18 |
- |
|
| 19 |
- // Path to the mock cgroup directory. |
|
| 20 |
- CgroupPath string |
|
| 21 |
- |
|
| 22 |
- // Temporary directory to store mock cgroup filesystem. |
|
| 23 |
- tempDir string |
|
| 24 |
- t *testing.T |
|
| 25 |
-} |
|
| 26 |
- |
|
| 27 |
-// Creates a new test util for the specified subsystem |
|
| 28 |
-func NewCgroupTestUtil(subsystem string, t *testing.T) *cgroupTestUtil {
|
|
| 29 |
- d := &data{}
|
|
| 30 |
- tempDir, err := ioutil.TempDir("", fmt.Sprintf("%s_cgroup_test", subsystem))
|
|
| 31 |
- if err != nil {
|
|
| 32 |
- t.Fatal(err) |
|
| 33 |
- } |
|
| 34 |
- d.root = tempDir |
|
| 35 |
- testCgroupPath, err := d.path(subsystem) |
|
| 36 |
- if err != nil {
|
|
| 37 |
- t.Fatal(err) |
|
| 38 |
- } |
|
| 39 |
- |
|
| 40 |
- // Ensure the full mock cgroup path exists. |
|
| 41 |
- err = os.MkdirAll(testCgroupPath, 0755) |
|
| 42 |
- if err != nil {
|
|
| 43 |
- t.Fatal(err) |
|
| 44 |
- } |
|
| 45 |
- return &cgroupTestUtil{CgroupData: d, CgroupPath: testCgroupPath, tempDir: tempDir, t: t}
|
|
| 46 |
-} |
|
| 47 |
- |
|
| 48 |
-func (c *cgroupTestUtil) cleanup() {
|
|
| 49 |
- os.RemoveAll(c.tempDir) |
|
| 50 |
-} |
|
| 51 |
- |
|
| 52 |
-// Write the specified contents on the mock of the specified cgroup files. |
|
| 53 |
-func (c *cgroupTestUtil) writeFileContents(fileContents map[string]string) {
|
|
| 54 |
- for file, contents := range fileContents {
|
|
| 55 |
- err := writeFile(c.CgroupPath, file, contents) |
|
| 56 |
- if err != nil {
|
|
| 57 |
- c.t.Fatal(err) |
|
| 58 |
- } |
|
| 59 |
- } |
|
| 60 |
-} |
| 61 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,60 @@ |
| 0 |
+/* |
|
| 1 |
+Utility for testing cgroup operations. |
|
| 2 |
+ |
|
| 3 |
+Creates a mock of the cgroup filesystem for the duration of the test. |
|
| 4 |
+*/ |
|
| 5 |
+package fs |
|
| 6 |
+ |
|
| 7 |
+import ( |
|
| 8 |
+ "fmt" |
|
| 9 |
+ "io/ioutil" |
|
| 10 |
+ "os" |
|
| 11 |
+ "testing" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+type cgroupTestUtil struct {
|
|
| 15 |
+ // data to use in tests. |
|
| 16 |
+ CgroupData *data |
|
| 17 |
+ |
|
| 18 |
+ // Path to the mock cgroup directory. |
|
| 19 |
+ CgroupPath string |
|
| 20 |
+ |
|
| 21 |
+ // Temporary directory to store mock cgroup filesystem. |
|
| 22 |
+ tempDir string |
|
| 23 |
+ t *testing.T |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 26 |
+// Creates a new test util for the specified subsystem |
|
| 27 |
+func NewCgroupTestUtil(subsystem string, t *testing.T) *cgroupTestUtil {
|
|
| 28 |
+ d := &data{}
|
|
| 29 |
+ tempDir, err := ioutil.TempDir("", fmt.Sprintf("%s_cgroup_test", subsystem))
|
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ t.Fatal(err) |
|
| 32 |
+ } |
|
| 33 |
+ d.root = tempDir |
|
| 34 |
+ testCgroupPath, err := d.path(subsystem) |
|
| 35 |
+ if err != nil {
|
|
| 36 |
+ t.Fatal(err) |
|
| 37 |
+ } |
|
| 38 |
+ |
|
| 39 |
+ // Ensure the full mock cgroup path exists. |
|
| 40 |
+ err = os.MkdirAll(testCgroupPath, 0755) |
|
| 41 |
+ if err != nil {
|
|
| 42 |
+ t.Fatal(err) |
|
| 43 |
+ } |
|
| 44 |
+ return &cgroupTestUtil{CgroupData: d, CgroupPath: testCgroupPath, tempDir: tempDir, t: t}
|
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+func (c *cgroupTestUtil) cleanup() {
|
|
| 48 |
+ os.RemoveAll(c.tempDir) |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+// Write the specified contents on the mock of the specified cgroup files. |
|
| 52 |
+func (c *cgroupTestUtil) writeFileContents(fileContents map[string]string) {
|
|
| 53 |
+ for file, contents := range fileContents {
|
|
| 54 |
+ err := writeFile(c.CgroupPath, file, contents) |
|
| 55 |
+ if err != nil {
|
|
| 56 |
+ c.t.Fatal(err) |
|
| 57 |
+ } |
|
| 58 |
+ } |
|
| 59 |
+} |
| ... | ... |
@@ -133,7 +133,7 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP |
| 133 | 133 |
} |
| 134 | 134 |
*/ |
| 135 | 135 |
|
| 136 |
- command := exec.Command(init, append([]string{"init"}, args...)...)
|
|
| 136 |
+ command := exec.Command(init, append([]string{"init", "--"}, args...)...)
|
|
| 137 | 137 |
// make sure the process is executed inside the context of the rootfs |
| 138 | 138 |
command.Dir = rootfs |
| 139 | 139 |
command.Env = append(os.Environ(), env...) |
| ... | ... |
@@ -5,7 +5,6 @@ package namespaces |
| 5 | 5 |
import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"os" |
| 8 |
- "runtime" |
|
| 9 | 8 |
"strings" |
| 10 | 9 |
"syscall" |
| 11 | 10 |
|
| ... | ... |
@@ -28,6 +27,8 @@ import ( |
| 28 | 28 |
// Move this to libcontainer package. |
| 29 | 29 |
// Init is the init process that first runs inside a new namespace to setup mounts, users, networking, |
| 30 | 30 |
// and other options required for the new container. |
| 31 |
+// The caller of Init function has to ensure that the go runtime is locked to an OS thread |
|
| 32 |
+// (using runtime.LockOSThread) else system calls like setns called within Init may not work as intended. |
|
| 31 | 33 |
func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *syncpipe.SyncPipe, args []string) (err error) {
|
| 32 | 34 |
defer func() {
|
| 33 | 35 |
if err != nil {
|
| ... | ... |
@@ -87,8 +88,6 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn |
| 87 | 87 |
} |
| 88 | 88 |
} |
| 89 | 89 |
|
| 90 |
- runtime.LockOSThread() |
|
| 91 |
- |
|
| 92 | 90 |
if err := apparmor.ApplyProfile(container.AppArmorProfile); err != nil {
|
| 93 | 91 |
return fmt.Errorf("set apparmor profile %s: %s", container.AppArmorProfile, err)
|
| 94 | 92 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package nsinit |
| 3 | 3 |
import ( |
| 4 | 4 |
"log" |
| 5 | 5 |
"os" |
| 6 |
+ "runtime" |
|
| 6 | 7 |
"strconv" |
| 7 | 8 |
|
| 8 | 9 |
"github.com/codegangsta/cli" |
| ... | ... |
@@ -23,6 +24,8 @@ var ( |
| 23 | 23 |
) |
| 24 | 24 |
|
| 25 | 25 |
func initAction(context *cli.Context) {
|
| 26 |
+ runtime.LockOSThread() |
|
| 27 |
+ |
|
| 26 | 28 |
container, err := loadContainer() |
| 27 | 29 |
if err != nil {
|
| 28 | 30 |
log.Fatal(err) |