diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index 7ed9be81..df7bfb3c 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -31,6 +31,9 @@ type Manager interface { // Returns cgroup paths to save in a state file and to be able to // restore the object later. GetPaths() map[string]string + + // Set the cgroup as configured. + Set(container *configs.Config) error } type NotFoundError struct { diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index ba7dd768..12ece2fe 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -32,6 +32,8 @@ type subsystem interface { Remove(*data) error // Creates and joins the cgroup represented by data. Apply(*data) error + // Set the cgroup represented by cgroup. + Set(path string, cgroup *configs.Cgroup) error } type Manager struct { @@ -147,6 +149,20 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { return stats, nil } +func (m *Manager) Set(container *configs.Config) error { + for name, path := range m.Paths { + sys, ok := subsystems[name] + if !ok || !cgroups.PathExists(path) { + continue + } + if err := sys.Set(path, container.Cgroups); err != nil { + return err + } + } + + return nil +} + // Freeze toggles the container's freezer cgroup depending on the state // provided func (m *Manager) Freeze(state configs.FreezerState) error { diff --git a/cgroups/fs/blkio.go b/cgroups/fs/blkio.go index 87d91128..275b78ed 100644 --- a/cgroups/fs/blkio.go +++ b/cgroups/fs/blkio.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" ) type BlkioGroup struct { @@ -29,6 +30,16 @@ func (s *BlkioGroup) Apply(d *data) error { return nil } +func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.BlkioWeight != 0 { + if err := writeFile(path, "blkio.weight", strconv.FormatInt(cgroup.BlkioWeight, 10)); err != nil { + return err + } + } + + return nil +} + func (s *BlkioGroup) Remove(d *data) error { return removePath(d.path("blkio")) } diff --git a/cgroups/fs/cpu.go b/cgroups/fs/cpu.go index 385625c7..0a5040af 100644 --- a/cgroups/fs/cpu.go +++ b/cgroups/fs/cpu.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" ) type CpuGroup struct { @@ -37,6 +38,26 @@ func (s *CpuGroup) Apply(d *data) error { return nil } +func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.CpuShares != 0 { + if err := writeFile(path, "cpu.shares", strconv.FormatInt(cgroup.CpuShares, 10)); err != nil { + return err + } + } + if cgroup.CpuPeriod != 0 { + if err := writeFile(path, "cpu.cfs_period_us", strconv.FormatInt(cgroup.CpuPeriod, 10)); err != nil { + return err + } + } + if cgroup.CpuQuota != 0 { + if err := writeFile(path, "cpu.cfs_quota_us", strconv.FormatInt(cgroup.CpuQuota, 10)); err != nil { + return err + } + } + + return nil +} + func (s *CpuGroup) Remove(d *data) error { return removePath(d.path("cpu")) } diff --git a/cgroups/fs/cpuacct.go b/cgroups/fs/cpuacct.go index 58378125..decee850 100644 --- a/cgroups/fs/cpuacct.go +++ b/cgroups/fs/cpuacct.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/system" ) @@ -30,6 +31,10 @@ func (s *CpuacctGroup) Apply(d *data) error { return nil } +func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error { + return nil +} + func (s *CpuacctGroup) Remove(d *data) error { return removePath(d.path("cpuacct")) } diff --git a/cgroups/fs/cpuset.go b/cgroups/fs/cpuset.go index d9b3e7b7..54d1aee4 100644 --- a/cgroups/fs/cpuset.go +++ b/cgroups/fs/cpuset.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" ) type CpusetGroup struct { @@ -21,6 +22,22 @@ func (s *CpusetGroup) Apply(d *data) error { return s.ApplyDir(dir, d.c.CpusetCpus, d.c.CpusetMems, d.pid) } +func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.CpusetCpus != "" { + if err := writeFile(path, "cpuset.cpus", cgroup.CpusetCpus); err != nil { + return err + } + } + + if cgroup.CpusetMems != "" { + if err := writeFile(path, "cpuset.mems", cgroup.CpusetMems); err != nil { + return err + } + } + + return nil +} + func (s *CpusetGroup) Remove(d *data) error { return removePath(d.path("cpuset")) } diff --git a/cgroups/fs/devices.go b/cgroups/fs/devices.go index d1fef46f..835cfeef 100644 --- a/cgroups/fs/devices.go +++ b/cgroups/fs/devices.go @@ -1,6 +1,9 @@ package fs -import "github.com/docker/libcontainer/cgroups" +import ( + "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" +) type DevicesGroup struct { } @@ -25,6 +28,22 @@ func (s *DevicesGroup) Apply(d *data) error { return nil } +func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { + if !cgroup.AllowAllDevices { + if err := writeFile(path, "devices.deny", "a"); err != nil { + return err + } + + for _, dev := range cgroup.AllowedDevices { + if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil { + return err + } + } + } + + return nil +} + func (s *DevicesGroup) Remove(d *data) error { return removePath(d.path("devices")) } diff --git a/cgroups/fs/freezer.go b/cgroups/fs/freezer.go index 6e9aef18..738d9c0d 100644 --- a/cgroups/fs/freezer.go +++ b/cgroups/fs/freezer.go @@ -42,6 +42,28 @@ func (s *FreezerGroup) Apply(d *data) error { return nil } +func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error { + switch cgroup.Freezer { + case configs.Frozen, configs.Thawed: + if err := writeFile(path, "freezer.state", string(cgroup.Freezer)); err != nil { + return err + } + + for { + state, err := readFile(path, "freezer.state") + if err != nil { + return err + } + if strings.TrimSpace(state) == string(cgroup.Freezer) { + break + } + time.Sleep(1 * time.Millisecond) + } + } + + return nil +} + func (s *FreezerGroup) Remove(d *data) error { return removePath(d.path("freezer")) } diff --git a/cgroups/fs/memory.go b/cgroups/fs/memory.go index 573c8ab7..828d4b20 100644 --- a/cgroups/fs/memory.go +++ b/cgroups/fs/memory.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" ) type MemoryGroup struct { @@ -53,6 +54,32 @@ func (s *MemoryGroup) Apply(d *data) error { return nil } +func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.Memory != 0 { + if err := writeFile(path, "memory.limit_in_bytes", strconv.FormatInt(cgroup.Memory, 10)); err != nil { + return err + } + } + if cgroup.MemoryReservation != 0 { + if err := writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(cgroup.MemoryReservation, 10)); err != nil { + return err + } + } + // By default, MemorySwap is set to twice the size of Memory. + if cgroup.MemorySwap == 0 && cgroup.Memory != 0 { + if err := writeFile(path, "memory.memsw.limit_in_bytes", strconv.FormatInt(cgroup.Memory*2, 10)); err != nil { + return err + } + } + if cgroup.MemorySwap > 0 { + if err := writeFile(path, "memory.memsw.limit_in_bytes", strconv.FormatInt(cgroup.MemorySwap, 10)); err != nil { + return err + } + } + + return nil +} + func (s *MemoryGroup) Remove(d *data) error { return removePath(d.path("memory")) } diff --git a/cgroups/fs/perf_event.go b/cgroups/fs/perf_event.go index 305b4c05..ca65f734 100644 --- a/cgroups/fs/perf_event.go +++ b/cgroups/fs/perf_event.go @@ -2,6 +2,7 @@ package fs import ( "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/configs" ) type PerfEventGroup struct { @@ -15,6 +16,10 @@ func (s *PerfEventGroup) Apply(d *data) error { return nil } +func (s *PerfEventGroup) Set(path string, cgroup *configs.Cgroup) error { + return nil +} + func (s *PerfEventGroup) Remove(d *data) error { return removePath(d.path("perf_event")) } diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index 8a46ea8b..95ed4ea7 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -38,6 +38,10 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { return nil, fmt.Errorf("Systemd not supported") } +func (m *Manager) Set(container *configs.Config) error { + return nil, fmt.Errorf("Systemd not supported") +} + func (m *Manager) Freeze(state configs.FreezerState) error { return fmt.Errorf("Systemd not supported") } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index 5d45fd6f..7e8fe0a0 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -26,7 +26,10 @@ type Manager struct { } type subsystem interface { - GetStats(string, *cgroups.Stats) error + // Returns the stats, as 'stats', corresponding to the cgroup under 'path'. + GetStats(path string, stats *cgroups.Stats) error + // Set the cgroup represented by cgroup. + Set(path string, cgroup *configs.Cgroup) error } var subsystems = map[string]subsystem{ @@ -323,6 +326,10 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { return stats, nil } +func (m *Manager) Set(container *configs.Config) error { + panic("not implemented") +} + func getUnitName(c *configs.Cgroup) string { return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name) } diff --git a/container_linux_test.go b/container_linux_test.go index 87942a8c..5f589f3d 100644 --- a/container_linux_test.go +++ b/container_linux_test.go @@ -29,6 +29,10 @@ func (m *mockCgroupManager) Apply(pid int) error { return nil } +func (m *mockCgroupManager) Set(container *configs.Config) error { + return nil +} + func (m *mockCgroupManager) Destroy() error { return nil }