Break down groups into subsystems
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
parent
8cc8aca9cc
commit
bb89b83c68
9 changed files with 247 additions and 172 deletions
|
@ -10,9 +10,28 @@ import (
|
||||||
"github.com/dotcloud/docker/pkg/cgroups"
|
"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
|
root string
|
||||||
cgroup string
|
cgroup string
|
||||||
|
c *cgroups.Cgroup
|
||||||
|
pid int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
|
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)
|
cgroup = filepath.Join(c.Parent, cgroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := &rawCgroup{
|
d := &data{
|
||||||
root: cgroupRoot,
|
root: cgroupRoot,
|
||||||
cgroup: cgroup,
|
cgroup: cgroup,
|
||||||
|
c: c,
|
||||||
|
pid: pid,
|
||||||
}
|
}
|
||||||
for _, g := range []func(*cgroups.Cgroup, int) error{
|
for _, sys := range subsystems {
|
||||||
raw.setupDevices,
|
if err := sys.Set(d); err != nil {
|
||||||
raw.setupMemory,
|
|
||||||
raw.setupCpu,
|
|
||||||
raw.setupCpuset,
|
|
||||||
raw.setupCpuacct,
|
|
||||||
raw.setupBlkio,
|
|
||||||
raw.setupPerfevent,
|
|
||||||
raw.setupFreezer,
|
|
||||||
} {
|
|
||||||
if err := g(c, pid); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return d, nil
|
||||||
return raw, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (raw *rawCgroup) path(subsystem string) (string, error) {
|
func (raw *data) path(subsystem string) (string, error) {
|
||||||
initPath, err := cgroups.GetInitCgroupDir(subsystem)
|
initPath, err := cgroups.GetInitCgroupDir(subsystem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -68,7 +79,7 @@ func (raw *rawCgroup) path(subsystem string) (string, error) {
|
||||||
return filepath.Join(raw.root, subsystem, initPath, raw.cgroup), nil
|
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)
|
path, err := raw.path(subsystem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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) {
|
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
||||||
return "", 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 "", err
|
||||||
}
|
}
|
||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (raw *rawCgroup) setupDevices(c *cgroups.Cgroup, pid int) (err error) {
|
func (raw *data) Cleanup() 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 {
|
|
||||||
get := func(subsystem string) string {
|
get := func(subsystem string) string {
|
||||||
path, _ := raw.path(subsystem)
|
path, _ := raw.path(subsystem)
|
||||||
return path
|
return path
|
||||||
|
|
16
cgroups/fs/blkio.go
Normal file
16
cgroups/fs/blkio.go
Normal file
|
@ -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
|
||||||
|
}
|
23
cgroups/fs/cpu.go
Normal file
23
cgroups/fs/cpu.go
Normal file
|
@ -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
|
||||||
|
}
|
16
cgroups/fs/cpuacct.go
Normal file
16
cgroups/fs/cpuacct.go
Normal file
|
@ -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
|
||||||
|
}
|
28
cgroups/fs/cpuset.go
Normal file
28
cgroups/fs/cpuset.go
Normal file
|
@ -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
|
||||||
|
}
|
61
cgroups/fs/devices.go
Normal file
61
cgroups/fs/devices.go
Normal file
|
@ -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
|
||||||
|
}
|
16
cgroups/fs/freezer.go
Normal file
16
cgroups/fs/freezer.go
Normal file
|
@ -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
|
||||||
|
}
|
41
cgroups/fs/memory.go
Normal file
41
cgroups/fs/memory.go
Normal file
|
@ -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
|
||||||
|
}
|
16
cgroups/fs/perf_event.go
Normal file
16
cgroups/fs/perf_event.go
Normal file
|
@ -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
|
||||||
|
}
|
Loading…
Reference in a new issue