Skip to content

Commit

Permalink
Merge pull request openshift#79 from rjnagal/cgroup_testing
Browse files Browse the repository at this point in the history
Add a standalone test utility for cgroup package.
  • Loading branch information
Michael Crosby committed Jul 10, 2014
2 parents 52e70ec + 0916444 commit 1e643a7
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 0 deletions.
264 changes: 264 additions & 0 deletions cgroups/cgutil/cgutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
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{"config, c", "cgroup.json", "path to container configuration (cgroups.Cgroup object)"},
cli.IntFlag{"pid, p", 0, "pid of the initial process in the container"},
},
Action: createAction,
}

var destroyCommand = cli.Command{
Name: "destroy",
Usage: "Destroy an existing cgroup container.",
Flags: []cli.Flag{
cli.StringFlag{"name, n", "", "container name"},
cli.StringFlag{"parent, p", "", "container parent"},
},
Action: destroyAction,
}

var statsCommand = cli.Command{
Name: "stats",
Usage: "Get stats for cgroup",
Flags: []cli.Flag{
cli.StringFlag{"name, n", "", "container name"},
cli.StringFlag{"parent, p", "", "container parent"},
},
Action: statsAction,
}

var pauseCommand = cli.Command{
Name: "pause",
Usage: "Pause cgroup",
Flags: []cli.Flag{
cli.StringFlag{"name, n", "", "container name"},
cli.StringFlag{"parent, p", "", "container parent"},
},
Action: pauseAction,
}

var resumeCommand = cli.Command{
Name: "resume",
Usage: "Resume a paused cgroup",
Flags: []cli.Flag{
cli.StringFlag{"name, n", "", "container name"},
cli.StringFlag{"parent, p", "", "container parent"},
},
Action: resumeAction,
}

var psCommand = cli.Command{
Name: "ps",
Usage: "Get list of pids for a cgroup",
Flags: []cli.Flag{
cli.StringFlag{"name, n", "", "container name"},
cli.StringFlag{"parent, p", "", "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 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 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)
}

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,
destroyCommand,
statsCommand,
pauseCommand,
resumeCommand,
psCommand,
}

if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
10 changes: 10 additions & 0 deletions cgroups/cgutil/sample_cgroup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "luke",
"parent": "darth",
"allow_all_devices": true,
"memory": 1073741824,
"memory_swap": -1,
"cpu_shares": 2048,
"cpu_quota": 500000,
"cpu_period": 250000
}

0 comments on commit 1e643a7

Please sign in to comment.