Merge pull request #376 from hqhq/hq_add_set_interface

add a new api Set
This commit is contained in:
Mrunal Patel 2015-03-03 19:57:55 -08:00
commit 3ca0e1ff95
22 changed files with 459 additions and 76 deletions

View File

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

View File

@ -31,7 +31,9 @@ type subsystem interface {
// Removes the cgroup represented by 'data'.
Remove(*data) error
// Creates and joins the cgroup represented by data.
Set(*data) error
Apply(*data) error
// Set the cgroup represented by cgroup.
Set(path string, cgroup *configs.Cgroup) error
}
type Manager struct {
@ -91,7 +93,7 @@ func (m *Manager) Apply(pid int) error {
}
}()
for name, sys := range subsystems {
if err := sys.Set(d); err != nil {
if err := sys.Apply(d); err != nil {
return err
}
// TODO: Apply should, ideally, be reentrant or be broken up into a separate
@ -129,7 +131,7 @@ func ApplyDevices(c *configs.Cgroup, pid int) error {
devices := subsystems["devices"]
return devices.Set(d)
return devices.Apply(d)
}
func (m *Manager) GetStats() (*cgroups.Stats, error) {
@ -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 {
@ -159,7 +175,7 @@ func (m *Manager) Freeze(state configs.FreezerState) error {
m.Cgroups.Freezer = state
freezer := subsystems["freezer"]
err = freezer.Set(d)
err = freezer.Apply(d)
if err != nil {
m.Cgroups.Freezer = prevState
return err

View File

@ -9,19 +9,28 @@ import (
"strings"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
)
type BlkioGroup struct {
}
func (s *BlkioGroup) Set(d *data) error {
func (s *BlkioGroup) Apply(d *data) error {
dir, err := d.join("blkio")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
if d.c.BlkioWeight != 0 {
if err := writeFile(dir, "blkio.weight", strconv.FormatInt(d.c.BlkioWeight, 10)); err != nil {
if err := s.Set(dir, d.c); err != nil {
return err
}
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
}
}

View File

@ -1,6 +1,7 @@
package fs
import (
"strconv"
"testing"
"github.com/docker/libcontainer/cgroups"
@ -72,6 +73,35 @@ func appendBlkioStatEntry(blkioStatEntries *[]cgroups.BlkioStatEntry, major, min
*blkioStatEntries = append(*blkioStatEntries, cgroups.BlkioStatEntry{Major: major, Minor: minor, Value: value, Op: op})
}
func TestBlkioSetWeight(t *testing.T) {
helper := NewCgroupTestUtil("blkio", t)
defer helper.cleanup()
const (
weightBefore = 100
weightAfter = 200
)
helper.writeFileContents(map[string]string{
"blkio.weight": strconv.Itoa(weightBefore),
})
helper.CgroupData.c.BlkioWeight = weightAfter
blkio := &BlkioGroup{}
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
value, err := getCgroupParamUint(helper.CgroupPath, "blkio.weight")
if err != nil {
t.Fatalf("Failed to parse blkio.weight - %s", err)
}
if value != weightAfter {
t.Fatal("Got the wrong value, set blkio.weight failed.")
}
}
func TestBlkioStats(t *testing.T) {
helper := NewCgroupTestUtil("blkio", t)
defer helper.cleanup()

View File

@ -7,33 +7,44 @@ import (
"strconv"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
)
type CpuGroup struct {
}
func (s *CpuGroup) Set(d *data) error {
func (s *CpuGroup) Apply(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 {
if err := s.Set(dir, d.c); err != nil {
return err
}
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 d.c.CpuPeriod != 0 {
if err := writeFile(dir, "cpu.cfs_period_us", strconv.FormatInt(d.c.CpuPeriod, 10)); err != nil {
if cgroup.CpuPeriod != 0 {
if err := writeFile(path, "cpu.cfs_period_us", strconv.FormatInt(cgroup.CpuPeriod, 10)); err != nil {
return err
}
}
if d.c.CpuQuota != 0 {
if err := writeFile(dir, "cpu.cfs_quota_us", strconv.FormatInt(d.c.CpuQuota, 10)); err != nil {
if cgroup.CpuQuota != 0 {
if err := writeFile(path, "cpu.cfs_quota_us", strconv.FormatInt(cgroup.CpuQuota, 10)); err != nil {
return err
}
}
return nil
}

View File

@ -2,11 +2,81 @@ package fs
import (
"fmt"
"strconv"
"testing"
"github.com/docker/libcontainer/cgroups"
)
func TestCpuSetShares(t *testing.T) {
helper := NewCgroupTestUtil("cpu", t)
defer helper.cleanup()
const (
sharesBefore = 1024
sharesAfter = 512
)
helper.writeFileContents(map[string]string{
"cpu.shares": strconv.Itoa(sharesBefore),
})
helper.CgroupData.c.CpuShares = sharesAfter
cpu := &CpuGroup{}
if err := cpu.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
value, err := getCgroupParamUint(helper.CgroupPath, "cpu.shares")
if err != nil {
t.Fatalf("Failed to parse cpu.shares - %s", err)
}
if value != sharesAfter {
t.Fatal("Got the wrong value, set cpu.shares failed.")
}
}
func TestCpuSetBandWidth(t *testing.T) {
helper := NewCgroupTestUtil("cpu", t)
defer helper.cleanup()
const (
quotaBefore = 8000
quotaAfter = 5000
periodBefore = 10000
periodAfter = 7000
)
helper.writeFileContents(map[string]string{
"cpu.cfs_quota_us": strconv.Itoa(quotaBefore),
"cpu.cfs_period_us": strconv.Itoa(periodBefore),
})
helper.CgroupData.c.CpuQuota = quotaAfter
helper.CgroupData.c.CpuPeriod = periodAfter
cpu := &CpuGroup{}
if err := cpu.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
quota, err := getCgroupParamUint(helper.CgroupPath, "cpu.cfs_quota_us")
if err != nil {
t.Fatalf("Failed to parse cpu.cfs_quota_us - %s", err)
}
if quota != quotaAfter {
t.Fatal("Got the wrong value, set cpu.cfs_quota_us failed.")
}
period, err := getCgroupParamUint(helper.CgroupPath, "cpu.cfs_period_us")
if err != nil {
t.Fatalf("Failed to parse cpu.cfs_period_us - %s", err)
}
if period != periodAfter {
t.Fatal("Got the wrong value, set cpu.cfs_period_us failed.")
}
}
func TestCpuStats(t *testing.T) {
helper := NewCgroupTestUtil("cpu", t)
defer helper.cleanup()

View File

@ -8,6 +8,7 @@ import (
"strings"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
"github.com/docker/libcontainer/system"
)
@ -21,7 +22,7 @@ var clockTicks = uint64(system.GetClockTicks())
type CpuacctGroup struct {
}
func (s *CpuacctGroup) Set(d *data) error {
func (s *CpuacctGroup) Apply(d *data) error {
// we just want to join this group even though we don't set anything
if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) {
return err
@ -30,6 +31,10 @@ func (s *CpuacctGroup) Set(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"))
}

View File

@ -8,17 +8,34 @@ import (
"strconv"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
)
type CpusetGroup struct {
}
func (s *CpusetGroup) Set(d *data) error {
func (s *CpusetGroup) Apply(d *data) error {
dir, err := d.path("cpuset")
if err != nil {
return err
}
return s.SetDir(dir, d.c.CpusetCpus, d.c.CpusetMems, d.pid)
return s.ApplyDir(dir, d.c, 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 {
@ -29,7 +46,7 @@ func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *CpusetGroup) SetDir(dir, cpus string, mems string, pid int) error {
func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) error {
if err := s.ensureParent(dir); err != nil {
return err
}
@ -40,17 +57,10 @@ func (s *CpusetGroup) SetDir(dir, cpus string, mems string, pid int) error {
return err
}
// If we don't use --cpuset-xxx, the default value inherit from parent cgroup
// is set in s.ensureParent, otherwise, use the value we set
if cpus != "" {
if err := writeFile(dir, "cpuset.cpus", cpus); err != nil {
return err
}
}
if mems != "" {
if err := writeFile(dir, "cpuset.mems", mems); err != nil {
return err
}
// the default values inherit from parent cgroup are already set in
// s.ensureParent, cover these if we have our own
if err := s.Set(dir, cgroup); err != nil {
return err
}
return nil

63
cgroups/fs/cpuset_test.go Normal file
View File

@ -0,0 +1,63 @@
package fs
import (
"testing"
)
func TestCpusetSetCpus(t *testing.T) {
helper := NewCgroupTestUtil("cpuset", t)
defer helper.cleanup()
const (
cpusBefore = "0"
cpusAfter = "1-3"
)
helper.writeFileContents(map[string]string{
"cpuset.cpus": cpusBefore,
})
helper.CgroupData.c.CpusetCpus = cpusAfter
cpuset := &CpusetGroup{}
if err := cpuset.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
value, err := getCgroupParamString(helper.CgroupPath, "cpuset.cpus")
if err != nil {
t.Fatalf("Failed to parse cpuset.cpus - %s", err)
}
if value != cpusAfter {
t.Fatal("Got the wrong value, set cpuset.cpus failed.")
}
}
func TestCpusetSetMems(t *testing.T) {
helper := NewCgroupTestUtil("cpuset", t)
defer helper.cleanup()
const (
memsBefore = "0"
memsAfter = "1"
)
helper.writeFileContents(map[string]string{
"cpuset.mems": memsBefore,
})
helper.CgroupData.c.CpusetMems = memsAfter
cpuset := &CpusetGroup{}
if err := cpuset.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
value, err := getCgroupParamString(helper.CgroupPath, "cpuset.mems")
if err != nil {
t.Fatalf("Failed to parse cpuset.mems - %s", err)
}
if value != memsAfter {
t.Fatal("Got the wrong value, set cpuset.mems failed.")
}
}

View File

@ -1,27 +1,39 @@
package fs
import "github.com/docker/libcontainer/cgroups"
import (
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
)
type DevicesGroup struct {
}
func (s *DevicesGroup) Set(d *data) error {
func (s *DevicesGroup) Apply(d *data) error {
dir, err := d.join("devices")
if err != nil {
return err
}
if !d.c.AllowAllDevices {
if err := writeFile(dir, "devices.deny", "a"); err != nil {
if err := s.Set(dir, d.c); err != nil {
return err
}
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 d.c.AllowedDevices {
if err := writeFile(dir, "devices.allow", dev.CgroupString()); err != nil {
for _, dev := range cgroup.AllowedDevices {
if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
return err
}
}
}
return nil
}

View File

@ -0,0 +1,48 @@
package fs
import (
"testing"
"github.com/docker/libcontainer/configs"
)
var (
allowedDevices = []*configs.Device{
{
Path: "/dev/zero",
Type: 'c',
Major: 1,
Minor: 5,
Permissions: "rwm",
FileMode: 0666,
},
}
allowedList = "c 1:5 rwm"
)
func TestDevicesSetAllow(t *testing.T) {
helper := NewCgroupTestUtil("devices", t)
defer helper.cleanup()
helper.writeFileContents(map[string]string{
"device.deny": "a",
})
helper.CgroupData.c.AllowAllDevices = false
helper.CgroupData.c.AllowedDevices = allowedDevices
devices := &DevicesGroup{}
if err := devices.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
// FIXME: this doesn't make sence, the file devices.allow under real cgroupfs
// is not allowed to read. Our test path don't have cgroupfs mounted.
value, err := getCgroupParamString(helper.CgroupPath, "devices.allow")
if err != nil {
t.Fatalf("Failed to parse devices.allow - %s", err)
}
if value != allowedList {
t.Fatal("Got the wrong value, set devices.allow failed.")
}
}

View File

@ -11,7 +11,7 @@ import (
type FreezerGroup struct {
}
func (s *FreezerGroup) Set(d *data) error {
func (s *FreezerGroup) Apply(d *data) error {
switch d.c.Freezer {
case configs.Frozen, configs.Thawed:
dir, err := d.path("freezer")
@ -19,20 +19,9 @@ func (s *FreezerGroup) Set(d *data) error {
return err
}
if err := writeFile(dir, "freezer.state", string(d.c.Freezer)); err != nil {
if err := s.Set(dir, d.c); err != nil {
return err
}
for {
state, err := readFile(dir, "freezer.state")
if err != nil {
return err
}
if strings.TrimSpace(state) == string(d.c.Freezer) {
break
}
time.Sleep(1 * time.Millisecond)
}
default:
if _, err := d.join("freezer"); err != nil && !cgroups.IsNotFound(err) {
return err
@ -42,6 +31,28 @@ func (s *FreezerGroup) Set(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"))
}

View File

@ -8,12 +8,13 @@ import (
"strconv"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
)
type MemoryGroup struct {
}
func (s *MemoryGroup) Set(d *data) error {
func (s *MemoryGroup) Apply(d *data) error {
dir, err := d.join("memory")
// only return an error for memory if it was specified
if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
@ -25,31 +26,36 @@ func (s *MemoryGroup) Set(d *data) error {
}
}()
// Only set values if some config was specified.
if d.c.Memory != 0 || d.c.MemoryReservation != 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 d.c.MemoryReservation != 0 {
if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.c.MemoryReservation, 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 == 0 {
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil {
return err
}
}
if d.c.MemorySwap > 0 {
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.MemorySwap, 10)); err != nil {
return err
}
if err := s.Set(dir, d.c); err != nil {
return err
}
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
}

View File

@ -1,6 +1,7 @@
package fs
import (
"strconv"
"testing"
"github.com/docker/libcontainer/cgroups"
@ -14,6 +15,46 @@ rss 1024`
memoryFailcnt = "100\n"
)
func TestMemorySetMemory(t *testing.T) {
helper := NewCgroupTestUtil("memory", t)
defer helper.cleanup()
const (
memoryBefore = 314572800 // 300M
memoryAfter = 524288000 // 500M
reservationBefore = 209715200 // 200M
reservationAfter = 314572800 // 300M
)
helper.writeFileContents(map[string]string{
"memory.limit_in_bytes": strconv.Itoa(memoryBefore),
"memory.soft_limit_in_bytes": strconv.Itoa(reservationBefore),
})
helper.CgroupData.c.Memory = memoryAfter
helper.CgroupData.c.MemoryReservation = reservationAfter
memory := &MemoryGroup{}
if err := memory.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
t.Fatal(err)
}
value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes")
if err != nil {
t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err)
}
if value != memoryAfter {
t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.")
}
value, err = getCgroupParamUint(helper.CgroupPath, "memory.soft_limit_in_bytes")
if err != nil {
t.Fatalf("Failed to parse memory.soft_limit_in_bytes - %s", err)
}
if value != reservationAfter {
t.Fatal("Got the wrong value, set memory.soft_limit_in_bytes failed.")
}
}
func TestMemoryStats(t *testing.T) {
helper := NewCgroupTestUtil("memory", t)
defer helper.cleanup()

View File

@ -2,12 +2,13 @@ package fs
import (
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/configs"
)
type PerfEventGroup struct {
}
func (s *PerfEventGroup) Set(d *data) error {
func (s *PerfEventGroup) Apply(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 && !cgroups.IsNotFound(err) {
return err
@ -15,6 +16,10 @@ func (s *PerfEventGroup) Set(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"))
}

View File

@ -10,6 +10,8 @@ import (
"io/ioutil"
"os"
"testing"
"github.com/docker/libcontainer/configs"
)
type cgroupTestUtil struct {
@ -26,7 +28,9 @@ type cgroupTestUtil struct {
// Creates a new test util for the specified subsystem
func NewCgroupTestUtil(subsystem string, t *testing.T) *cgroupTestUtil {
d := &data{}
d := &data{
c: &configs.Cgroup{},
}
tempDir, err := ioutil.TempDir("", fmt.Sprintf("%s_cgroup_test", subsystem))
if err != nil {
t.Fatal(err)

View File

@ -60,3 +60,13 @@ func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) {
return parseUint(strings.TrimSpace(string(contents)), 10, 64)
}
// Gets a string value from the specified cgroup file
func getCgroupParamString(cgroupPath, cgroupFile string) (string, error) {
contents, err := ioutil.ReadFile(filepath.Join(cgroupPath, cgroupFile))
if err != nil {
return "", err
}
return strings.TrimSpace(string(contents)), nil
}

View File

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

View File

@ -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)
}
@ -398,5 +405,5 @@ func joinCpuset(c *configs.Cgroup, pid int) error {
s := &fs.CpusetGroup{}
return s.SetDir(path, c.CpusetCpus, c.CpusetMems, pid)
return s.ApplyDir(path, c, pid)
}

View File

@ -90,6 +90,14 @@ type Container interface {
// Systemerror - System error.
Stats() (*Stats, error)
// Set cgroup resources of container as configured
//
// We can use this to change resources when containers are running.
//
// errors:
// Systemerror - System error.
Set() error
// Start a process inside the container. Returns error if process fails to
// start. You can track process lifecycle with passed Process structure.
//

View File

@ -78,6 +78,12 @@ func (c *linuxContainer) Stats() (*Stats, error) {
return stats, nil
}
func (c *linuxContainer) Set() error {
c.m.Lock()
defer c.m.Unlock()
return c.cgroupManager.Set(c.config)
}
func (c *linuxContainer) Start(process *Process) error {
c.m.Lock()
defer c.m.Unlock()

View File

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