Fixed the logic of cgroup creation

This commit is contained in:
Diptanu Choudhury 2016-03-01 16:53:56 -08:00
parent f750ae3f4e
commit 5748bd0516
5 changed files with 155 additions and 1 deletions

5
Godeps/Godeps.json generated
View File

@ -443,6 +443,11 @@
"Comment": "v0.0.8-59-g53e4dd6", "Comment": "v0.0.8-59-g53e4dd6",
"Rev": "53e4dd65f5de928ae6deaf2de2c0596e741cbaaa" "Rev": "53e4dd65f5de928ae6deaf2de2c0596e741cbaaa"
}, },
{
"ImportPath": "github.com/opencontainers/runc/libcontainer/utils",
"Comment": "v0.0.8-59-g53e4dd6",
"Rev": "53e4dd65f5de928ae6deaf2de2c0596e741cbaaa"
},
{ {
"ImportPath": "github.com/ryanuber/columnize", "ImportPath": "github.com/ryanuber/columnize",
"Comment": "v2.0.1-8-g983d3a5", "Comment": "v2.0.1-8-g983d3a5",

View File

@ -82,7 +82,12 @@ func (e *UniversalExecutor) applyLimits(pid int) error {
func (e *UniversalExecutor) configureCgroups(resources *structs.Resources) error { func (e *UniversalExecutor) configureCgroups(resources *structs.Resources) error {
e.groups = &cgroupConfig.Cgroup{} e.groups = &cgroupConfig.Cgroup{}
e.groups.Resources = &cgroupConfig.Resources{} 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 // TODO: verify this is needed for things like network access
e.groups.Resources.AllowAllDevices = true e.groups.Resources.AllowAllDevices = true

View File

@ -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 "../../../../<etc>/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)
}

View File

@ -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))
}
}

View File

@ -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
}