From bb89b83c6850156b0e0c861daa519256b0304013 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 18 Apr 2014 21:55:06 -0700 Subject: [PATCH] Break down groups into subsystems Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- cgroups/fs/apply_raw.go | 202 ++++++--------------------------------- cgroups/fs/blkio.go | 16 ++++ cgroups/fs/cpu.go | 23 +++++ cgroups/fs/cpuacct.go | 16 ++++ cgroups/fs/cpuset.go | 28 ++++++ cgroups/fs/devices.go | 61 ++++++++++++ cgroups/fs/freezer.go | 16 ++++ cgroups/fs/memory.go | 41 ++++++++ cgroups/fs/perf_event.go | 16 ++++ 9 files changed, 247 insertions(+), 172 deletions(-) create mode 100644 cgroups/fs/blkio.go create mode 100644 cgroups/fs/cpu.go create mode 100644 cgroups/fs/cpuacct.go create mode 100644 cgroups/fs/cpuset.go create mode 100644 cgroups/fs/devices.go create mode 100644 cgroups/fs/freezer.go create mode 100644 cgroups/fs/memory.go create mode 100644 cgroups/fs/perf_event.go diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index d8267bf..4f1b379 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -10,9 +10,28 @@ import ( "github.com/dotcloud/docker/pkg/cgroups" ) -type rawCgroup struct { +var ( + subsystems = []subsystem{ + &devicesGroup{}, + &memoryGroup{}, + &cpuGroup{}, + &cpusetGroup{}, + &cpuacctGroup{}, + &blkioGroup{}, + &perfEventGroup{}, + &freezerGroup{}, + } +) + +type subsystem interface { + Set(*data) error +} + +type data struct { root string cgroup string + c *cgroups.Cgroup + pid int } func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { @@ -38,29 +57,21 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { cgroup = filepath.Join(c.Parent, cgroup) } - raw := &rawCgroup{ + d := &data{ root: cgroupRoot, cgroup: cgroup, + c: c, + pid: pid, } - for _, g := range []func(*cgroups.Cgroup, int) error{ - raw.setupDevices, - raw.setupMemory, - raw.setupCpu, - raw.setupCpuset, - raw.setupCpuacct, - raw.setupBlkio, - raw.setupPerfevent, - raw.setupFreezer, - } { - if err := g(c, pid); err != nil { + for _, sys := range subsystems { + if err := sys.Set(d); err != nil { return nil, err } } - - return raw, nil + return d, nil } -func (raw *rawCgroup) path(subsystem string) (string, error) { +func (raw *data) path(subsystem string) (string, error) { initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err @@ -68,7 +79,7 @@ func (raw *rawCgroup) path(subsystem string) (string, error) { return filepath.Join(raw.root, subsystem, initPath, raw.cgroup), nil } -func (raw *rawCgroup) join(subsystem string, pid int) (string, error) { +func (raw *data) join(subsystem string) (string, error) { path, err := raw.path(subsystem) if err != nil { return "", err @@ -76,166 +87,13 @@ func (raw *rawCgroup) join(subsystem string, pid int) (string, error) { if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { return "", err } - if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil { + if err := writeFile(path, "cgroup.procs", strconv.Itoa(raw.pid)); err != nil { return "", err } return path, nil } -func (raw *rawCgroup) setupDevices(c *cgroups.Cgroup, pid int) (err error) { - dir, err := raw.join("devices", pid) - if err != nil { - return err - } - defer func() { - if err != nil { - os.RemoveAll(dir) - } - }() - - if !c.DeviceAccess { - - 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 *cgroups.Cgroup, pid int) (err error) { - dir, err := raw.join("memory", pid) - // only return an error for memory if it was not specified - if err != nil && (c.Memory != 0 || c.MemorySwap != 0) { - return err - } - defer func() { - if err != nil { - os.RemoveAll(dir) - } - }() - - if c.Memory != 0 || c.MemorySwap != 0 { - 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 *cgroups.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 *cgroups.Cgroup, pid int) (err error) { - // we don't want to join this cgroup unless it is specified - if c.CpusetCpus != "" { - dir, err := raw.join("cpuset", pid) - if err != nil && c.CpusetCpus != "" { - 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) setupCpuacct(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("cpuacct", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) setupBlkio(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("blkio", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) setupPerfevent(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("perf_event", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) setupFreezer(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("freezer", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) Cleanup() error { +func (raw *data) Cleanup() error { get := func(subsystem string) string { path, _ := raw.path(subsystem) return path diff --git a/cgroups/fs/blkio.go b/cgroups/fs/blkio.go new file mode 100644 index 0000000..f0096f8 --- /dev/null +++ b/cgroups/fs/blkio.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type blkioGroup struct { +} + +func (s *blkioGroup) Set(d *data) error { + // we just want to join this group even though we don't set anything + if _, err := d.join("blkio"); err != nil && err != cgroups.ErrNotFound { + return err + } + return nil +} diff --git a/cgroups/fs/cpu.go b/cgroups/fs/cpu.go new file mode 100644 index 0000000..33879ba --- /dev/null +++ b/cgroups/fs/cpu.go @@ -0,0 +1,23 @@ +package fs + +import ( + "strconv" +) + +type cpuGroup struct { +} + +func (s *cpuGroup) Set(d *data) error { + // We always want to join the cpu group, to allow fair cpu scheduling + // on a container basis + dir, err := d.join("cpu") + if err != nil { + return err + } + if d.c.CpuShares != 0 { + if err := writeFile(dir, "cpu.shares", strconv.FormatInt(d.c.CpuShares, 10)); err != nil { + return err + } + } + return nil +} diff --git a/cgroups/fs/cpuacct.go b/cgroups/fs/cpuacct.go new file mode 100644 index 0000000..603b100 --- /dev/null +++ b/cgroups/fs/cpuacct.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type cpuacctGroup struct { +} + +func (s *cpuacctGroup) Set(d *data) error { + // we just want to join this group even though we don't set anything + if _, err := d.join("cpuacct"); err != nil && err != cgroups.ErrNotFound { + return err + } + return nil +} diff --git a/cgroups/fs/cpuset.go b/cgroups/fs/cpuset.go new file mode 100644 index 0000000..5108365 --- /dev/null +++ b/cgroups/fs/cpuset.go @@ -0,0 +1,28 @@ +package fs + +import ( + "os" +) + +type cpusetGroup struct { +} + +func (s *cpusetGroup) Set(d *data) error { + // we don't want to join this cgroup unless it is specified + if d.c.CpusetCpus != "" { + dir, err := d.join("cpuset") + if err != nil && d.c.CpusetCpus != "" { + return err + } + defer func() { + if err != nil { + os.RemoveAll(dir) + } + }() + + if err := writeFile(dir, "cpuset.cpus", d.c.CpusetCpus); err != nil { + return err + } + } + return nil +} diff --git a/cgroups/fs/devices.go b/cgroups/fs/devices.go new file mode 100644 index 0000000..769df39 --- /dev/null +++ b/cgroups/fs/devices.go @@ -0,0 +1,61 @@ +package fs + +import ( + "os" +) + +type devicesGroup struct { +} + +func (s *devicesGroup) Set(d *data) error { + dir, err := d.join("devices") + if err != nil { + return err + } + defer func() { + if err != nil { + os.RemoveAll(dir) + } + }() + + if !d.c.DeviceAccess { + 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 +} diff --git a/cgroups/fs/freezer.go b/cgroups/fs/freezer.go new file mode 100644 index 0000000..51db689 --- /dev/null +++ b/cgroups/fs/freezer.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type freezerGroup struct { +} + +func (s *freezerGroup) Set(d *data) error { + // we just want to join this group even though we don't set anything + if _, err := d.join("freezer"); err != nil && err != cgroups.ErrNotFound { + return err + } + return nil +} diff --git a/cgroups/fs/memory.go b/cgroups/fs/memory.go new file mode 100644 index 0000000..cf33d66 --- /dev/null +++ b/cgroups/fs/memory.go @@ -0,0 +1,41 @@ +package fs + +import ( + "os" + "strconv" +) + +type memoryGroup struct { +} + +func (s *memoryGroup) Set(d *data) error { + dir, err := d.join("memory") + // only return an error for memory if it was not specified + if err != nil && (d.c.Memory != 0 || d.c.MemorySwap != 0) { + return err + } + defer func() { + if err != nil { + os.RemoveAll(dir) + } + }() + + if d.c.Memory != 0 || d.c.MemorySwap != 0 { + if d.c.Memory != 0 { + if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil { + return err + } + if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.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 d.c.MemorySwap != -1 { + if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil { + return err + } + } + } + return nil +} diff --git a/cgroups/fs/perf_event.go b/cgroups/fs/perf_event.go new file mode 100644 index 0000000..2af6d7a --- /dev/null +++ b/cgroups/fs/perf_event.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type perfEventGroup struct { +} + +func (s *perfEventGroup) Set(d *data) error { + // we just want to join this group even though we don't set anything + if _, err := d.join("perf_event"); err != nil && err != cgroups.ErrNotFound { + return err + } + return nil +}