瀏覽代碼

Merge pull request #7597 from crosbymichael/update-libcontainer-aug4

Update libcontainer to 29363e2d2d7b8f62a5f353be333
Michael Crosby 11 年之前
父節點
當前提交
37db53bf7a
共有 31 個文件被更改,包括 468 次插入294 次删除
  1. 1 1
      hack/vendor.sh
  2. 1 0
      vendor/src/github.com/docker/libcontainer/MAINTAINERS
  3. 1 1
      vendor/src/github.com/docker/libcontainer/Makefile
  4. 1 1
      vendor/src/github.com/docker/libcontainer/README.md
  5. 1 0
      vendor/src/github.com/docker/libcontainer/cgroups/cgroups.go
  6. 19 3
      vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
  7. 2 2
      vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go
  8. 20 11
      vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go
  9. 1 1
      vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go
  10. 106 187
      vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go
  11. 21 0
      vendor/src/github.com/docker/libcontainer/cgroups/utils.go
  12. 1 1
      vendor/src/github.com/docker/libcontainer/console/console.go
  13. 1 1
      vendor/src/github.com/docker/libcontainer/mount/init.go
  14. 9 3
      vendor/src/github.com/docker/libcontainer/namespaces/exec.go
  15. 13 2
      vendor/src/github.com/docker/libcontainer/namespaces/execin.go
  16. 10 10
      vendor/src/github.com/docker/libcontainer/namespaces/nsenter/nsenter.c
  17. 7 0
      vendor/src/github.com/docker/libcontainer/netlink/netlink.go
  18. 27 9
      vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go
  19. 46 0
      vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
  20. 4 0
      vendor/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
  21. 8 0
      vendor/src/github.com/docker/libcontainer/network/network.go
  22. 2 2
      vendor/src/github.com/docker/libcontainer/nsinit/config.go
  23. 23 5
      vendor/src/github.com/docker/libcontainer/nsinit/exec.go
  24. 2 2
      vendor/src/github.com/docker/libcontainer/nsinit/init.go
  25. 17 14
      vendor/src/github.com/docker/libcontainer/nsinit/main.go
  26. 63 21
      vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go
  27. 0 7
      vendor/src/github.com/docker/libcontainer/nsinit/nsinit/nsinit.go
  28. 2 2
      vendor/src/github.com/docker/libcontainer/nsinit/pause.go
  29. 2 2
      vendor/src/github.com/docker/libcontainer/nsinit/stats.go
  30. 54 6
      vendor/src/github.com/docker/libcontainer/nsinit/utils.go
  31. 3 0
      vendor/src/github.com/docker/libcontainer/state.go

+ 1 - 1
hack/vendor.sh

@@ -59,7 +59,7 @@ rm -rf src/code.google.com/p/go
 mkdir -p src/code.google.com/p/go/src/pkg/archive
 mkdir -p src/code.google.com/p/go/src/pkg/archive
 mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
 mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
 
 
-clone git github.com/docker/libcontainer f2e78425c377acc7a67a35c3148069b6285a3c4b
+clone git github.com/docker/libcontainer 29363e2d2d7b8f62a5f353be333758f83df540a9
 # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
 # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
 rm -rf src/github.com/docker/libcontainer/vendor
 rm -rf src/github.com/docker/libcontainer/vendor
 eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
 eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"

+ 1 - 0
vendor/src/github.com/docker/libcontainer/MAINTAINERS

@@ -1,5 +1,6 @@
 Michael Crosby <michael@docker.com> (@crosbymichael)
 Michael Crosby <michael@docker.com> (@crosbymichael)
 Rohit Jnagal <jnagal@google.com> (@rjnagal)
 Rohit Jnagal <jnagal@google.com> (@rjnagal)
 Victor Marmol <vmarmol@google.com> (@vmarmol)
 Victor Marmol <vmarmol@google.com> (@vmarmol)
+Mrunal Patel <mpatel@redhat.com> (@mrunalp)
 .travis.yml: Tianon Gravi <admwiggin@gmail.com> (@tianon)
 .travis.yml: Tianon Gravi <admwiggin@gmail.com> (@tianon)
 update-vendor.sh: Tianon Gravi <admwiggin@gmail.com> (@tianon)
 update-vendor.sh: Tianon Gravi <admwiggin@gmail.com> (@tianon)

+ 1 - 1
vendor/src/github.com/docker/libcontainer/Makefile

@@ -2,7 +2,7 @@
 all:
 all:
 	docker build -t docker/libcontainer .
 	docker build -t docker/libcontainer .
 
 
-test:
+test: 
 	# we need NET_ADMIN for the netlink tests and SYS_ADMIN for mounting
 	# we need NET_ADMIN for the netlink tests and SYS_ADMIN for mounting
 	docker run --rm -it --cap-add NET_ADMIN --cap-add SYS_ADMIN docker/libcontainer
 	docker run --rm -it --cap-add NET_ADMIN --cap-add SYS_ADMIN docker/libcontainer
 
 

+ 1 - 1
vendor/src/github.com/docker/libcontainer/README.md

@@ -1,4 +1,4 @@
-## libcontainer - reference implementation for containers
+## libcontainer - reference implementation for containers [![Build Status](https://travis-ci.org/docker/libcontainer.png?branch=master)](https://travis-ci.org/docker/libcontainer)
 
 
 ### Note on API changes:
 ### Note on API changes:
 
 

+ 1 - 0
vendor/src/github.com/docker/libcontainer/cgroups/cgroups.go

@@ -37,4 +37,5 @@ type Cgroup struct {
 
 
 type ActiveCgroup interface {
 type ActiveCgroup interface {
 	Cleanup() error
 	Cleanup() error
+	Paths() (map[string]string, error)
 }
 }

+ 19 - 3
vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go

@@ -21,12 +21,16 @@ var (
 		"perf_event": &PerfEventGroup{},
 		"perf_event": &PerfEventGroup{},
 		"freezer":    &FreezerGroup{},
 		"freezer":    &FreezerGroup{},
 	}
 	}
