summaryrefslogtreecommitdiff
path: root/pkg/cgroups/apply_raw.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/cgroups/apply_raw.go')
-rw-r--r--pkg/cgroups/apply_raw.go216
1 files changed, 216 insertions, 0 deletions
diff --git a/pkg/cgroups/apply_raw.go b/pkg/cgroups/apply_raw.go
new file mode 100644
index 0000000000..220f08f1dc
--- /dev/null
+++ b/pkg/cgroups/apply_raw.go
@@ -0,0 +1,216 @@
+package cgroups
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strconv"
+)
+
+type rawCgroup struct {
+ root string
+ cgroup string
+}
+
+func rawApply(c *Cgroup, pid int) (ActiveCgroup, error) {
+ // We have two implementation of cgroups support, one is based on
+ // systemd and the dbus api, and one is based on raw cgroup fs operations
+ // following the pre-single-writer model docs at:
+ // http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups/
+ //
+ // we can pick any subsystem to find the root
+
+ cgroupRoot, err := FindCgroupMountpoint("cpu")
+ if err != nil {
+ return nil, err
+ }
+ cgroupRoot = filepath.Dir(cgroupRoot)
+
+ if _, err := os.Stat(cgroupRoot); err != nil {
+ return nil, fmt.Errorf("cgroups fs not found")
+ }
+
+ cgroup := c.Name
+ if c.Parent != "" {
+ cgroup = filepath.Join(c.Parent, cgroup)
+ }
+
+ raw := &rawCgroup{
+ root: cgroupRoot,
+ cgroup: cgroup,
+ }
+
+ if err := raw.setupDevices(c, pid); err != nil {
+ return nil, err
+ }
+ if err := raw.setupMemory(c, pid); err != nil {
+ return nil, err
+ }
+ if err := raw.setupCpu(c, pid); err != nil {
+ return nil, err
+ }
+ if err := raw.setupCpuset(c, pid); err != nil {
+ return nil, err
+ }
+ return raw, nil
+}
+
+func (raw *rawCgroup) path(subsystem string) (string, error) {
+ initPath, err := GetInitCgroupDir(subsystem)
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(raw.root, subsystem, initPath, raw.cgroup), nil
+}
+
+func (raw *rawCgroup) join(subsystem string, pid int) (string, error) {
+ path, err := raw.path(subsystem)
+ if err != nil {
+ return "", err
+ }
+ if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+ return "", err
+ }
+ if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
+ return "", err
+ }
+ return path, nil
+}
+
+func (raw *rawCgroup) setupDevices(c *Cgroup, pid int) (err error) {
+ if !c.DeviceAccess {
+ dir, err := raw.join("devices", pid)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ if err != nil {
+ os.RemoveAll(dir)
+ }
+ }()
+
+ if err := writeFile(dir, "devices.deny", "a"); err != nil {
+ return err
+ }
+
+ allow := []string{
+ // allow mknod for any device
+ "c *:* m",
+ "b *:* m",
+
+ // /dev/null, zero, full
+ "c 1:3 rwm",
+ "c 1:5 rwm",
+ "c 1:7 rwm",
+
+ // consoles
+ "c 5:1 rwm",
+ "c 5:0 rwm",
+ "c 4:0 rwm",
+ "c 4:1 rwm",
+
+ // /dev/urandom,/dev/random
+ "c 1:9 rwm",
+ "c 1:8 rwm",
+
+ // /dev/pts/ - pts namespaces are "coming soon"
+ "c 136:* rwm",
+ "c 5:2 rwm",
+
+ // tuntap
+ "c 10:200 rwm",
+ }
+
+ for _, val := range allow {
+ if err := writeFile(dir, "devices.allow", val); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (raw *rawCgroup) setupMemory(c *Cgroup, pid int) (err error) {
+ if c.Memory != 0 || c.MemorySwap != 0 {
+ dir, err := raw.join("memory", pid)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ os.RemoveAll(dir)
+ }
+ }()
+
+ if c.Memory != 0 {
+ if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(c.Memory, 10)); err != nil {
+ return err
+ }
+ if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(c.Memory, 10)); err != nil {
+ return err
+ }
+ }
+ // By default, MemorySwap is set to twice the size of RAM.
+ // If you want to omit MemorySwap, set it to `-1'.
+ if c.MemorySwap != -1 {
+ if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(c.Memory*2, 10)); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (raw *rawCgroup) setupCpu(c *Cgroup, pid int) (err error) {
+ // We always want to join the cpu group, to allow fair cpu scheduling
+ // on a container basis
+ dir, err := raw.join("cpu", pid)
+ if err != nil {
+ return err
+ }
+ if c.CpuShares != 0 {
+ if err := writeFile(dir, "cpu.shares", strconv.FormatInt(c.CpuShares, 10)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (raw *rawCgroup) setupCpuset(c *Cgroup, pid int) (err error) {
+ if c.CpusetCpus != "" {
+ dir, err := raw.join("cpuset", pid)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ os.RemoveAll(dir)
+ }
+ }()
+
+ if err := writeFile(dir, "cpuset.cpus", c.CpusetCpus); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (raw *rawCgroup) Cleanup() error {
+ get := func(subsystem string) string {
+ path, _ := raw.path(subsystem)
+ return path
+ }
+
+ for _, path := range []string{
+ get("memory"),
+ get("devices"),
+ get("cpu"),
+ get("cpuset"),
+ } {
+ if path != "" {
+ os.RemoveAll(path)
+ }
+ }
+ return nil
+}