From f1301c9378f9d206da5ddbe304a5426f272703c8 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Tue, 1 Mar 2016 16:53:56 -0800 Subject: [PATCH] Fixed the logic of cgroup creation --- Godeps/Godeps.json | 5 ++ client/driver/executor/executor_linux.go | 7 +- .../runc/libcontainer/utils/utils.go | 86 +++++++++++++++++++ .../runc/libcontainer/utils/utils_test.go | 25 ++++++ .../runc/libcontainer/utils/utils_unix.go | 33 +++++++ 5 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go create mode 100644 vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 529f984bb800..7113d7100864 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -443,6 +443,11 @@ "Comment": "v0.0.8-59-g53e4dd6", "Rev": "53e4dd65f5de928ae6deaf2de2c0596e741cbaaa" }, + { + "ImportPath": "github.com/opencontainers/runc/libcontainer/utils", + "Comment": "v0.0.8-59-g53e4dd6", + "Rev": "53e4dd65f5de928ae6deaf2de2c0596e741cbaaa" + }, { "ImportPath": "github.com/ryanuber/columnize", "Comment": "v2.0.1-8-g983d3a5", diff --git a/client/driver/executor/executor_linux.go b/client/driver/executor/executor_linux.go index b86ae5f7f466..9db338fc081e 100644 --- a/client/driver/executor/executor_linux.go +++ b/client/driver/executor/executor_linux.go @@ -82,7 +82,12 @@ func (e *UniversalExecutor) applyLimits(pid int) error { func (e *UniversalExecutor) configureCgroups(resources *structs.Resources) error { e.groups = &cgroupConfig.Cgroup{} e.groups.Resources = &cgroupConfig.Resources{} - e.groups.Name = structs.GenerateUUID() + cgroupName := structs.GenerateUUID() + cgPath, err := cgroups.GetThisCgroupDir("devices") + if err != nil { + return fmt.Errorf("unable to get mount point for devices sub-system: %v", err) + } + e.groups.Path = filepath.Join(cgPath, cgroupName) // TODO: verify this is needed for things like network access e.groups.Resources.AllowAllDevices = true diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go new file mode 100644 index 000000000000..68ae3c477b4e --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -0,0 +1,86 @@ +package utils + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "io" + "os" + "path/filepath" + "syscall" +) + +const ( + exitSignalOffset = 128 +) + +// GenerateRandomName returns a new name joined with a prefix. This size +// specified is used to truncate the randomly generated value +func GenerateRandomName(prefix string, size int) (string, error) { + id := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, id); err != nil { + return "", err + } + if size > 64 { + size = 64 + } + return prefix + hex.EncodeToString(id)[:size], nil +} + +// ResolveRootfs ensures that the current working directory is +// not a symlink and returns the absolute path to the rootfs +func ResolveRootfs(uncleanRootfs string) (string, error) { + rootfs, err := filepath.Abs(uncleanRootfs) + if err != nil { + return "", err + } + return filepath.EvalSymlinks(rootfs) +} + +// ExitStatus returns the correct exit status for a process based on if it +// was signaled or exited cleanly +func ExitStatus(status syscall.WaitStatus) int { + if status.Signaled() { + return exitSignalOffset + int(status.Signal()) + } + return status.ExitStatus() +} + +// WriteJSON writes the provided struct v to w using standard json marshaling +func WriteJSON(w io.Writer, v interface{}) error { + data, err := json.Marshal(v) + if err != nil { + return err + } + _, err = w.Write(data) + return err +} + +// CleanPath makes a path safe for use with filepath.Join. This is done by not +// only cleaning the path, but also (if the path is relative) adding a leading +// '/' and cleaning it (then removing the leading '/'). This ensures that a +// path resulting from prepending another path will always resolve to lexically +// be a subdirectory of the prefixed path. This is all done lexically, so paths +// that include symlinks won't be safe as a result of using CleanPath. +func CleanPath(path string) string { + // Deal with empty strings nicely. + if path == "" { + return "" + } + + // Ensure that all paths are cleaned (especially problematic ones like + // "/../../../../../" which can cause lots of issues). + path = filepath.Clean(path) + + // If the path isn't absolute, we need to do more processing to fix paths + // such as "../../../..//some/path". We also shouldn't convert absolute + // paths to relative ones. + if !filepath.IsAbs(path) { + path = filepath.Clean(string(os.PathSeparator) + path) + // This can't fail, as (by definition) all paths are relative to root. + path, _ = filepath.Rel(string(os.PathSeparator), path) + } + + // Clean the path again for good measure. + return filepath.Clean(path) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go new file mode 100644 index 000000000000..813180a8a44b --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go @@ -0,0 +1,25 @@ +package utils + +import "testing" + +func TestGenerateName(t *testing.T) { + name, err := GenerateRandomName("veth", 5) + if err != nil { + t.Fatal(err) + } + + expected := 5 + len("veth") + if len(name) != expected { + t.Fatalf("expected name to be %d chars but received %d", expected, len(name)) + } + + name, err = GenerateRandomName("veth", 65) + if err != nil { + t.Fatal(err) + } + + expected = 64 + len("veth") + if len(name) != expected { + t.Fatalf("expected name to be %d chars but received %d", expected, len(name)) + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go new file mode 100644 index 000000000000..408918f27dad --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go @@ -0,0 +1,33 @@ +// +build !windows + +package utils + +import ( + "io/ioutil" + "strconv" + "syscall" +) + +func CloseExecFrom(minFd int) error { + fdList, err := ioutil.ReadDir("/proc/self/fd") + if err != nil { + return err + } + for _, fi := range fdList { + fd, err := strconv.Atoi(fi.Name()) + if err != nil { + // ignore non-numeric file names + continue + } + + if fd < minFd { + // ignore descriptors lower than our specified minimum + continue + } + + // intentionally ignore errors from syscall.CloseOnExec + syscall.CloseOnExec(fd) + // the cases where this might fail are basically file descriptors that have already been closed (including and especially the one that was created when ioutil.ReadDir did the "opendir" syscall) + } + return nil +}