+	CgroupProcesses = "cgroup.procs"
 )
 )
 
 
 type subsystem interface {
 type subsystem interface {
-	Set(*data) error
+	// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
+	GetStats(path string, stats *cgroups.Stats) error
+	// Removes the cgroup represented by 'data'.
 	Remove(*data) error
 	Remove(*data) error
-	GetStats(string, *cgroups.Stats) error
+	// Creates and joins the cgroup represented by data.
+	Set(*data) error
 }
 }
 
 
 type data struct {
 type data struct {
@@ -149,6 +153,18 @@ func (raw *data) parent(subsystem string) (string, error) {
 	return filepath.Join(raw.root, subsystem, initPath), nil
 	return filepath.Join(raw.root, subsystem, initPath), nil
 }
 }
 
 
+func (raw *data) Paths() (map[string]string, error) {
+	paths := make(map[string]string)
+	for sysname := range subsystems {
+		path, err := raw.path(sysname)
+		if err != nil {
+			return nil, err
+		}
+		paths[sysname] = path
+	}
+	return paths, nil
+}
+
 func (raw *data) path(subsystem string) (string, error) {
 func (raw *data) path(subsystem string) (string, error) {
 	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
 	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
 	if filepath.IsAbs(raw.cgroup) {
 	if filepath.IsAbs(raw.cgroup) {
@@ -169,7 +185,7 @@ func (raw *data) join(subsystem string) (string, error) {
 	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
 	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
 		return "", err
 		return "", err
 	}
 	}
-	if err := writeFile(path, "cgroup.procs", strconv.Itoa(raw.pid)); err != nil {
+	if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil {
 		return "", err
 		return "", err
 	}
 	}
 	return path, nil
 	return path, nil

+ 2 - 2
vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go

@@ -54,7 +54,7 @@ func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
 		return err
 		return err
 	}
 	}
 	// sample for 100ms
 	// sample for 100ms
-	time.Sleep(100 * time.Millisecond)
+	time.Sleep(1000 * time.Millisecond)
 	if kernelModeUsage, userModeUsage, err = getCpuUsage(path); err != nil {
 	if kernelModeUsage, userModeUsage, err = getCpuUsage(path); err != nil {
 		return err
 		return err
 	}
 	}
@@ -73,7 +73,7 @@ func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
 		deltaUsage  = lastUsage - startUsage
 		deltaUsage  = lastUsage - startUsage
 	)
 	)
 	if deltaSystem > 0.0 {
 	if deltaSystem > 0.0 {
-		percentage = ((deltaProc / deltaSystem) * clockTicks) * cpuCount
+		percentage = uint64((float64(deltaProc) / float64(deltaSystem)) * float64(clockTicks*cpuCount))
 	}
 	}
 	// NOTE: a percentage over 100% is valid for POSIX because that means the
 	// NOTE: a percentage over 100% is valid for POSIX because that means the
 	// processes is using multiple cores
 	// processes is using multiple cores

+ 20 - 11
vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go

@@ -20,19 +20,10 @@ func (s *CpusetGroup) Set(d *data) error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		if err := s.ensureParent(dir); err != nil {
-			return err
-		}
 
 
-		// because we are not using d.join we need to place the pid into the procs file
-		// unlike the other subsystems
-		if err := writeFile(dir, "cgroup.procs", strconv.Itoa(d.pid)); err != nil {
-			return err
-		}
-		if err := writeFile(dir, "cpuset.cpus", d.c.CpusetCpus); err != nil {
-			return err
-		}
+		return s.SetDir(dir, d.c.CpusetCpus, d.pid)
 	}
 	}
+
 	return nil
 	return nil
 }
 }
 
 
@@ -44,6 +35,24 @@ func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error {
 	return nil
 	return nil
 }
 }
 
 
