From 6dd7552537728a120a47f3575d1de342f1be8070 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 13 Jan 2015 00:54:00 +0300 Subject: [PATCH 1/7] new-api: implement fs and systemd cgroup managers Signed-off-by: Andrey Vagin --- cgroup_manager.go | 30 ------------------ cgroups/cgroups.go | 11 +++++++ cgroups/fs/apply_raw.go | 43 +++++++++++++++++++------ cgroups/manager/manager.go | 19 ++++++++++++ cgroups/systemd/apply_nosystemd.go | 23 ++++++++++++-- cgroups/systemd/apply_systemd.go | 50 ++++++++++++++++++++---------- linux_container.go | 5 +-- linux_container_test.go | 15 +++++++++ linux_factory.go | 6 ++-- namespaces/exec.go | 23 +++----------- 10 files changed, 144 insertions(+), 81 deletions(-) delete mode 100644 cgroup_manager.go create mode 100644 cgroups/manager/manager.go diff --git a/cgroup_manager.go b/cgroup_manager.go deleted file mode 100644 index 1bcb1bc4..00000000 --- a/cgroup_manager.go +++ /dev/null @@ -1,30 +0,0 @@ -package libcontainer - -import ( - "github.com/docker/libcontainer/cgroups" -) - -// TODO(vmarmol): Move this to cgroups and rename to Manager. -type CgroupManager interface { - GetPids() ([]int, error) - GetStats() (*cgroups.Stats, error) -} - -func NewCgroupManager() CgroupManager { - return &fsManager{} -} - -type fsManager struct { -} - -func (m *fsManager) GetPids() ([]int, error) { - // TODO(vmarmol): Implement - //return fs.GetPids(config) - panic("not implemented") -} - -func (m *fsManager) GetStats() (*cgroups.Stats, error) { - // TODO(vmarmol): Implement - //return fs.GetStats(config) - panic("not implemented") -} diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index fe360059..0ce7cc97 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -6,6 +6,17 @@ import ( "github.com/docker/libcontainer/devices" ) +type Manager interface { + Apply(pid int) error + + GetPids() ([]int, error) + GetStats() (*Stats, error) + + RemovePaths() error + GetPaths() map[string]string + SetPaths(map[string]string) +} + type FreezerState string const ( diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 6f85793d..68789286 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -24,6 +24,11 @@ var ( CgroupProcesses = "cgroup.procs" ) +type Manager struct { + Cgroups *cgroups.Cgroup + paths map[string]string +} + // The absolute path to the root of the cgroup hierarchies. var cgroupRoot string @@ -57,10 +62,14 @@ type data struct { pid int } -func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { - d, err := getCgroupData(c, pid) +func (m *Manager) Apply(pid int) error { + if m.Cgroups == nil { + return nil + } + + d, err := getCgroupData(m.Cgroups, pid) if err != nil { - return nil, err + return err } paths := make(map[string]string) @@ -71,7 +80,7 @@ func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { }() for name, sys := range subsystems { if err := sys.Set(d); err != nil { - return nil, err + return err } // FIXME: Apply should, ideally, be reentrant or be broken up into a separate // create and join phase so that the cgroup hierarchy for a container can be @@ -81,11 +90,25 @@ func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { if cgroups.IsNotFound(err) { continue } - return nil, err + return err } paths[name] = p } - return paths, nil + m.paths = paths + + return nil +} + +func (m *Manager) RemovePaths() error { + return cgroups.RemovePaths(m.paths) +} + +func (m *Manager) GetPaths() map[string]string { + return m.paths +} + +func (m *Manager) SetPaths(paths map[string]string) { + m.paths = paths } // Symmetrical public function to update device based cgroups. Also available @@ -101,9 +124,9 @@ func ApplyDevices(c *cgroups.Cgroup, pid int) error { return devices.Set(d) } -func GetStats(systemPaths map[string]string) (*cgroups.Stats, error) { +func (m *Manager) GetStats() (*cgroups.Stats, error) { stats := cgroups.NewStats() - for name, path := range systemPaths { + for name, path := range m.paths { sys, ok := subsystems[name] if !ok { continue @@ -131,8 +154,8 @@ func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error { return freezer.Set(d) } -func GetPids(c *cgroups.Cgroup) ([]int, error) { - d, err := getCgroupData(c, 0) +func (m *Manager) GetPids() ([]int, error) { + d, err := getCgroupData(m.Cgroups, 0) if err != nil { return nil, err } diff --git a/cgroups/manager/manager.go b/cgroups/manager/manager.go new file mode 100644 index 00000000..3ee625b4 --- /dev/null +++ b/cgroups/manager/manager.go @@ -0,0 +1,19 @@ +package manager + +import ( + "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/cgroups/fs" + "github.com/docker/libcontainer/cgroups/systemd" +) + +func NewCgroupManager(cgroups *cgroups.Cgroup) cgroups.Manager { + if systemd.UseSystemd() { + return &systemd.Manager{ + Cgroups: cgroups, + } + } + + return &fs.Manager{ + Cgroups: cgroups, + } +} diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index 4b9a2f5b..f35eb594 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -8,15 +8,34 @@ import ( "github.com/docker/libcontainer/cgroups" ) +type Manager struct { + Cgroups *cgroups.Cgroup +} + func UseSystemd() bool { return false } -func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { +func (m *Manager) Apply(pid int) error { + return fmt.Errorf("Systemd not supported") +} + +func (m *Manager) GetPids() ([]int, error) { return nil, fmt.Errorf("Systemd not supported") } -func GetPids(c *cgroups.Cgroup) ([]int, error) { +func (m *Manager) RemovePaths() error { + return fmt.Errorf("Systemd not supported") +} + +func (m *Manager) GetPaths() map[string]string { + return nil +} + +func (m *Manager) SetPaths(paths map[string]string) { +} + +func (m *Manager) GetStats() (*cgroups.Stats, error) { return nil, fmt.Errorf("Systemd not supported") } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index 3d898114..96ffdebe 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -19,8 +19,9 @@ import ( "github.com/godbus/dbus" ) -type systemdCgroup struct { - cgroup *cgroups.Cgroup +type Manager struct { + Cgroups *cgroups.Cgroup + paths map[string]string } type subsystem interface { @@ -81,16 +82,14 @@ func getIfaceForUnit(unitName string) string { return "Unit" } -func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { +func (m *Manager) Apply(pid int) error { var ( + c = m.Cgroups unitName = getUnitName(c) slice = "system.slice" properties []systemd.Property - res = &systemdCgroup{} ) - res.cgroup = c - if c.Slice != "" { slice = c.Slice } @@ -120,19 +119,19 @@ func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { } if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil { - return nil, err + return err } if !c.AllowAllDevices { if err := joinDevices(c, pid); err != nil { - return nil, err + return err } } // -1 disables memorySwap if c.MemorySwap >= 0 && (c.Memory != 0 || c.MemorySwap > 0) { if err := joinMemory(c, pid); err != nil { - return nil, err + return err } } @@ -140,11 +139,11 @@ func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { // we need to manually join the freezer and cpuset cgroup in systemd // because it does not currently support it via the dbus api. if err := joinFreezer(c, pid); err != nil { - return nil, err + return err } if err := joinCpuset(c, pid); err != nil { - return nil, err + return err } paths := make(map[string]string) @@ -158,17 +157,32 @@ func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { "perf_event", "freezer", } { - subsystemPath, err := getSubsystemPath(res.cgroup, sysname) + subsystemPath, err := getSubsystemPath(m.Cgroups, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } - return nil, err + return err } paths[sysname] = subsystemPath } - return paths, nil + + m.paths = paths + + return nil +} + +func (m *Manager) RemovePaths() error { + return cgroups.RemovePaths(m.paths) +} + +func (m *Manager) GetPaths() map[string]string { + return m.paths +} + +func (m *Manager) SetPaths(paths map[string]string) { + m.paths = paths } func writeFile(dir, file, data string) error { @@ -229,8 +243,8 @@ func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error { return nil } -func GetPids(c *cgroups.Cgroup) ([]int, error) { - path, err := getSubsystemPath(c, "cpu") +func (m *Manager) GetPids() ([]int, error) { + path, err := getSubsystemPath(m.Cgroups, "cpu") if err != nil { return nil, err } @@ -238,6 +252,10 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) { return cgroups.ReadProcsFile(path) } +func (m *Manager) GetStats() (*cgroups.Stats, error) { + panic("not implemented") +} + func getUnitName(c *cgroups.Cgroup) string { return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name) } diff --git a/linux_container.go b/linux_container.go index 7845f8db..fffd7c67 100644 --- a/linux_container.go +++ b/linux_container.go @@ -10,6 +10,7 @@ import ( "path/filepath" "syscall" + "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/namespaces" "github.com/docker/libcontainer/network" @@ -21,7 +22,7 @@ type linuxContainer struct { root string config *configs.Config state *configs.State - cgroupManager CgroupManager + cgroupManager cgroups.Manager initArgs []string } @@ -133,7 +134,7 @@ func (c *linuxContainer) updateStateFile() error { } func (c *linuxContainer) startInitProcess(cmd *exec.Cmd, config *ProcessConfig) error { - err := namespaces.Exec(config.Args, config.Env, cmd, c.config, c.state) + err := namespaces.Exec(config.Args, config.Env, cmd, c.config, c.cgroupManager, c.state) if err != nil { return err } diff --git a/linux_container_test.go b/linux_container_test.go index 64d4fb8b..a3c6e306 100644 --- a/linux_container_test.go +++ b/linux_container_test.go @@ -22,6 +22,21 @@ func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) { return m.stats, nil } +func (m *mockCgroupManager) Apply(pid int) error { + return nil +} + +func (m *mockCgroupManager) RemovePaths() error { + return nil +} + +func (m *mockCgroupManager) GetPaths() map[string]string { + return nil +} + +func (m *mockCgroupManager) SetPaths(map[string]string) { +} + func TestGetContainerPids(t *testing.T) { container := &linuxContainer{ id: "myid", diff --git a/linux_factory.go b/linux_factory.go index 10e464ec..a8311668 100644 --- a/linux_factory.go +++ b/linux_factory.go @@ -11,6 +11,7 @@ import ( "github.com/golang/glog" + cgroups "github.com/docker/libcontainer/cgroups/manager" "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/namespaces" ) @@ -88,7 +89,7 @@ func (l *linuxFactory) Create(id string, config *configs.Config) (Container, err return nil, newGenericError(err, SystemError) } - cgroupManager := NewCgroupManager() + cgroupManager := cgroups.NewCgroupManager(config.Cgroups) return &linuxContainer{ id: id, root: containerRoot, @@ -116,7 +117,8 @@ func (l *linuxFactory) Load(id string) (Container, error) { return nil, err } - cgroupManager := NewCgroupManager() + cgroupManager := cgroups.NewCgroupManager(config.Cgroups) + cgroupManager.SetPaths(state.CgroupPaths) glog.Infof("using %s as cgroup manager", cgroupManager) return &linuxContainer{ id: id, diff --git a/namespaces/exec.go b/namespaces/exec.go index 1d7914a0..ff20c414 100644 --- a/namespaces/exec.go +++ b/namespaces/exec.go @@ -10,8 +10,6 @@ import ( "syscall" "github.com/docker/libcontainer/cgroups" - "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/network" "github.com/docker/libcontainer/system" @@ -21,7 +19,7 @@ import ( // Move this to libcontainer package. // Exec performs setup outside of a namespace so that a container can be // executed. Exec is a high level function for working with container namespaces. -func Exec(args []string, env []string, command *exec.Cmd, container *configs.Config, state *configs.State) error { +func Exec(args []string, env []string, command *exec.Cmd, container *configs.Config, cgroupManager cgroups.Manager, state *configs.State) error { var err error // create a pipe so that we can syncronize with the namespaced process and @@ -70,11 +68,11 @@ func Exec(args []string, env []string, command *exec.Cmd, container *configs.Con // Do this before syncing with child so that no children // can escape the cgroup - cgroupPaths, err := SetupCgroups(container, command.Process.Pid) + err = cgroupManager.Apply(command.Process.Pid) if err != nil { return terminate(err) } - defer cgroups.RemovePaths(cgroupPaths) + defer cgroupManager.RemovePaths() var networkState network.NetworkState if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil { @@ -102,7 +100,7 @@ func Exec(args []string, env []string, command *exec.Cmd, container *configs.Con state.InitPid = command.Process.Pid state.InitStartTime = started state.NetworkState = networkState - state.CgroupPaths = cgroupPaths + state.CgroupPaths = cgroupManager.GetPaths() return nil } @@ -140,19 +138,6 @@ func DefaultCreateCommand(container *configs.Config, console, dataPath, init str return command } -// SetupCgroups applies the cgroup restrictions to the process running in the container based -// on the container's configuration -func SetupCgroups(container *configs.Config, nspid int) (map[string]string, error) { - if container.Cgroups != nil { - c := container.Cgroups - if systemd.UseSystemd() { - return systemd.Apply(c, nspid) - } - return fs.Apply(c, nspid) - } - return map[string]string{}, nil -} - // InitializeNetworking creates the container's network stack outside of the namespace and moves // interfaces into the container's net namespaces if necessary func InitializeNetworking(container *configs.Config, nspid int, networkState *network.NetworkState) error { From 59e66b818db8695204e576d1962ab07806e8b2ba Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 13 Jan 2015 14:49:46 +0300 Subject: [PATCH 2/7] nsinit: add getContainer() Signed-off-by: Andrey Vagin --- nsinit/exec.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/nsinit/exec.go b/nsinit/exec.go index 6c98c0f3..dc7b2108 100644 --- a/nsinit/exec.go +++ b/nsinit/exec.go @@ -28,17 +28,7 @@ var execCommand = cli.Command{ }, } -func execAction(context *cli.Context) { - var exitCode int - - process := &libcontainer.ProcessConfig{ - Args: context.Args(), - Env: context.StringSlice("env"), - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - } - +func getContainer(context *cli.Context) (libcontainer.Container, error) { factory, err := libcontainer.New(context.GlobalString("root"), []string{os.Args[0], "init", "--fd", "3", "--"}) if err != nil { log.Fatal(err) @@ -55,6 +45,22 @@ func execAction(context *cli.Context) { } container, err = factory.Create(id, config) } + + return container, err +} + +func execAction(context *cli.Context) { + var exitCode int + + process := &libcontainer.ProcessConfig{ + Args: context.Args(), + Env: context.StringSlice("env"), + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + } + + container, err := getContainer(context) if err != nil { log.Fatal(err) } From ba4257a146e9416c04f8dd09e57024e77393ae52 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 13 Jan 2015 14:52:14 +0300 Subject: [PATCH 3/7] new-api: add the Freezer method to cgroup.Manager Signed-off-by: Andrey Vagin --- cgroups/cgroups.go | 2 ++ cgroups/fs/apply_raw.go | 6 +++--- cgroups/systemd/apply_nosystemd.go | 4 ++++ cgroups/systemd/apply_systemd.go | 4 ++-- linux_container_test.go | 4 ++++ nsinit/pause.go | 32 +++++++++++------------------- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index 0ce7cc97..e23eb146 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -12,6 +12,8 @@ type Manager interface { GetPids() ([]int, error) GetStats() (*Stats, error) + Freeze(state FreezerState) error + RemovePaths() error GetPaths() map[string]string SetPaths(map[string]string) diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 68789286..57246c71 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -141,13 +141,13 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { // Freeze toggles the container's freezer cgroup depending on the state // provided -func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error { - d, err := getCgroupData(c, 0) +func (m *Manager) Freeze(state cgroups.FreezerState) error { + d, err := getCgroupData(m.Cgroups, 0) if err != nil { return err } - c.Freezer = state + m.Cgroups.Freezer = state freezer := subsystems["freezer"] diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index f35eb594..ef7856e9 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -39,6 +39,10 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { return nil, fmt.Errorf("Systemd not supported") } +func (m *Manager) Freeze(state cgroups.FreezerState) error { + return fmt.Errorf("Systemd not supported") +} + func ApplyDevices(c *cgroups.Cgroup, pid int) error { return fmt.Errorf("Systemd not supported") } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index 96ffdebe..3d1fc73b 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -221,8 +221,8 @@ func getSubsystemPath(c *cgroups.Cgroup, subsystem string) (string, error) { return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil } -func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error { - path, err := getSubsystemPath(c, "freezer") +func (m *Manager) Freeze(state cgroups.FreezerState) error { + path, err := getSubsystemPath(m.Cgroups, "freezer") if err != nil { return err } diff --git a/linux_container_test.go b/linux_container_test.go index a3c6e306..eb14f13b 100644 --- a/linux_container_test.go +++ b/linux_container_test.go @@ -37,6 +37,10 @@ func (m *mockCgroupManager) GetPaths() map[string]string { func (m *mockCgroupManager) SetPaths(map[string]string) { } +func (m *mockCgroupManager) Freeze(state cgroups.FreezerState) error { + return nil +} + func TestGetContainerPids(t *testing.T) { container := &linuxContainer{ id: "myid", diff --git a/nsinit/pause.go b/nsinit/pause.go index ada24250..6ba95cd1 100644 --- a/nsinit/pause.go +++ b/nsinit/pause.go @@ -4,9 +4,6 @@ import ( "log" "github.com/codegangsta/cli" - "github.com/docker/libcontainer/cgroups" - "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/cgroups/systemd" ) var pauseCommand = cli.Command{ @@ -22,28 +19,23 @@ var unpauseCommand = cli.Command{ } func pauseAction(context *cli.Context) { - if err := toggle(cgroups.Frozen); err != nil { + container, err := getContainer(context) + if err != nil { + log.Fatal(err) + } + + if err = container.Pause(); err != nil { log.Fatal(err) } } func unpauseAction(context *cli.Context) { - if err := toggle(cgroups.Thawed); err != nil { + container, err := getContainer(context) + if err != nil { + log.Fatal(err) + } + + if err = container.Resume(); err != nil { log.Fatal(err) } } - -func toggle(state cgroups.FreezerState) error { - container, err := loadConfig() - if err != nil { - return err - } - - if systemd.UseSystemd() { - err = systemd.Freeze(container.Cgroups, state) - } else { - err = fs.Freeze(container.Cgroups, state) - } - - return err -} From ee6e585e219d813c8acaec833ef04ea50fb1f733 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Wed, 14 Jan 2015 18:47:26 +0300 Subject: [PATCH 4/7] cgroups: replace SetPaths on LoadCgroupManager Signed-off-by: Andrey Vagin --- cgroups/cgroups.go | 1 - cgroups/fs/apply_raw.go | 14 +++++--------- cgroups/manager/manager.go | 14 ++++++++++++++ cgroups/systemd/apply_nosystemd.go | 4 +--- cgroups/systemd/apply_systemd.go | 12 ++++-------- linux_container_test.go | 3 --- linux_factory.go | 3 +-- 7 files changed, 25 insertions(+), 26 deletions(-) diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index e23eb146..973f436a 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -16,7 +16,6 @@ type Manager interface { RemovePaths() error GetPaths() map[string]string - SetPaths(map[string]string) } type FreezerState string diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 57246c71..79b24170 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -26,7 +26,7 @@ var ( type Manager struct { Cgroups *cgroups.Cgroup - paths map[string]string + Paths map[string]string } // The absolute path to the root of the cgroup hierarchies. @@ -94,21 +94,17 @@ func (m *Manager) Apply(pid int) error { } paths[name] = p } - m.paths = paths + m.Paths = paths return nil } func (m *Manager) RemovePaths() error { - return cgroups.RemovePaths(m.paths) + return cgroups.RemovePaths(m.Paths) } func (m *Manager) GetPaths() map[string]string { - return m.paths -} - -func (m *Manager) SetPaths(paths map[string]string) { - m.paths = paths + return m.Paths } // Symmetrical public function to update device based cgroups. Also available @@ -126,7 +122,7 @@ func ApplyDevices(c *cgroups.Cgroup, pid int) error { func (m *Manager) GetStats() (*cgroups.Stats, error) { stats := cgroups.NewStats() - for name, path := range m.paths { + for name, path := range m.Paths { sys, ok := subsystems[name] if !ok { continue diff --git a/cgroups/manager/manager.go b/cgroups/manager/manager.go index 3ee625b4..2ab04c39 100644 --- a/cgroups/manager/manager.go +++ b/cgroups/manager/manager.go @@ -17,3 +17,17 @@ func NewCgroupManager(cgroups *cgroups.Cgroup) cgroups.Manager { Cgroups: cgroups, } } + +func LoadCgroupManager(cgroups *cgroups.Cgroup, paths map[string]string) cgroups.Manager { + if systemd.UseSystemd() { + return &systemd.Manager{ + Cgroups: cgroups, + Paths: paths, + } + } + + return &fs.Manager{ + Cgroups: cgroups, + Paths: paths, + } +} diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index ef7856e9..6bd30d48 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -10,6 +10,7 @@ import ( type Manager struct { Cgroups *cgroups.Cgroup + Paths map[string]string } func UseSystemd() bool { @@ -32,9 +33,6 @@ func (m *Manager) GetPaths() map[string]string { return nil } -func (m *Manager) SetPaths(paths map[string]string) { -} - func (m *Manager) GetStats() (*cgroups.Stats, error) { return nil, fmt.Errorf("Systemd not supported") } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index 3d1fc73b..a8aa0248 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -21,7 +21,7 @@ import ( type Manager struct { Cgroups *cgroups.Cgroup - paths map[string]string + Paths map[string]string } type subsystem interface { @@ -168,21 +168,17 @@ func (m *Manager) Apply(pid int) error { paths[sysname] = subsystemPath } - m.paths = paths + m.Paths = paths return nil } func (m *Manager) RemovePaths() error { - return cgroups.RemovePaths(m.paths) + return cgroups.RemovePaths(m.Paths) } func (m *Manager) GetPaths() map[string]string { - return m.paths -} - -func (m *Manager) SetPaths(paths map[string]string) { - m.paths = paths + return m.Paths } func writeFile(dir, file, data string) error { diff --git a/linux_container_test.go b/linux_container_test.go index eb14f13b..e2f0fb80 100644 --- a/linux_container_test.go +++ b/linux_container_test.go @@ -34,9 +34,6 @@ func (m *mockCgroupManager) GetPaths() map[string]string { return nil } -func (m *mockCgroupManager) SetPaths(map[string]string) { -} - func (m *mockCgroupManager) Freeze(state cgroups.FreezerState) error { return nil } diff --git a/linux_factory.go b/linux_factory.go index a8311668..542331d4 100644 --- a/linux_factory.go +++ b/linux_factory.go @@ -117,8 +117,7 @@ func (l *linuxFactory) Load(id string) (Container, error) { return nil, err } - cgroupManager := cgroups.NewCgroupManager(config.Cgroups) - cgroupManager.SetPaths(state.CgroupPaths) + cgroupManager := cgroups.LoadCgroupManager(config.Cgroups, state.CgroupPaths) glog.Infof("using %s as cgroup manager", cgroupManager) return &linuxContainer{ id: id, From 083d91f8c361a6804bac3d74e01fd74bea517260 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Wed, 14 Jan 2015 18:23:42 +0300 Subject: [PATCH 5/7] cgroups: Add comments for methods of cgroup managers Signed-off-by: Andrey Vagin --- cgroups/cgroups.go | 17 ++++++++++++++++- cgroups/fs/apply_raw.go | 2 +- cgroups/manager/manager.go | 2 ++ cgroups/systemd/apply_nosystemd.go | 2 +- cgroups/systemd/apply_systemd.go | 2 +- linux_container_test.go | 2 +- namespaces/exec.go | 2 +- 7 files changed, 23 insertions(+), 6 deletions(-) diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index 973f436a..894c8125 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -7,14 +7,29 @@ import ( ) type Manager interface { + // Apply cgroup configuration to the process with the specified pid Apply(pid int) error + // Returns the PIDs inside the cgroup set GetPids() ([]int, error) + + // Returns statistics for the cgroup set GetStats() (*Stats, error) + // Toggles the freezer cgroup according with specified state Freeze(state FreezerState) error - RemovePaths() error + // Destroys the cgroup set + Destroy() error + + // NewCgroupManager() and LoadCgroupManager() require following attributes: + // Paths map[string]string + // Cgroups *cgroups.Cgroup + // Paths maps cgroup subsystem to path at which it is mounted. + // Cgroups specifies specific cgroup settings for the various subsystems + + // Returns cgroup paths to save in a state file and to be able to + // restore the object later. GetPaths() map[string]string } diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 79b24170..59beb7ed 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -99,7 +99,7 @@ func (m *Manager) Apply(pid int) error { return nil } -func (m *Manager) RemovePaths() error { +func (m *Manager) Destroy() error { return cgroups.RemovePaths(m.Paths) } diff --git a/cgroups/manager/manager.go b/cgroups/manager/manager.go index 2ab04c39..87396813 100644 --- a/cgroups/manager/manager.go +++ b/cgroups/manager/manager.go @@ -6,6 +6,7 @@ import ( "github.com/docker/libcontainer/cgroups/systemd" ) +// Create a new cgroup manager with specified configuration func NewCgroupManager(cgroups *cgroups.Cgroup) cgroups.Manager { if systemd.UseSystemd() { return &systemd.Manager{ @@ -18,6 +19,7 @@ func NewCgroupManager(cgroups *cgroups.Cgroup) cgroups.Manager { } } +// Restore a cgroup manager with specified configuration and state func LoadCgroupManager(cgroups *cgroups.Cgroup, paths map[string]string) cgroups.Manager { if systemd.UseSystemd() { return &systemd.Manager{ diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index 6bd30d48..62928b82 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -25,7 +25,7 @@ func (m *Manager) GetPids() ([]int, error) { return nil, fmt.Errorf("Systemd not supported") } -func (m *Manager) RemovePaths() error { +func (m *Manager) Destroy() error { return fmt.Errorf("Systemd not supported") } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index a8aa0248..854d7f3b 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -173,7 +173,7 @@ func (m *Manager) Apply(pid int) error { return nil } -func (m *Manager) RemovePaths() error { +func (m *Manager) Destroy() error { return cgroups.RemovePaths(m.Paths) } diff --git a/linux_container_test.go b/linux_container_test.go index e2f0fb80..17bd8b9a 100644 --- a/linux_container_test.go +++ b/linux_container_test.go @@ -26,7 +26,7 @@ func (m *mockCgroupManager) Apply(pid int) error { return nil } -func (m *mockCgroupManager) RemovePaths() error { +func (m *mockCgroupManager) Destroy() error { return nil } diff --git a/namespaces/exec.go b/namespaces/exec.go index ff20c414..f9526c22 100644 --- a/namespaces/exec.go +++ b/namespaces/exec.go @@ -72,7 +72,7 @@ func Exec(args []string, env []string, command *exec.Cmd, container *configs.Con if err != nil { return terminate(err) } - defer cgroupManager.RemovePaths() + defer cgroupManager.Destroy() var networkState network.NetworkState if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil { From 4eaff5e14ea4c29bc9d37c63195c234e1b3bb407 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Wed, 14 Jan 2015 19:39:29 +0300 Subject: [PATCH 6/7] cgroups: don't change a freezer state if an operation failed Signed-off-by: Andrey Vagin --- cgroups/fs/apply_raw.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 59beb7ed..1fe5faf3 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -143,11 +143,15 @@ func (m *Manager) Freeze(state cgroups.FreezerState) error { return err } + freezer := subsystems["freezer"] + err = freezer.Set(d) + if err != nil { + return err + } + m.Cgroups.Freezer = state - freezer := subsystems["freezer"] - - return freezer.Set(d) + return nil } func (m *Manager) GetPids() ([]int, error) { From 6334be0ac56b2a38456d65b29326aad8dd0bcc60 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Wed, 14 Jan 2015 19:48:25 +0300 Subject: [PATCH 7/7] cgroups: add TODO before NewCgroupManager() Signed-off-by: Andrey Vagin --- cgroups/manager/manager.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cgroups/manager/manager.go b/cgroups/manager/manager.go index 87396813..bd5fd48a 100644 --- a/cgroups/manager/manager.go +++ b/cgroups/manager/manager.go @@ -7,6 +7,9 @@ import ( ) // Create a new cgroup manager with specified configuration +// TODO this object is not really initialized until Apply() is called. +// Maybe make this to the equivalent of Apply() at some point? +// @vmarmol func NewCgroupManager(cgroups *cgroups.Cgroup) cgroups.Manager { if systemd.UseSystemd() { return &systemd.Manager{