From 6c6808e5bfee53be71a1c3c641a4640cf4d03d36 Mon Sep 17 00:00:00 2001 From: Donald Huang Date: Fri, 14 Nov 2014 23:51:29 +0000 Subject: [PATCH 1/5] Change arguments to fs.GetStats to be map[string]string Allows us to remove systemd.GetPaths later Signed-off-by: Donald Huang --- api_temp.go | 2 +- cgroups/cgutil/cgutil.go | 28 ---------------------------- cgroups/fs/apply_raw.go | 22 +++++----------------- 3 files changed, 6 insertions(+), 46 deletions(-) diff --git a/api_temp.go b/api_temp.go index 9b2c52077..fbd526fff 100644 --- a/api_temp.go +++ b/api_temp.go @@ -21,7 +21,7 @@ func GetStats(container *Config, state *State) (*ContainerStats, error) { if systemd.UseSystemd() { stats.CgroupStats, err = systemd.GetStats(container.Cgroups) } else { - stats.CgroupStats, err = fs.GetStats(container.Cgroups) + stats.CgroupStats, err = fs.GetStats(state.CgroupPaths) } if err != nil { diff --git a/cgroups/cgutil/cgutil.go b/cgroups/cgutil/cgutil.go index d1a66117f..3b9a9a66b 100644 --- a/cgroups/cgutil/cgutil.go +++ b/cgroups/cgutil/cgutil.go @@ -34,16 +34,6 @@ var destroyCommand = cli.Command{ Action: destroyAction, } -var statsCommand = cli.Command{ - Name: "stats", - Usage: "Get stats for cgroup", - Flags: []cli.Flag{ - cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, - cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, - }, - Action: statsAction, -} - var pauseCommand = cli.Command{ Name: "pause", Usage: "Pause cgroup", @@ -196,23 +186,6 @@ func destroyAction(context *cli.Context) { } } -func statsAction(context *cli.Context) { - config, err := getConfig(context) - if err != nil { - log.Fatal(err) - } - stats, err := fs.GetStats(config) - if err != nil { - log.Fatal(err) - } - - out, err := json.MarshalIndent(stats, "", "\t") - if err != nil { - log.Fatal(err) - } - fmt.Printf("Usage stats for '%s':\n %v\n", config.Name, string(out)) -} - func pauseAction(context *cli.Context) { setFreezerState(context, cgroups.Frozen) } @@ -252,7 +225,6 @@ func main() { app.Commands = []cli.Command{ createCommand, destroyCommand, - statsCommand, pauseCommand, resumeCommand, psCommand, diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 599ab5727..c6860ca61 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -94,25 +94,13 @@ func Cleanup(c *cgroups.Cgroup) error { return d.Cleanup() } -func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) { +func GetStats(systemPaths map[string]string) (*cgroups.Stats, error) { stats := cgroups.NewStats() - - d, err := getCgroupData(c, 0) - if err != nil { - return nil, fmt.Errorf("getting CgroupData %s", err) - } - - for sysname, sys := range subsystems { - path, err := d.path(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 + for name, path := range systemPaths { + sys, ok := subsystems[name] + if !ok { + continue } - if err := sys.GetStats(path, stats); err != nil { return nil, err } From 5cacd4813299803eb43b8c551a52e707eaf7105a Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 14 Nov 2014 17:03:40 -0800 Subject: [PATCH 2/5] Remove systemd.GetStats Because we are using the paths that are created when we initially setup cgroups for a container we no longer have to dynamically generates them when a user requests stats. This allows us to fully use the fs stats code without having system create it's paths. Signed-off-by: Michael Crosby --- api_temp.go | 19 ++--------- cgroups/systemd/apply_nosystemd.go | 4 --- cgroups/systemd/apply_systemd.go | 54 ++++++------------------------ 3 files changed, 13 insertions(+), 64 deletions(-) diff --git a/api_temp.go b/api_temp.go index fbd526fff..5c682ee34 100644 --- a/api_temp.go +++ b/api_temp.go @@ -5,30 +5,17 @@ package libcontainer import ( "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/network" ) // TODO(vmarmol): Complete Stats() in final libcontainer API and move users to that. // DEPRECATED: The below portions are only to be used during the transition to the official API. // Returns all available stats for the given container. -func GetStats(container *Config, state *State) (*ContainerStats, error) { - var ( - err error - stats = &ContainerStats{} - ) - - if systemd.UseSystemd() { - stats.CgroupStats, err = systemd.GetStats(container.Cgroups) - } else { - stats.CgroupStats, err = fs.GetStats(state.CgroupPaths) - } - - if err != nil { +func GetStats(container *Config, state *State) (stats *ContainerStats, err error) { + stats = &ContainerStats{} + if stats.CgroupStats, err = fs.GetStats(state.CgroupPaths); err != nil { return stats, err } - stats.NetworkStats, err = network.GetStats(&state.NetworkState) - return stats, err } diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index 42a09e3fe..81334191d 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -27,7 +27,3 @@ func ApplyDevices(c *cgroups.Cgroup, pid int) error { func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error { return fmt.Errorf("Systemd not supported") } - -func GetStats(c *cgroups.Cgroup) (*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 5155b6753..a70aa4088 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -31,16 +31,6 @@ var ( connLock sync.Mutex theConn *systemd.Conn hasStartTransientUnit bool - subsystems = map[string]subsystem{ - "devices": &fs.DevicesGroup{}, - "memory": &fs.MemoryGroup{}, - "cpu": &fs.CpuGroup{}, - "cpuset": &fs.CpusetGroup{}, - "cpuacct": &fs.CpuacctGroup{}, - "blkio": &fs.BlkioGroup{}, - "perf_event": &fs.PerfEventGroup{}, - "freezer": &fs.FreezerGroup{}, - } ) func newProp(name string, units interface{}) systemd.Property { @@ -168,21 +158,26 @@ func writeFile(dir, file, data string) error { func (c *systemdCgroup) Paths() (map[string]string, error) { paths := make(map[string]string) - - for sysname := range subsystems { + for _, sysname := range []string{ + "devices", + "memory", + "cpu", + "cpuset", + "cpuacct", + "blkio", + "perf_event", + "freezer", + } { subsystemPath, err := getSubsystemPath(c.cgroup, 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 } - paths[sysname] = subsystemPath } - return paths, nil } @@ -267,35 +262,6 @@ func getUnitName(c *cgroups.Cgroup) string { return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name) } -/* - * This would be nicer to get from the systemd API when accounting - * is enabled, but sadly there is no way to do that yet. - * The lack of this functionality in the API & the approach taken - * is guided by - * http://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#readingaccountinginformation. - */ -func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) { - stats := cgroups.NewStats() - - for sysname, sys := range subsystems { - subsystemPath, err := getSubsystemPath(c, 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 - } - - if err := sys.GetStats(subsystemPath, stats); err != nil { - return nil, err - } - } - - return stats, nil -} - // Atm we can't use the systemd device support because of two missing things: // * Support for wildcards to allow mknod on any device // * Support for wildcards to allow /dev/pts support From bc7efa6b81f44c29ef4e4c422d91b9ccc1041e20 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 14 Nov 2014 17:22:10 -0800 Subject: [PATCH 3/5] Have cgroup.Apply return paths to setup cgroups There is no reason to have a special type returned from the cgroups Apply function for getting the paths and cleanup. With access to the paths we can just delete what we need. Signed-off-by: Michael Crosby --- cgroups/cgroups.go | 5 --- cgroups/cgutil/cgutil.go | 27 -------------- cgroups/fs/apply_raw.go | 58 ++++++++++-------------------- cgroups/systemd/apply_nosystemd.go | 2 +- cgroups/systemd/apply_systemd.go | 26 +++----------- namespaces/exec.go | 27 +++++++------- 6 files changed, 37 insertions(+), 108 deletions(-) diff --git a/cgroups/cgroups.go b/cgroups/cgroups.go index 567e9a6c1..fe3600597 100644 --- a/cgroups/cgroups.go +++ b/cgroups/cgroups.go @@ -53,8 +53,3 @@ type Cgroup struct { Freezer FreezerState `json:"freezer,omitempty"` // set the freeze value for the process Slice string `json:"slice,omitempty"` // Parent slice to use for systemd } - -type ActiveCgroup interface { - Cleanup() error - Paths() (map[string]string, error) -} diff --git a/cgroups/cgutil/cgutil.go b/cgroups/cgutil/cgutil.go index 3b9a9a66b..db02d1568 100644 --- a/cgroups/cgutil/cgutil.go +++ b/cgroups/cgutil/cgutil.go @@ -24,16 +24,6 @@ var createCommand = cli.Command{ Action: createAction, } -var destroyCommand = cli.Command{ - Name: "destroy", - Usage: "Destroy an existing cgroup container.", - Flags: []cli.Flag{ - cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, - cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, - }, - Action: destroyAction, -} - var pauseCommand = cli.Command{ Name: "pause", Usage: "Pause cgroup", @@ -170,22 +160,6 @@ func createAction(context *cli.Context) { } } -func destroyAction(context *cli.Context) { - config, err := getConfig(context) - if err != nil { - log.Fatal(err) - } - - killAll(config) - // Systemd will clean up cgroup state for empty container. - if !systemd.UseSystemd() { - err := fs.Cleanup(config) - if err != nil { - log.Fatal(err) - } - } -} - func pauseAction(context *cli.Context) { setFreezerState(context, cgroups.Frozen) } @@ -224,7 +198,6 @@ func main() { app.Commands = []cli.Command{ createCommand, - destroyCommand, pauseCommand, resumeCommand, psCommand, diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index c6860ca61..3597374b3 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -57,20 +57,33 @@ type data struct { pid int } -func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { +func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { d, err := getCgroupData(c, pid) if err != nil { return nil, err } - for _, sys := range subsystems { + paths := make(map[string]string) + for name, sys := range subsystems { if err := sys.Set(d); err != nil { - d.Cleanup() + for _, p := range paths { + os.RemoveAll(p) + } return nil, err } + p, err := d.path(name) + if err != nil { + if cgroups.IsNotFound(err) { + continue + } + for _, p := range paths { + os.RemoveAll(p) + } + return nil, err + } + paths[name] = p } - - return d, nil + return paths, nil } // Symmetrical public function to update device based cgroups. Also available @@ -86,14 +99,6 @@ func ApplyDevices(c *cgroups.Cgroup, pid int) error { return devices.Set(d) } -func Cleanup(c *cgroups.Cgroup) error { - d, err := getCgroupData(c, 0) - if err != nil { - return fmt.Errorf("Could not get Cgroup data %s", err) - } - return d.Cleanup() -} - func GetStats(systemPaths map[string]string) (*cgroups.Stats, error) { stats := cgroups.NewStats() for name, path := range systemPaths { @@ -164,26 +169,6 @@ func (raw *data) parent(subsystem string) (string, error) { return filepath.Join(raw.root, subsystem, initPath), nil } -func (raw *data) Paths() (map[string]string, error) { - paths := make(map[string]string) - - for sysname := range subsystems { - path, err := raw.path(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 - } - - paths[sysname] = path - } - - return paths, nil -} - func (raw *data) path(subsystem string) (string, error) { // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. if filepath.IsAbs(raw.cgroup) { @@ -222,13 +207,6 @@ func (raw *data) join(subsystem string) (string, error) { return path, nil } -func (raw *data) Cleanup() error { - for _, sys := range subsystems { - sys.Remove(raw) - } - return nil -} - func writeFile(dir, file, data string) error { return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) } diff --git a/cgroups/systemd/apply_nosystemd.go b/cgroups/systemd/apply_nosystemd.go index 81334191d..4b9a2f5b7 100644 --- a/cgroups/systemd/apply_nosystemd.go +++ b/cgroups/systemd/apply_nosystemd.go @@ -12,7 +12,7 @@ func UseSystemd() bool { return false } -func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { +func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { return nil, fmt.Errorf("Systemd not supported") } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index a70aa4088..94f3465ff 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -81,7 +81,7 @@ func getIfaceForUnit(unitName string) string { return "Unit" } -func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { +func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { var ( unitName = getUnitName(c) slice = "system.slice" @@ -149,14 +149,6 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { } } - return res, nil -} - -func writeFile(dir, file, data string) error { - return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) -} - -func (c *systemdCgroup) Paths() (map[string]string, error) { paths := make(map[string]string) for _, sysname := range []string{ "devices", @@ -168,7 +160,7 @@ func (c *systemdCgroup) Paths() (map[string]string, error) { "perf_event", "freezer", } { - subsystemPath, err := getSubsystemPath(c.cgroup, sysname) + subsystemPath, err := getSubsystemPath(res.cgroup, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { @@ -181,18 +173,8 @@ func (c *systemdCgroup) Paths() (map[string]string, error) { return paths, nil } -func (c *systemdCgroup) Cleanup() error { - // systemd cleans up, we don't need to do much - paths, err := c.Paths() - if err != nil { - return err - } - - for _, path := range paths { - os.RemoveAll(path) - } - - return nil +func writeFile(dir, file, data string) error { + return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) } func joinFreezer(c *cgroups.Cgroup, pid int) error { diff --git a/namespaces/exec.go b/namespaces/exec.go index bd3a4a3f9..eac03d5df 100644 --- a/namespaces/exec.go +++ b/namespaces/exec.go @@ -10,7 +10,6 @@ import ( "syscall" "github.com/docker/libcontainer" - "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/cgroups/fs" "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/network" @@ -60,16 +59,11 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri // Do this before syncing with child so that no children // can escape the cgroup - cgroupRef, err := SetupCgroups(container, command.Process.Pid) - if err != nil { - return terminate(err) - } - defer cgroupRef.Cleanup() - - cgroupPaths, err := cgroupRef.Paths() + cgroupPaths, err := SetupCgroups(container, command.Process.Pid) if err != nil { return terminate(err) } + defer removeCgroupPaths(cgroupPaths) var networkState network.NetworkState if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil { @@ -153,18 +147,15 @@ func DefaultCreateCommand(container *libcontainer.Config, console, dataPath, ini // SetupCgroups applies the cgroup restrictions to the process running in the container based // on the container's configuration -func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) { +func SetupCgroups(container *libcontainer.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 nil, nil + return map[string]string{}, nil } // InitializeNetworking creates the container's network stack outside of the namespace and moves @@ -181,3 +172,13 @@ func InitializeNetworking(container *libcontainer.Config, nspid int, networkStat } return nil } + +// removeCgroupPaths takes the subsystem paths for each cgroup that was +// setup for the container and removes them from the cgroup filesystem. +// Errors are ignored during the removal because we don't want to end up +// with partially removed cgroups. +func removeCgroupPaths(paths map[string]string) { + for _, path := range paths { + os.RemoveAll(path) + } +} From 29b1d2b23f0d2d410968adaccfacf72a85e13e70 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 17 Nov 2014 11:55:40 -0800 Subject: [PATCH 4/5] Move RemovePaths into cgroups pkg for reuse Signed-off-by: Michael Crosby --- cgroups/fs/apply_raw.go | 14 ++++++++------ cgroups/utils.go | 13 ++++++++++++- namespaces/exec.go | 13 ++----------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 3597374b3..6f85793dd 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -64,21 +64,23 @@ func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { } paths := make(map[string]string) + defer func() { + if err != nil { + cgroups.RemovePaths(paths) + } + }() for name, sys := range subsystems { if err := sys.Set(d); err != nil { - for _, p := range paths { - os.RemoveAll(p) - } return nil, 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 + // created then join consists of writing the process pids to cgroup.procs p, err := d.path(name) if err != nil { if cgroups.IsNotFound(err) { continue } - for _, p := range paths { - os.RemoveAll(p) - } return nil, err } paths[name] = p diff --git a/cgroups/utils.go b/cgroups/utils.go index 77a3c0d7c..224a20b9b 100644 --- a/cgroups/utils.go +++ b/cgroups/utils.go @@ -189,6 +189,17 @@ func EnterPid(cgroupPaths map[string]string, pid int) error { } } } - return nil } + +// RemovePaths iterates over the provided paths removing them. +// If an error is encountered the removal proceeds and the first error is +// returned to ensure a partial removal is not possible. +func RemovePaths(paths map[string]string) (err error) { + for _, path := range paths { + if rerr := os.RemoveAll(path); err == nil { + err = rerr + } + } + return err +} diff --git a/namespaces/exec.go b/namespaces/exec.go index eac03d5df..b7873edd0 100644 --- a/namespaces/exec.go +++ b/namespaces/exec.go @@ -10,6 +10,7 @@ import ( "syscall" "github.com/docker/libcontainer" + "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/cgroups/fs" "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/network" @@ -63,7 +64,7 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri if err != nil { return terminate(err) } - defer removeCgroupPaths(cgroupPaths) + defer cgroups.RemovePaths(cgroupPaths) var networkState network.NetworkState if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil { @@ -172,13 +173,3 @@ func InitializeNetworking(container *libcontainer.Config, nspid int, networkStat } return nil } - -// removeCgroupPaths takes the subsystem paths for each cgroup that was -// setup for the container and removes them from the cgroup filesystem. -// Errors are ignored during the removal because we don't want to end up -// with partially removed cgroups. -func removeCgroupPaths(paths map[string]string) { - for _, path := range paths { - os.RemoveAll(path) - } -} From 5b623a6e43d65d133e94e598993bd749d5a43b11 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 17 Nov 2014 11:56:02 -0800 Subject: [PATCH 5/5] Remove cgutil cli application as it is not being used Signed-off-by: Michael Crosby --- cgroups/cgutil/cgutil.go | 209 ------------------------------ cgroups/cgutil/sample_cgroup.json | 10 -- 2 files changed, 219 deletions(-) delete mode 100644 cgroups/cgutil/cgutil.go delete mode 100644 cgroups/cgutil/sample_cgroup.json diff --git a/cgroups/cgutil/cgutil.go b/cgroups/cgutil/cgutil.go deleted file mode 100644 index db02d1568..000000000 --- a/cgroups/cgutil/cgutil.go +++ /dev/null @@ -1,209 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "log" - "os" - "syscall" - "time" - - "github.com/codegangsta/cli" - "github.com/docker/libcontainer/cgroups" - "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/cgroups/systemd" -) - -var createCommand = cli.Command{ - Name: "create", - Usage: "Create a cgroup container using the supplied configuration and initial process.", - Flags: []cli.Flag{ - cli.StringFlag{Name: "config, c", Value: "cgroup.json", Usage: "path to container configuration (cgroups.Cgroup object)"}, - cli.IntFlag{Name: "pid, p", Value: 0, Usage: "pid of the initial process in the container"}, - }, - Action: createAction, -} - -var pauseCommand = cli.Command{ - Name: "pause", - Usage: "Pause cgroup", - Flags: []cli.Flag{ - cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, - cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, - }, - Action: pauseAction, -} - -var resumeCommand = cli.Command{ - Name: "resume", - Usage: "Resume a paused cgroup", - Flags: []cli.Flag{ - cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, - cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, - }, - Action: resumeAction, -} - -var psCommand = cli.Command{ - Name: "ps", - Usage: "Get list of pids for a cgroup", - Flags: []cli.Flag{ - cli.StringFlag{Name: "name, n", Value: "", Usage: "container name"}, - cli.StringFlag{Name: "parent, p", Value: "", Usage: "container parent"}, - }, - Action: psAction, -} - -func getConfigFromFile(c *cli.Context) (*cgroups.Cgroup, error) { - f, err := os.Open(c.String("config")) - if err != nil { - return nil, err - } - defer f.Close() - - var config *cgroups.Cgroup - if err := json.NewDecoder(f).Decode(&config); err != nil { - log.Fatal(err) - } - return config, nil -} - -func openLog(name string) error { - f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0755) - if err != nil { - return err - } - - log.SetOutput(f) - return nil -} - -func getConfig(context *cli.Context) (*cgroups.Cgroup, error) { - name := context.String("name") - if name == "" { - log.Fatal(fmt.Errorf("Missing container name")) - } - parent := context.String("parent") - return &cgroups.Cgroup{ - Name: name, - Parent: parent, - }, nil -} - -func killAll(config *cgroups.Cgroup) { - // We could use freezer here to prevent process spawning while we are trying - // to kill everything. But going with more portable solution of retrying for - // now. - pids := getPids(config) - retry := 10 - for len(pids) != 0 || retry > 0 { - killPids(pids) - time.Sleep(100 * time.Millisecond) - retry-- - pids = getPids(config) - } - if len(pids) != 0 { - log.Fatal(fmt.Errorf("Could not kill existing processes in the container.")) - } -} - -func getPids(config *cgroups.Cgroup) []int { - pids, err := fs.GetPids(config) - if err != nil { - log.Fatal(err) - } - return pids -} - -func killPids(pids []int) { - for _, pid := range pids { - // pids might go away on their own. Ignore errors. - syscall.Kill(pid, syscall.SIGKILL) - } -} - -func setFreezerState(context *cli.Context, state cgroups.FreezerState) { - config, err := getConfig(context) - if err != nil { - log.Fatal(err) - } - - if systemd.UseSystemd() { - err = systemd.Freeze(config, state) - } else { - err = fs.Freeze(config, state) - } - if err != nil { - log.Fatal(err) - } -} - -func createAction(context *cli.Context) { - config, err := getConfigFromFile(context) - if err != nil { - log.Fatal(err) - } - pid := context.Int("pid") - if pid <= 0 { - log.Fatal(fmt.Errorf("Invalid pid : %d", pid)) - } - if systemd.UseSystemd() { - _, err := systemd.Apply(config, pid) - if err != nil { - log.Fatal(err) - } - } else { - _, err := fs.Apply(config, pid) - if err != nil { - log.Fatal(err) - } - } -} - -func pauseAction(context *cli.Context) { - setFreezerState(context, cgroups.Frozen) -} - -func resumeAction(context *cli.Context) { - setFreezerState(context, cgroups.Thawed) -} - -func psAction(context *cli.Context) { - config, err := getConfig(context) - if err != nil { - log.Fatal(err) - } - - pids, err := fs.GetPids(config) - if err != nil { - log.Fatal(err) - } - - fmt.Printf("Pids in '%s':\n", config.Name) - fmt.Println(pids) -} - -func main() { - logPath := os.Getenv("log") - if logPath != "" { - if err := openLog(logPath); err != nil { - log.Fatal(err) - } - } - - app := cli.NewApp() - app.Name = "cgutil" - app.Usage = "Test utility for libcontainer cgroups package" - app.Version = "0.1" - - app.Commands = []cli.Command{ - createCommand, - pauseCommand, - resumeCommand, - psCommand, - } - - if err := app.Run(os.Args); err != nil { - log.Fatal(err) - } -} diff --git a/cgroups/cgutil/sample_cgroup.json b/cgroups/cgutil/sample_cgroup.json deleted file mode 100644 index 2d2978494..000000000 --- a/cgroups/cgutil/sample_cgroup.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "luke", - "parent": "darth", - "allow_all_devices": true, - "memory": 1073741824, - "memory_swap": -1, - "cpu_shares": 2048, - "cpu_quota": 500000, - "cpu_period": 250000 -}