+func (s *CpusetGroup) SetDir(dir, value string, pid int) error {
+	if err := s.ensureParent(dir); err != nil {
+		return err
+	}
+
+	// because we are not using d.join we need to place the pid into the procs file
+	// unlike the other subsystems
+	if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil {
+		return err
+	}
+
+	if err := writeFile(dir, "cpuset.cpus", value); err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func (s *CpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) {
 func (s *CpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) {
 	if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus")); err != nil {
 	if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus")); err != nil {
 		return
 		return

+ 1 - 1
vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go

@@ -14,7 +14,7 @@ type MemoryGroup struct {
 
 
 func (s *MemoryGroup) Set(d *data) error {
 func (s *MemoryGroup) Set(d *data) error {
 	dir, err := d.join("memory")
 	dir, err := d.join("memory")
-	// only return an error for memory if it was not specified
+	// only return an error for memory if it was specified
 	if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
 	if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
 		return err
 		return err
 	}
 	}

+ 106 - 187
vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go

@@ -21,7 +21,7 @@ import (
 )
 )
 
 
 type systemdCgroup struct {
 type systemdCgroup struct {
-	cleanupDirs []string
+	cgroup *cgroups.Cgroup
 }
 }
 
 
 type subsystem interface {
 type subsystem interface {
@@ -84,39 +84,15 @@ func getIfaceForUnit(unitName string) string {
 	return "Unit"
 	return "Unit"
 }
 }
 
 
-type cgroupArg struct {
-	File  string
-	Value string
-}
-
 func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 	var (
 	var (
 		unitName   = getUnitName(c)
 		unitName   = getUnitName(c)
 		slice      = "system.slice"
 		slice      = "system.slice"
 		properties []systemd1.Property
 		properties []systemd1.Property
-		cpuArgs    []cgroupArg
-		cpusetArgs []cgroupArg
-		memoryArgs []cgroupArg
-		res        systemdCgroup
+		res        = &systemdCgroup{}
 	)
 	)
 
 
-	// First set up things not supported by systemd
-
-	// -1 disables memorySwap
-	if c.MemorySwap >= 0 && (c.Memory != 0 || c.MemorySwap > 0) {
-		memorySwap := c.MemorySwap
-
-		if memorySwap == 0 {
-			// By default, MemorySwap is set to twice the size of RAM.
-			memorySwap = c.Memory * 2
-		}
-
-		memoryArgs = append(memoryArgs, cgroupArg{"memory.memsw.limit_in_bytes", strconv.FormatInt(memorySwap, 10)})
-	}
-
-	if c.CpusetCpus != "" {
-		cpusetArgs = append(cpusetArgs, cgroupArg{"cpuset.cpus", c.CpusetCpus})
-	}
+	res.cgroup = c
 
 
 	if c.Slice != "" {
 	if c.Slice != "" {
 		slice = c.Slice
 		slice = c.Slice
@@ -150,201 +126,84 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	// To work around the lack of /dev/pts/* support above we need to manually add these
-	// so, ask systemd for the cgroup used
-	props, err := theConn.GetUnitTypeProperties(unitName, getIfaceForUnit(unitName))
-	if err != nil {
-		return nil, err
-	}
-
-	cgroup := props["ControlGroup"].(string)
-
 	if !c.AllowAllDevices {
 	if !c.AllowAllDevices {
-		// Atm we can't use the systemd device support because of two missing things:
-		// * Support for wildcards to allow mknod on any device
-		// * Support for wildcards to allow /dev/pts support
-		//
-		// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
-		// in wide use. When both these are availalable we will be able to switch, but need to keep the old
-		// implementation for backwards compat.
-		//
-		// Note: we can't use systemd to set up the initial limits, and then change the cgroup
-		// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
-		// This happens at least for v208 when any sibling unit is started.
-
-		mountpoint, err := cgroups.FindCgroupMountpoint("devices")
-		if err != nil {
+		if err := joinDevices(c, pid); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-
-		initPath, err := cgroups.GetInitCgroupDir("devices")
-		if err != nil {
-			return nil, err
-		}
-
-		dir := filepath.Join(mountpoint, initPath, c.Parent, c.Name)
-
-		res.cleanupDirs = append(res.cleanupDirs, dir)
-
-		if err := os.MkdirAll(dir, 0755); err != nil && !os.IsExist(err) {
-			return nil, err
-		}
-
-		if err := ioutil.WriteFile(filepath.Join(dir, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
-			return nil, err
-		}
-
-		if err := writeFile(dir, "devices.deny", "a"); err != nil {
-			return nil, err
-		}
-
-		for _, dev := range c.AllowedDevices {
-			if err := writeFile(dir, "devices.allow", dev.GetCgroupAllowString()); err != nil {
-				return nil, err
-			}
-		}
 	}
 	}
 
 
-	if len(cpuArgs) != 0 {
-		mountpoint, err := cgroups.FindCgroupMountpoint("cpu")
-		if err != nil {
-			return nil, err
-		}
-
-		path := filepath.Join(mountpoint, cgroup)
-
-		for _, arg := range cpuArgs {
-			if err := ioutil.WriteFile(filepath.Join(path, arg.File), []byte(arg.Value), 0700); err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	if len(memoryArgs) != 0 {
-		mountpoint, err := cgroups.FindCgroupMountpoint("memory")
-		if err != nil {
+	// -1 disables memorySwap
+	if c.MemorySwap >= 0 && (c.Memory != 0 || c.MemorySwap > 0) {
+		if err := joinMemory(c, pid); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 
 
-		path := filepath.Join(mountpoint, cgroup)
-
-		for _, arg := range memoryArgs {
-			if err := ioutil.WriteFile(filepath.Join(path, arg.File), []byte(arg.Value), 0700); err != nil {
-				return nil, err
-			}
-		}
 	}
 	}
 
 
 	// we need to manually join the freezer cgroup in systemd because it does not currently support it
 	// we need to manually join the freezer cgroup in systemd because it does not currently support it
 	// via the dbus api
 	// via the dbus api
-	freezerPath, err := joinFreezer(c, pid)
-	if err != nil {
+	if err := joinFreezer(c, pid); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	res.cleanupDirs = append(res.cleanupDirs, freezerPath)
 
 
-	if len(cpusetArgs) != 0 {
-		// systemd does not atm set up the cpuset controller, so we must manually
-		// join it. Additionally that is a very finicky controller where each
-		// level must have a full setup as the default for a new directory is "no cpus",
-		// so we avoid using any hierarchies here, creating a toplevel directory.
-		mountpoint, err := cgroups.FindCgroupMountpoint("cpuset")
-		if err != nil {
-			return nil, err
-		}
-
-		initPath, err := cgroups.GetInitCgroupDir("cpuset")
-		if err != nil {
-			return nil, err
-		}
-
-		var (
-			foundCpus bool
-			foundMems bool
-
-			rootPath = filepath.Join(mountpoint, initPath)
-			path     = filepath.Join(mountpoint, initPath, c.Parent+"-"+c.Name)
-		)
-
-		res.cleanupDirs = append(res.cleanupDirs, path)
-
-		if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+	if c.CpusetCpus != "" {
+		if err := joinCpuset(c, pid); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
+	}
 
 
-		for _, arg := range cpusetArgs {
-			if arg.File == "cpuset.cpus" {
-				foundCpus = true
-			}
-			if arg.File == "cpuset.mems" {
-				foundMems = true
-			}
-			if err := ioutil.WriteFile(filepath.Join(path, arg.File), []byte(arg.Value), 0700); err != nil {
-				return nil, err
-			}
-		}
-
-		// These are required, if not specified inherit from parent
-		if !foundCpus {
-			s, err := ioutil.ReadFile(filepath.Join(rootPath, "cpuset.cpus"))
-			if err != nil {
-				return nil, err
-			}
+	return res, nil
+}
 
 
-			if err := ioutil.WriteFile(filepath.Join(path, "cpuset.cpus"), s, 0700); err != nil {
-				return nil, err
-			}
-		}
+func writeFile(dir, file, data string) error {
+	return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
+}
 
 
-		// These are required, if not specified inherit from parent
-		if !foundMems {
-			s, err := ioutil.ReadFile(filepath.Join(rootPath, "cpuset.mems"))
-			if err != nil {
-				return nil, err
-			}
+func (c *systemdCgroup) Paths() (map[string]string, error) {
+	paths := make(map[string]string)
 
 
-			if err := ioutil.WriteFile(filepath.Join(path, "cpuset.mems"), s, 0700); err != nil {
-				return nil, err
+	for sysname := range subsystems {
+		subsystemPath, err := getSubsystemPath(c.cgroup, sysname)
+		if err != nil {
+			// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
+			if err == cgroups.ErrNotFound {
+				continue
 			}
 			}
-		}
 
 
-		if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-	}
 
 
-	return &res, nil
-}
+		paths[sysname] = subsystemPath
+	}
 
 
-func writeFile(dir, file, data string) error {
-	return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
+	return paths, nil
 }
 }
 
 
 func (c *systemdCgroup) Cleanup() error {
 func (c *systemdCgroup) Cleanup() error {
 	// systemd cleans up, we don't need to do much
 	// systemd cleans up, we don't need to do much
+	paths, err := c.Paths()
+	if err != nil {
+		return err
+	}
 
 
-	for _, path := range c.cleanupDirs {
+	for _, path := range paths {
 		os.RemoveAll(path)
 		os.RemoveAll(path)
 	}
 	}
 
 
 	return nil
 	return nil
 }
 }
 
 
-func joinFreezer(c *cgroups.Cgroup, pid int) (string, error) {
+func joinFreezer(c *cgroups.Cgroup, pid int) error {
 	path, err := getSubsystemPath(c, "freezer")
 	path, err := getSubsystemPath(c, "freezer")
 	if err != nil {
 	if err != nil {
-		return "", err
+		return err
 	}
 	}
 
 
 	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
 	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
-		return "", err
-	}
-
-	if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
-		return "", err
+		return err
 	}
 	}
 
 
-	return path, nil
+	return ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700)
 }
 }
 
 
 func getSubsystemPath(c *cgroups.Cgroup, subsystem string) (string, error) {
 func getSubsystemPath(c *cgroups.Cgroup, subsystem string) (string, error) {
@@ -389,20 +248,12 @@ func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error {
 }
 }
 
 
 func GetPids(c *cgroups.Cgroup) ([]int, error) {
 func GetPids(c *cgroups.Cgroup) ([]int, error) {
-	unitName := getUnitName(c)
-
-	mountpoint, err := cgroups.FindCgroupMountpoint("cpu")
+	path, err := getSubsystemPath(c, "cpu")
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	props, err := theConn.GetUnitTypeProperties(unitName, getIfaceForUnit(unitName))
-	if err != nil {
-		return nil, err
-	}
-	cgroup := props["ControlGroup"].(string)
-
-	return cgroups.ReadProcsFile(filepath.Join(mountpoint, cgroup))
+	return cgroups.ReadProcsFile(path)
 }
 }
 
 
 func getUnitName(c *cgroups.Cgroup) string {
 func getUnitName(c *cgroups.Cgroup) string {
@@ -437,3 +288,71 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) {
 
 
 	return stats, nil
 	return stats, nil
 }
 }
+
+// Atm we can't use the systemd device support because of two missing things:
+// * Support for wildcards to allow mknod on any device
+// * Support for wildcards to allow /dev/pts support
+//
+// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
+// in wide use. When both these are availalable we will be able to switch, but need to keep the old
+// implementation for backwards compat.
+//
+// Note: we can't use systemd to set up the initial limits, and then change the cgroup
+// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
+// This happens at least for v208 when any sibling unit is started.
+func joinDevices(c *cgroups.Cgroup, pid int) error {
+	path, err := getSubsystemPath(c, "devices")
+	if err != nil {
+		return err
+	}
+
+	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+		return err
+	}
+
+	if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
+		return err
+	}
+
+	if err := writeFile(path, "devices.deny", "a"); err != nil {
+		return err
+	}
+
+	for _, dev := range c.AllowedDevices {
+		if err := writeFile(path, "devices.allow", dev.GetCgroupAllowString()); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func joinMemory(c *cgroups.Cgroup, pid int) error {
+	memorySwap := c.MemorySwap
+
+	if memorySwap == 0 {
+		// By default, MemorySwap is set to twice the size of RAM.
+		memorySwap = c.Memory * 2
+	}
+
+	path, err := getSubsystemPath(c, "memory")
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(filepath.Join(path, "memory.memsw.limit_in_bytes"), []byte(strconv.FormatInt(memorySwap, 10)), 0700)
+}
+
+// systemd does not atm set up the cpuset controller, so we must manually
+// join it. Additionally that is a very finicky controller where each
+// level must have a full setup as the default for a new directory is "no cpus"
+func joinCpuset(c *cgroups.Cgroup, pid int) error {
+	path, err := getSubsystemPath(c, "cpuset")
+	if err != nil {
+		return err
+	}
+
+	s := &fs.CpusetGroup{}
+
+	return s.SetDir(path, c.CpusetCpus, pid)
+}

+ 21 - 0
vendor/src/github.com/docker/libcontainer/cgroups/utils.go

@@ -4,6 +4,7 @@ import (
 	"bufio"
 	"bufio"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
+	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"strconv"
 	"strconv"
@@ -166,3 +167,23 @@ func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
 	}
 	}
 	return "", ErrNotFound
 	return "", ErrNotFound
 }
 }
+
+func pathExists(path string) bool {
+	if _, err := os.Stat(path); err != nil {
+		return false
+	}
+	return true
+}
+
+func EnterPid(cgroupPaths map[string]string, pid int) error {
+	for _, path := range cgroupPaths {
+		if pathExists(path) {
+			if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"),
+				[]byte(strconv.Itoa(pid)), 0700); err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}

+ 1 - 1
vendor/src/github.com/docker/libcontainer/console/console.go

@@ -114,7 +114,7 @@ func OpenPtmx() (*os.File, error) {
 func OpenTerminal(name string, flag int) (*os.File, error) {
 func OpenTerminal(name string, flag int) (*os.File, error) {
 	r, e := syscall.Open(name, flag, 0)
 	r, e := syscall.Open(name, flag, 0)
 	if e != nil {
 	if e != nil {
-		return nil, &os.PathError{"open", name, e}
+		return nil, &os.PathError{Op: "open", Path: name, Err: e}
 	}
 	}
 	return os.NewFile(uintptr(r), name), nil
 	return os.NewFile(uintptr(r), name), nil
 }
 }

+ 1 - 1
vendor/src/github.com/docker/libcontainer/mount/init.go

@@ -236,7 +236,7 @@ func reOpenDevNull(rootfs string) error {
 		if stat.Rdev == devNullStat.Rdev {
 		if stat.Rdev == devNullStat.Rdev {
 			// Close and re-open the fd.
 			// Close and re-open the fd.
 			if err = syscall.Dup2(int(file.Fd()), fd); err != nil {
 			if err = syscall.Dup2(int(file.Fd()), fd); err != nil {
-				return fmt.Errorf("Failed to dup fd %d to fd %d - %s", file.Fd(), fd)
+				return fmt.Errorf("Failed to dup fd %d to fd %d - %s", file.Fd(), fd, err)
 			}
 			}
 		}
 		}
 	}
 	}

+ 9 - 3
vendor/src/github.com/docker/libcontainer/namespaces/exec.go

@@ -56,14 +56,19 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
 
 
 	// Do this before syncing with child so that no children
 	// Do this before syncing with child so that no children
 	// can escape the cgroup
 	// can escape the cgroup
-	cleaner, err := SetupCgroups(container, command.Process.Pid)
+	cgroupRef, err := SetupCgroups(container, command.Process.Pid)
 	if err != nil {
 	if err != nil {
 		command.Process.Kill()
 		command.Process.Kill()
 		command.Wait()
 		command.Wait()
 		return -1, err
 		return -1, err
 	}
 	}
-	if cleaner != nil {
-		defer cleaner.Cleanup()
+	defer cgroupRef.Cleanup()
+
+	cgroupPaths, err := cgroupRef.Paths()
+	if err != nil {
+		command.Process.Kill()
+		command.Wait()
+		return -1, err
 	}
 	}
 
 
 	var networkState network.NetworkState
 	var networkState network.NetworkState
@@ -77,6 +82,7 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
 		InitPid:       command.Process.Pid,
 		InitPid:       command.Process.Pid,
 		InitStartTime: started,
 		InitStartTime: started,
 		NetworkState:  networkState,
 		NetworkState:  networkState,
+		CgroupPaths:   cgroupPaths,
 	}
 	}
 
 
 	if err := libcontainer.SaveState(dataPath, state); err != nil {
 	if err := libcontainer.SaveState(dataPath, state); err != nil {

+ 13 - 2
vendor/src/github.com/docker/libcontainer/namespaces/execin.go

@@ -3,6 +3,7 @@
 package namespaces
 package namespaces
 
 
 import (
 import (
+	"fmt"
 	"io"
 	"io"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
@@ -11,6 +12,7 @@ import (
 	"syscall"
 	"syscall"
 
 
 	"github.com/docker/libcontainer"
 	"github.com/docker/libcontainer"
+	"github.com/docker/libcontainer/cgroups"
 	"github.com/docker/libcontainer/label"
 	"github.com/docker/libcontainer/label"
 	"github.com/docker/libcontainer/syncpipe"
 	"github.com/docker/libcontainer/syncpipe"
 	"github.com/docker/libcontainer/system"
 	"github.com/docker/libcontainer/system"
@@ -18,10 +20,10 @@ import (
 
 
 // ExecIn reexec's the initPath with the argv 0 rewrite to "nsenter" so that it is able to run the
 // ExecIn reexec's the initPath with the argv 0 rewrite to "nsenter" so that it is able to run the
 // setns code in a single threaded environment joining the existing containers' namespaces.
 // setns code in a single threaded environment joining the existing containers' namespaces.
-func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs []string, initPath string,
+func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs []string, initPath, action string,
 	stdin io.Reader, stdout, stderr io.Writer, console string, startCallback func(*exec.Cmd)) (int, error) {
 	stdin io.Reader, stdout, stderr io.Writer, console string, startCallback func(*exec.Cmd)) (int, error) {
 
 
-	args := []string{"nsenter", "--nspid", strconv.Itoa(state.InitPid)}
+	args := []string{fmt.Sprintf("nsenter-%s", action), "--nspid", strconv.Itoa(state.InitPid)}
 
 
 	if console != "" {
 	if console != "" {
 		args = append(args, "--console", console)
 		args = append(args, "--console", console)
@@ -58,6 +60,11 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
 	}
 	}
 	pipe.CloseChild()
 	pipe.CloseChild()
 
 
+	// Enter cgroups.
+	if err := EnterCgroups(state, cmd.Process.Pid); err != nil {
+		return -1, err
+	}
+
 	if err := pipe.SendToChild(container); err != nil {
 	if err := pipe.SendToChild(container); err != nil {
 		cmd.Process.Kill()
 		cmd.Process.Kill()
 		cmd.Wait()
 		cmd.Wait()
@@ -101,3 +108,7 @@ func FinalizeSetns(container *libcontainer.Config, args []string) error {
 
 
 	panic("unreachable")
 	panic("unreachable")
 }
 }
+
+func EnterCgroups(state *libcontainer.State, pid int) error {
+	return cgroups.EnterPid(state.CgroupPaths, pid)
+}

+ 10 - 10
vendor/src/github.com/docker/libcontainer/namespaces/nsenter/nsenter.c

@@ -31,8 +31,8 @@ void get_args(int *argc, char ***argv)
 		contents_size += kBufSize;
 		contents_size += kBufSize;
 		contents = (char *)realloc(contents, contents_size);
 		contents = (char *)realloc(contents, contents_size);
 		bytes_read =
 		bytes_read =
-		    read(fd, contents + contents_offset,
-			 contents_size - contents_offset);
+			read(fd, contents + contents_offset,
+			     contents_size - contents_offset);
 		contents_offset += bytes_read;
 		contents_offset += bytes_read;
 	}
 	}
 	while (bytes_read > 0);
 	while (bytes_read > 0);
@@ -80,20 +80,20 @@ void nsenter()
 	char **argv;
 	char **argv;
 	get_args(&argc, &argv);
 	get_args(&argc, &argv);
 
 
-    // check argv 0 to ensure that we are supposed to setns
-    // we use strncmp to test for a value of "nsenter" but also allows alternate implmentations
-    // after the setns code path to continue to use the argv 0 to determine actions to be run
-    // resulting in the ability to specify "nsenter-mknod", "nsenter-exec", etc...
-    if (strncmp(argv[0], kNsEnter, strlen(kNsEnter)) != 0) {
-        return;
-    }
+	// check argv 0 to ensure that we are supposed to setns
+	// we use strncmp to test for a value of "nsenter" but also allows alternate implmentations
+	// after the setns code path to continue to use the argv 0 to determine actions to be run
+	// resulting in the ability to specify "nsenter-mknod", "nsenter-exec", etc...
+	if (strncmp(argv[0], kNsEnter, strlen(kNsEnter)) != 0) {
+		return;
+	}
 
 
 	static const struct option longopts[] = {
 	static const struct option longopts[] = {
 		{"nspid", required_argument, NULL, 'n'},
 		{"nspid", required_argument, NULL, 'n'},
 		{"console", required_argument, NULL, 't'},
 		{"console", required_argument, NULL, 't'},
 		{NULL, 0, NULL, 0}
 		{NULL, 0, NULL, 0}
 	};
 	};
-
+    
 	pid_t init_pid = -1;
 	pid_t init_pid = -1;
 	char *init_pid_str = NULL;
 	char *init_pid_str = NULL;
 	char *console = NULL;
 	char *console = NULL;

+ 7 - 0
vendor/src/github.com/docker/libcontainer/netlink/netlink.go

@@ -21,3 +21,10 @@ type Route struct {
 	Iface   *net.Interface
 	Iface   *net.Interface
 	Default bool
 	Default bool
 }
 }
+
+// An IfAddr defines IP network settings for a given network interface
+type IfAddr struct {
+	Iface *net.Interface
+	IP    net.IP
+	IPNet *net.IPNet
+}

+ 27 - 9
vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go

@@ -651,30 +651,28 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
 	return s.HandleAck(wb.Seq)
 	return s.HandleAck(wb.Seq)
 }
 }
 
 
-// Add an Ip address to an interface. This is identical to:
-// ip addr add $ip/$ipNet dev $iface
-func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+func networkLinkIpAction(action, flags int, ifa IfAddr) error {
 	s, err := getNetlinkSocket()
 	s, err := getNetlinkSocket()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	defer s.Close()
 	defer s.Close()
 
 
-	family := getIpFamily(ip)
+	family := getIpFamily(ifa.IP)
 
 
-	wb := newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	wb := newNetlinkRequest(action, flags)
 
 
 	msg := newIfAddrmsg(family)
 	msg := newIfAddrmsg(family)
-	msg.Index = uint32(iface.Index)
-	prefixLen, _ := ipNet.Mask.Size()
+	msg.Index = uint32(ifa.Iface.Index)
+	prefixLen, _ := ifa.IPNet.Mask.Size()
 	msg.Prefixlen = uint8(prefixLen)
 	msg.Prefixlen = uint8(prefixLen)
 	wb.AddData(msg)
 	wb.AddData(msg)
 
 
 	var ipData []byte
 	var ipData []byte
 	if family == syscall.AF_INET {
 	if family == syscall.AF_INET {
-		ipData = ip.To4()
+		ipData = ifa.IP.To4()
 	} else {
 	} else {
-		ipData = ip.To16()
+		ipData = ifa.IP.To16()
 	}
 	}
 
 
 	localData := newRtAttr(syscall.IFA_LOCAL, ipData)
 	localData := newRtAttr(syscall.IFA_LOCAL, ipData)
@@ -690,6 +688,26 @@ func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
 	return s.HandleAck(wb.Seq)
 	return s.HandleAck(wb.Seq)
 }
 }
 
 
+// Delete an IP address from an interface. This is identical to:
+// ip addr del $ip/$ipNet dev $iface
+func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return networkLinkIpAction(
+		syscall.RTM_DELADDR,
+		syscall.NLM_F_ACK,
+		IfAddr{iface, ip, ipNet},
+	)
+}
+
+// Add an Ip address to an interface. This is identical to:
+// ip addr add $ip/$ipNet dev $iface
+func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return networkLinkIpAction(
+		syscall.RTM_NEWADDR,
+		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
+		IfAddr{iface, ip, ipNet},
+	)
+}
+
 func zeroTerminated(s string) []byte {
 func zeroTerminated(s string) []byte {
 	return []byte(s + "\000")
 	return []byte(s + "\000")
 }
 }

+ 46 - 0
vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go

@@ -2,9 +2,55 @@ package netlink
 
 
 import (
 import (
 	"net"
 	"net"
+	"strings"
 	"testing"
 	"testing"
 )
 )
 
 
+func ipAssigned(iface *net.Interface, ip net.IP) bool {
+	addrs, _ := iface.Addrs()
+
+	for _, addr := range addrs {
+		args := strings.SplitN(addr.String(), "/", 2)
+		if args[0] == ip.String() {
+			return true
+		}
+	}
+
+	return false
+}
+
+func TestAddDelNetworkIp(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	ifaceName := "lo"
+	ip := net.ParseIP("127.0.1.1")
+	mask := net.IPv4Mask(255, 255, 255, 255)
+	ipNet := &net.IPNet{IP: ip, Mask: mask}
+
+	iface, err := net.InterfaceByName(ifaceName)
+	if err != nil {
+		t.Skip("No 'lo' interface; skipping tests")
+	}
+
+	if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
+		t.Fatal(err)
+	}
+
+	if !ipAssigned(iface, ip) {
+		t.Fatalf("Could not locate address '%s' in lo address list.", ip.String())
+	}
+
+	if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
+		t.Fatal(err)
+	}
+
+	if ipAssigned(iface, ip) {
+		t.Fatalf("Located address '%s' in lo address list after removal.", ip.String())
+	}
+}
+
 func TestCreateBridgeWithMac(t *testing.T) {
 func TestCreateBridgeWithMac(t *testing.T) {
 	if testing.Short() {
 	if testing.Short() {
 		return
 		return

+ 4 - 0
vendor/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go

@@ -31,6 +31,10 @@ func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
 	return ErrNotImplemented
 	return ErrNotImplemented
 }
 }
 
 
+func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return ErrNotImplemented
+}
+
 func AddRoute(destination, source, gateway, device string) error {
 func AddRoute(destination, source, gateway, device string) error {
 	return ErrNotImplemented
 	return ErrNotImplemented
 }
 }

+ 8 - 0
vendor/src/github.com/docker/libcontainer/network/network.go

@@ -44,6 +44,14 @@ func SetInterfaceInNamespacePid(name string, nsPid int) error {
 	return netlink.NetworkSetNsPid(iface, nsPid)
 	return netlink.NetworkSetNsPid(iface, nsPid)
 }
 }
 
 
+func SetInterfaceInNamespaceFd(name string, fd uintptr) error {
+	iface, err := net.InterfaceByName(name)
+	if err != nil {
+		return err
+	}
+	return netlink.NetworkSetNsFd(iface, int(fd))
+}
+
 func SetInterfaceMaster(name, master string) error {
 func SetInterfaceMaster(name, master string) error {
 	iface, err := net.InterfaceByName(name)
 	iface, err := net.InterfaceByName(name)
 	if err != nil {
 	if err != nil {

+ 2 - 2
vendor/src/github.com/docker/libcontainer/nsinit/config.go

@@ -1,4 +1,4 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
@@ -15,7 +15,7 @@ var configCommand = cli.Command{
 }
 }
 
 
 func configAction(context *cli.Context) {
 func configAction(context *cli.Context) {
-	container, err := loadContainer()
+	container, err := loadConfig()
 	if err != nil {
 	if err != nil {
 		log.Fatal(err)
 		log.Fatal(err)
 	}
 	}

+ 23 - 5
vendor/src/github.com/docker/libcontainer/nsinit/exec.go

@@ -1,4 +1,4 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"fmt"
 	"fmt"
@@ -8,6 +8,7 @@ import (
 	"os/exec"
 	"os/exec"
 	"os/signal"
 	"os/signal"
 	"syscall"
 	"syscall"
+	"text/tabwriter"
 
 
 	"github.com/codegangsta/cli"
 	"github.com/codegangsta/cli"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/pkg/term"
@@ -20,12 +21,29 @@ var execCommand = cli.Command{
 	Name:   "exec",
 	Name:   "exec",
 	Usage:  "execute a new command inside a container",
 	Usage:  "execute a new command inside a container",
 	Action: execAction,
 	Action: execAction,
+	Flags: []cli.Flag{
+		cli.BoolFlag{Name: "list", Usage: "list all registered exec functions"},
+		cli.StringFlag{Name: "func", Value: "exec", Usage: "function name to exec inside a container"},
+	},
 }
 }
 
 
 func execAction(context *cli.Context) {
 func execAction(context *cli.Context) {
+	if context.Bool("list") {
+		w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
+		fmt.Fprint(w, "NAME\tUSAGE\n")
+
+		for k, f := range argvs {
+			fmt.Fprintf(w, "%s\t%s\n", k, f.Usage)
+		}
+
+		w.Flush()
+
+		return
+	}
+
 	var exitCode int
 	var exitCode int
 
 
-	container, err := loadContainer()
+	container, err := loadConfig()
 	if err != nil {
 	if err != nil {
 		log.Fatal(err)
 		log.Fatal(err)
 	}
 	}
@@ -36,7 +54,7 @@ func execAction(context *cli.Context) {
 	}
 	}
 
 
 	if state != nil {
 	if state != nil {
-		exitCode, err = startInExistingContainer(container, state, context)
+		exitCode, err = startInExistingContainer(container, state, context.String("func"), context)
 	} else {
 	} else {
 		exitCode, err = startContainer(container, dataPath, []string(context.Args()))
 		exitCode, err = startContainer(container, dataPath, []string(context.Args()))
 	}
 	}
@@ -52,7 +70,7 @@ func execAction(context *cli.Context) {
 // with the nsenter argument so that the C code can setns an the namespaces that we require.  Then that
 // with the nsenter argument so that the C code can setns an the namespaces that we require.  Then that
 // code path will drop us into the path that we can do the final setup of the namespace and exec the users
 // code path will drop us into the path that we can do the final setup of the namespace and exec the users
 // application.
 // application.
-func startInExistingContainer(config *libcontainer.Config, state *libcontainer.State, context *cli.Context) (int, error) {
+func startInExistingContainer(config *libcontainer.Config, state *libcontainer.State, action string, context *cli.Context) (int, error) {
 	var (
 	var (
 		master  *os.File
 		master  *os.File
 		console string
 		console string
@@ -102,7 +120,7 @@ func startInExistingContainer(config *libcontainer.Config, state *libcontainer.S
 		}()
 		}()
 	}
 	}
 
 
-	return namespaces.ExecIn(config, state, context.Args(), os.Args[0], stdin, stdout, stderr, console, startCallback)
+	return namespaces.ExecIn(config, state, context.Args(), os.Args[0], action, stdin, stdout, stderr, console, startCallback)
 }
 }
 
 
 // startContainer starts the container. Returns the exit status or -1 and an
 // startContainer starts the container. Returns the exit status or -1 and an

+ 2 - 2
vendor/src/github.com/docker/libcontainer/nsinit/init.go

@@ -1,4 +1,4 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"log"
 	"log"
@@ -26,7 +26,7 @@ var (
 func initAction(context *cli.Context) {
 func initAction(context *cli.Context) {
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 
 
-	container, err := loadContainer()
+	container, err := loadConfig()
 	if err != nil {
 	if err != nil {
 		log.Fatal(err)
 		log.Fatal(err)
 	}
 	}

+ 17 - 14
vendor/src/github.com/docker/libcontainer/nsinit/cli.go → vendor/src/github.com/docker/libcontainer/nsinit/main.go

@@ -1,38 +1,41 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"log"
 	"log"
 	"os"
 	"os"
+	"strings"
 
 
 	"github.com/codegangsta/cli"
 	"github.com/codegangsta/cli"
 )
 )
 
 
 var (
 var (
 	logPath = os.Getenv("log")
 	logPath = os.Getenv("log")
-	argvs   = make(map[string]func())
+	argvs   = make(map[string]*rFunc)
 )
 )
 
 
 func init() {
 func init() {
-	argvs["nsenter"] = nsenter
-}
+	argvs["exec"] = &rFunc{
+		Usage:  "execute a process inside an existing container",
+		Action: nsenterExec,
+	}
 
 
-func preload(context *cli.Context) error {
-	if logPath != "" {
-		if err := openLog(logPath); err != nil {
-			return err
-		}
+	argvs["mknod"] = &rFunc{
+		Usage:  "mknod a device inside an existing container",
+		Action: nsenterMknod,
 	}
 	}
 
 
-	return nil
+	argvs["ip"] = &rFunc{
+		Usage:  "display the container's network interfaces",
+		Action: nsenterIp,
+	}
 }
 }
 
 
-func NsInit() {
+func main() {
 	// we need to check our argv 0 for any registred functions to run instead of the
 	// we need to check our argv 0 for any registred functions to run instead of the
 	// normal cli code path
 	// normal cli code path
-
-	action, exists := argvs[os.Args[0]]
+	f, exists := argvs[strings.TrimPrefix(os.Args[0], "nsenter-")]
 	if exists {
 	if exists {
-		action()
+		runFunc(f)
 
 
 		return
 		return
 	}
 	}

+ 63 - 21
vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go

@@ -1,42 +1,84 @@
-package nsinit
+package main
 
 
 import (
 import (
+	"fmt"
 	"log"
 	"log"
+	"net"
 	"os"
 	"os"
+	"strconv"
+	"strings"
+	"text/tabwriter"
 
 
 	"github.com/docker/libcontainer"
 	"github.com/docker/libcontainer"
+	"github.com/docker/libcontainer/devices"
+	"github.com/docker/libcontainer/mount/nodes"
 	"github.com/docker/libcontainer/namespaces"
 	"github.com/docker/libcontainer/namespaces"
 	_ "github.com/docker/libcontainer/namespaces/nsenter"
 	_ "github.com/docker/libcontainer/namespaces/nsenter"
-	"github.com/docker/libcontainer/syncpipe"
 )
 )
 
 
-func findUserArgs() []string {
-	i := 0
-	for _, a := range os.Args {
-		i++
+// nsenterExec exec's a process inside an existing container
+func nsenterExec(config *libcontainer.Config, args []string) {
+	if err := namespaces.FinalizeSetns(config, args); err != nil {
+		log.Fatalf("failed to nsenter: %s", err)
+	}
+}
 
 
-		if a == "--" {
-			break
-		}
+// nsenterMknod runs mknod inside an existing container
+//
+// mknod <path> <type> <major> <minor>
+func nsenterMknod(config *libcontainer.Config, args []string) {
+	if len(args) != 4 {
+		log.Fatalf("expected mknod to have 4 arguments not %d", len(args))
 	}
 	}
 
 
-	return os.Args[i:]
-}
+	t := rune(args[1][0])
 
 
-// this expects that we already have our namespaces setup by the C initializer
-// we are expected to finalize the namespace and exec the user's application
-func nsenter() {
-	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
+	major, err := strconv.Atoi(args[2])
 	if err != nil {
 	if err != nil {
-		log.Fatalf("unable to create sync pipe: %s", err)
+		log.Fatal(err)
 	}
 	}
 
 
-	var config *libcontainer.Config
-	if err := syncPipe.ReadFromParent(&config); err != nil {
-		log.Fatalf("reading container config from parent: %s", err)
+	minor, err := strconv.Atoi(args[3])
+	if err != nil {
+		log.Fatal(err)
 	}
 	}
 
 
-	if err := namespaces.FinalizeSetns(config, findUserArgs()); err != nil {
-		log.Fatalf("failed to nsenter: %s", err)
+	n := &devices.Device{
+		Path:        args[0],
+		Type:        t,
+		MajorNumber: int64(major),
+		MinorNumber: int64(minor),
+	}
+
+	if err := nodes.CreateDeviceNode("/", n); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// nsenterIp displays the network interfaces inside a container's net namespace
+func nsenterIp(config *libcontainer.Config, args []string) {
+	interfaces, err := net.Interfaces()
+	if err != nil {
+		log.Fatal(err)
 	}
 	}
+
+	w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0)
+	fmt.Fprint(w, "NAME\tMTU\tMAC\tFLAG\tADDRS\n")
+
+	for _, iface := range interfaces {
+		addrs, err := iface.Addrs()
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		o := []string{}
+
+		for _, a := range addrs {
+			o = append(o, a.String())
+		}
+
+		fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\n", iface.Name, iface.MTU, iface.HardwareAddr, iface.Flags, strings.Join(o, ","))
+	}
+
+	w.Flush()
 }
 }

+ 0 - 7
vendor/src/github.com/docker/libcontainer/nsinit/nsinit/nsinit.go

@@ -1,7 +0,0 @@
-package main
-
-import "github.com/docker/libcontainer/nsinit"
-
-func main() {
-	nsinit.NsInit()
-}

+ 2 - 2
vendor/src/github.com/docker/libcontainer/nsinit/pause.go

@@ -1,4 +1,4 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"log"
 	"log"
@@ -34,7 +34,7 @@ func unpauseAction(context *cli.Context) {
 }
 }
 
 
 func toggle(state cgroups.FreezerState) error {
 func toggle(state cgroups.FreezerState) error {
-	container, err := loadContainer()
+	container, err := loadConfig()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 2 - 2
vendor/src/github.com/docker/libcontainer/nsinit/stats.go

@@ -1,4 +1,4 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
@@ -16,7 +16,7 @@ var statsCommand = cli.Command{
 }
 }
 
 
 func statsAction(context *cli.Context) {
 func statsAction(context *cli.Context) {
-	container, err := loadContainer()
+	container, err := loadConfig()
 	if err != nil {
 	if err != nil {
 		log.Fatal(err)
 		log.Fatal(err)
 	}
 	}

+ 54 - 6
vendor/src/github.com/docker/libcontainer/nsinit/utils.go

@@ -1,4 +1,4 @@
-package nsinit
+package main
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
@@ -6,10 +6,18 @@ import (
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 
 
+	"github.com/codegangsta/cli"
 	"github.com/docker/libcontainer"
 	"github.com/docker/libcontainer"
+	"github.com/docker/libcontainer/syncpipe"
 )
 )
 
 
-func loadContainer() (*libcontainer.Config, error) {
+// rFunc is a function registration for calling after an execin
+type rFunc struct {
+	Usage  string
+	Action func(*libcontainer.Config, []string)
+}
+
+func loadConfig() (*libcontainer.Config, error) {
 	f, err := os.Open(filepath.Join(dataPath, "container.json"))
 	f, err := os.Open(filepath.Join(dataPath, "container.json"))
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -35,12 +43,52 @@ func openLog(name string) error {
 	return nil
 	return nil
 }
 }
 
 
-func loadContainerFromJson(rawData string) (*libcontainer.Config, error) {
-	var container *libcontainer.Config
+func findUserArgs() []string {
+	i := 0
+	for _, a := range os.Args {
+		i++
+
+		if a == "--" {
+			break
+		}
+	}
+
+	return os.Args[i:]
+}
 
 
-	if err := json.Unmarshal([]byte(rawData), &container); err != nil {
+// loadConfigFromFd loads a container's config from the sync pipe that is provided by
+// fd 3 when running a process
+func loadConfigFromFd() (*libcontainer.Config, error) {
+	syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
+	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return container, nil
+	var config *libcontainer.Config
+	if err := syncPipe.ReadFromParent(&config); err != nil {
+		return nil, err
+	}
+
+	return config, nil
+}
+
+func preload(context *cli.Context) error {
+	if logPath != "" {
+		if err := openLog(logPath); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func runFunc(f *rFunc) {
+	userArgs := findUserArgs()
+
+	config, err := loadConfigFromFd()
+	if err != nil {
+		log.Fatalf("unable to receive config from sync pipe: %s", err)
+	}
+
+	f.Action(config, userArgs)
 }
 }

+ 3 - 0
vendor/src/github.com/docker/libcontainer/state.go

@@ -18,6 +18,9 @@ type State struct {
 
 
 	// Network runtime state.
 	// Network runtime state.
 	NetworkState network.NetworkState `json:"network_state,omitempty"`
 	NetworkState network.NetworkState `json:"network_state,omitempty"`
+
+	// Path to all the cgroups setup for a container. Key is cgroup subsystem name.
+	CgroupPaths map[string]string `json:"cgroup_paths,omitempty"`
 }
 }
 
 
 // The running state of the container.
 // The running state of the container.