From 3b4a1c54d834a21a2b2a22b359495939db3b77f1 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 14 Jul 2014 12:30:19 -0700 Subject: [PATCH] Update libcontainer dep to fb67bb80b4205bece36ff70 Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- hack/vendor.sh | 2 +- .../docker/libcontainer/.travis.yml | 23 +- .../src/github.com/docker/libcontainer/api.go | 23 -- .../docker/libcontainer/api_temp.go | 34 +++ .../libcontainer/cgroups/cgutil/cgutil.go | 264 ++++++++++++++++++ .../cgroups/cgutil/sample_cgroup.json | 10 + .../libcontainer/cgroups/fs/apply_raw.go | 43 ++- .../docker/libcontainer/cgroups/fs/blkio.go | 15 +- .../libcontainer/cgroups/fs/blkio_test.go | 44 +-- .../docker/libcontainer/cgroups/fs/cpu.go | 16 +- .../libcontainer/cgroups/fs/cpu_test.go | 12 +- .../docker/libcontainer/cgroups/fs/cpuacct.go | 26 +- .../docker/libcontainer/cgroups/fs/cpuset.go | 16 +- .../docker/libcontainer/cgroups/fs/devices.go | 8 +- .../docker/libcontainer/cgroups/fs/freezer.go | 29 +- .../docker/libcontainer/cgroups/fs/memory.go | 16 +- .../libcontainer/cgroups/fs/memory_test.go | 32 +-- .../libcontainer/cgroups/fs/perf_event.go | 8 +- .../docker/libcontainer/cgroups/stats.go | 13 +- .../cgroups/systemd/apply_nosystemd.go | 4 + .../cgroups/systemd/apply_systemd.go | 60 +++- .../github.com/docker/libcontainer/config.go | 86 ++++++ .../{container_test.go => config_test.go} | 0 .../docker/libcontainer/container.go | 135 ++++----- .../github.com/docker/libcontainer/factory.go | 25 ++ .../docker/libcontainer/label/label.go | 4 + .../libcontainer/label/label_selinux.go | 17 ++ .../docker/libcontainer/mount/init.go | 10 +- .../docker/libcontainer/mount/types.go | 1 + .../docker/libcontainer/namespaces/exec.go | 7 +- .../docker/libcontainer/namespaces/execin.go | 4 +- .../docker/libcontainer/namespaces/init.go | 3 +- .../libcontainer/nsinit/{main.go => cli.go} | 8 +- .../docker/libcontainer/nsinit/config.go | 29 ++ .../docker/libcontainer/nsinit/exec.go | 2 +- .../docker/libcontainer/nsinit/init.go | 5 +- .../docker/libcontainer/nsinit/nsenter.go | 4 +- .../libcontainer/nsinit/nsinit/nsinit.go | 7 + .../docker/libcontainer/nsinit/pause.go | 49 ++++ .../docker/libcontainer/nsinit/spec.go | 40 --- .../docker/libcontainer/nsinit/stats.go | 23 +- .../docker/libcontainer/nsinit/utils.go | 2 +- .../github.com/docker/libcontainer/process.go | 27 ++ .../security/capabilities/capabilities.go | 2 +- .../security/capabilities/types.go | 2 - .../docker/libcontainer/selinux/selinux.go | 45 ++- .../github.com/docker/libcontainer/state.go | 23 +- .../{namespaces => syncpipe}/sync_pipe.go | 2 +- .../sync_pipe_linux.go | 2 +- .../sync_pipe_test.go | 2 +- 50 files changed, 917 insertions(+), 347 deletions(-) delete mode 100644 vendor/src/github.com/docker/libcontainer/api.go create mode 100644 vendor/src/github.com/docker/libcontainer/api_temp.go create mode 100644 vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go create mode 100644 vendor/src/github.com/docker/libcontainer/cgroups/cgutil/sample_cgroup.json create mode 100644 vendor/src/github.com/docker/libcontainer/config.go rename vendor/src/github.com/docker/libcontainer/{container_test.go => config_test.go} (100%) create mode 100644 vendor/src/github.com/docker/libcontainer/factory.go rename vendor/src/github.com/docker/libcontainer/nsinit/{main.go => cli.go} (86%) create mode 100644 vendor/src/github.com/docker/libcontainer/nsinit/config.go create mode 100644 vendor/src/github.com/docker/libcontainer/nsinit/nsinit/nsinit.go create mode 100644 vendor/src/github.com/docker/libcontainer/nsinit/pause.go delete mode 100644 vendor/src/github.com/docker/libcontainer/nsinit/spec.go create mode 100644 vendor/src/github.com/docker/libcontainer/process.go rename vendor/src/github.com/docker/libcontainer/{namespaces => syncpipe}/sync_pipe.go (98%) rename vendor/src/github.com/docker/libcontainer/{namespaces => syncpipe}/sync_pipe_linux.go (95%) rename vendor/src/github.com/docker/libcontainer/{namespaces => syncpipe}/sync_pipe_test.go (98%) diff --git a/hack/vendor.sh b/hack/vendor.sh index b0a89db68d..93ecc8131e 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -63,4 +63,4 @@ mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar clone git github.com/godbus/dbus v1 clone git github.com/coreos/go-systemd v2 -clone git github.com/docker/libcontainer 53cfe0a1eba9145bf5329abbb52b0072ccab8a00 +clone git github.com/docker/libcontainer fb67bb80b4205bece36ff7096ee745ab0cee7e06 diff --git a/vendor/src/github.com/docker/libcontainer/.travis.yml b/vendor/src/github.com/docker/libcontainer/.travis.yml index 94dc5ac7c8..d4c2045d8a 100644 --- a/vendor/src/github.com/docker/libcontainer/.travis.yml +++ b/vendor/src/github.com/docker/libcontainer/.travis.yml @@ -1,12 +1,25 @@ language: go +# let us have pretty experimental Docker-based Travis workers +sudo: false + +env: + - TRAVIS_GLOBAL_WTF=1 + - GOOS=linux GOARCH=amd64 + - GOOS=linux GOARCH=386 + - GOOS=linux GOARCH=arm + - GOOS=darwin GOARCH=amd64 + - GOOS=darwin GOARCH=386 + - GOOS=freebsd GOARCH=amd64 + install: - - go get -d ./... - - go get -d github.com/dotcloud/docker # just to be sure + - go get -d -v ./... + - go get -d -v github.com/dotcloud/docker # just to be sure - DOCKER_PATH="${GOPATH%%:*}/src/github.com/dotcloud/docker" - sed -i 's!dotcloud/docker!docker/libcontainer!' "$DOCKER_PATH/hack/make/.validate" script: - - bash "$DOCKER_PATH/hack/make/validate-dco" - - bash "$DOCKER_PATH/hack/make/validate-gofmt" - - go test + - if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-dco"; fi + - if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-gofmt"; fi + - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then go build -v ./...; fi + - if [ -z "$TRAVIS_GLOBAL_WTF" ]; then go test -v ./...; fi diff --git a/vendor/src/github.com/docker/libcontainer/api.go b/vendor/src/github.com/docker/libcontainer/api.go deleted file mode 100644 index 310f06e810..0000000000 --- a/vendor/src/github.com/docker/libcontainer/api.go +++ /dev/null @@ -1,23 +0,0 @@ -package libcontainer - -import ( - "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/network" -) - -// Returns all available stats for the given container. -func GetStats(container *Config, state *State) (*ContainerStats, error) { - var containerStats ContainerStats - stats, err := fs.GetStats(container.Cgroups) - if err != nil { - return &containerStats, err - } - containerStats.CgroupStats = stats - networkStats, err := network.GetStats(&state.NetworkState) - if err != nil { - return &containerStats, err - } - containerStats.NetworkStats = networkStats - - return &containerStats, nil -} diff --git a/vendor/src/github.com/docker/libcontainer/api_temp.go b/vendor/src/github.com/docker/libcontainer/api_temp.go new file mode 100644 index 0000000000..9b2c520774 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/api_temp.go @@ -0,0 +1,34 @@ +/* +Temporary API endpoint for libcontainer while the full API is finalized (api.go). +*/ +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(container.Cgroups) + } + + if err != nil { + return stats, err + } + + stats.NetworkStats, err = network.GetStats(&state.NetworkState) + + return stats, err +} diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go b/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go new file mode 100644 index 0000000000..f4a541eab2 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/cgutil.go @@ -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) + } +} diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/sample_cgroup.json b/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/sample_cgroup.json new file mode 100644 index 0000000000..2d29784941 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/cgroups/cgutil/sample_cgroup.json @@ -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 +} diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go index 8fa34c21c2..e9c06e1e2c 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go @@ -12,21 +12,21 @@ import ( var ( subsystems = map[string]subsystem{ - "devices": &devicesGroup{}, - "memory": &memoryGroup{}, - "cpu": &cpuGroup{}, - "cpuset": &cpusetGroup{}, - "cpuacct": &cpuacctGroup{}, - "blkio": &blkioGroup{}, - "perf_event": &perfEventGroup{}, - "freezer": &freezerGroup{}, + "devices": &DevicesGroup{}, + "memory": &MemoryGroup{}, + "cpu": &CpuGroup{}, + "cpuset": &CpusetGroup{}, + "cpuacct": &CpuacctGroup{}, + "blkio": &BlkioGroup{}, + "perf_event": &PerfEventGroup{}, + "freezer": &FreezerGroup{}, } ) type subsystem interface { Set(*data) error Remove(*data) error - GetStats(*data, *cgroups.Stats) error + GetStats(string, *cgroups.Stats) error } type data struct { @@ -52,6 +52,14 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { return d, nil } +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(c *cgroups.Cgroup) (*cgroups.Stats, error) { stats := cgroups.NewStats() @@ -60,10 +68,19 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) { return nil, fmt.Errorf("getting CgroupData %s", err) } - for sysName, sys := range subsystems { - // Don't fail if a cgroup hierarchy was not found. - if err := sys.GetStats(d, stats); err != nil && err != cgroups.ErrNotFound { - return nil, fmt.Errorf("getting stats for system %q %s", sysName, 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 err == cgroups.ErrNotFound { + continue + } + + return nil, err + } + + if err := sys.GetStats(path, stats); err != nil { + return nil, err } } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio.go index 0e0a198de6..38b8757727 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio.go @@ -11,10 +11,10 @@ import ( "github.com/docker/libcontainer/cgroups" ) -type blkioGroup struct { +type BlkioGroup struct { } -func (s *blkioGroup) Set(d *data) error { +func (s *BlkioGroup) Set(d *data) error { // we just want to join this group even though we don't set anything if _, err := d.join("blkio"); err != nil && err != cgroups.ErrNotFound { return err @@ -22,7 +22,7 @@ func (s *blkioGroup) Set(d *data) error { return nil } -func (s *blkioGroup) Remove(d *data) error { +func (s *BlkioGroup) Remove(d *data) error { return removePath(d.path("blkio")) } @@ -65,6 +65,9 @@ func getBlkioStat(path string) ([]cgroups.BlkioStatEntry, error) { var blkioStats []cgroups.BlkioStatEntry f, err := os.Open(path) if err != nil { + if os.IsNotExist(err) { + return blkioStats, nil + } return nil, err } defer f.Close() @@ -110,13 +113,9 @@ func getBlkioStat(path string) ([]cgroups.BlkioStatEntry, error) { return blkioStats, nil } -func (s *blkioGroup) GetStats(d *data, stats *cgroups.Stats) error { +func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error { var blkioStats []cgroups.BlkioStatEntry var err error - path, err := d.path("blkio") - if err != nil { - return err - } if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.sectors_recursive")); err != nil { return err diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go index c916c86bba..db6f8d5214 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go @@ -44,8 +44,8 @@ func TestBlkioStats(t *testing.T) { "blkio.sectors_recursive": sectorsRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } @@ -84,10 +84,10 @@ func TestBlkioStatsNoSectorsFile(t *testing.T) { "blkio.io_queued_recursive": queuedRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) - if err == nil { - t.Fatal("Expected to fail, but did not") + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) + if err != nil { + t.Fatalf("Failed unexpectedly: %s", err) } } @@ -100,10 +100,10 @@ func TestBlkioStatsNoServiceBytesFile(t *testing.T) { "blkio.sectors_recursive": sectorsRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) - if err == nil { - t.Fatal("Expected to fail, but did not") + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) + if err != nil { + t.Fatalf("Failed unexpectedly: %s", err) } } @@ -116,10 +116,10 @@ func TestBlkioStatsNoServicedFile(t *testing.T) { "blkio.sectors_recursive": sectorsRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) - if err == nil { - t.Fatal("Expected to fail, but did not") + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) + if err != nil { + t.Fatalf("Failed unexpectedly: %s", err) } } @@ -132,10 +132,10 @@ func TestBlkioStatsNoQueuedFile(t *testing.T) { "blkio.sectors_recursive": sectorsRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) - if err == nil { - t.Fatal("Expected to fail, but did not") + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) + if err != nil { + t.Fatalf("Failed unexpectedly: %s", err) } } @@ -149,8 +149,8 @@ func TestBlkioStatsUnexpectedNumberOfFields(t *testing.T) { "blkio.sectors_recursive": sectorsRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected to fail, but did not") } @@ -166,8 +166,8 @@ func TestBlkioStatsUnexpectedFieldType(t *testing.T) { "blkio.sectors_recursive": sectorsRecursiveContents, }) - blkio := &blkioGroup{} - err := blkio.GetStats(helper.CgroupData, &actualStats) + blkio := &BlkioGroup{} + err := blkio.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected to fail, but did not") } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu.go index 1c692fd550..efac9ed16a 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu.go @@ -5,15 +5,14 @@ import ( "os" "path/filepath" "strconv" - "syscall" "github.com/docker/libcontainer/cgroups" ) -type cpuGroup struct { +type CpuGroup struct { } -func (s *cpuGroup) Set(d *data) error { +func (s *CpuGroup) Set(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") @@ -38,19 +37,14 @@ func (s *cpuGroup) Set(d *data) error { return nil } -func (s *cpuGroup) Remove(d *data) error { +func (s *CpuGroup) Remove(d *data) error { return removePath(d.path("cpu")) } -func (s *cpuGroup) GetStats(d *data, stats *cgroups.Stats) error { - path, err := d.path("cpu") - if err != nil { - return err - } - +func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error { f, err := os.Open(filepath.Join(path, "cpu.stat")) if err != nil { - if pathErr, ok := err.(*os.PathError); ok && pathErr.Err == syscall.ENOENT { + if os.IsNotExist(err) { return nil } return err diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu_test.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu_test.go index ebdb6a5757..017a1f4b8e 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu_test.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpu_test.go @@ -23,8 +23,8 @@ func TestCpuStats(t *testing.T) { "cpu.stat": cpuStatContent, }) - cpu := &cpuGroup{} - err := cpu.GetStats(helper.CgroupData, &actualStats) + cpu := &CpuGroup{} + err := cpu.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } @@ -41,8 +41,8 @@ func TestNoCpuStatFile(t *testing.T) { helper := NewCgroupTestUtil("cpu", t) defer helper.cleanup() - cpu := &cpuGroup{} - err := cpu.GetStats(helper.CgroupData, &actualStats) + cpu := &CpuGroup{} + err := cpu.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal("Expected not to fail, but did") } @@ -58,8 +58,8 @@ func TestInvalidCpuStat(t *testing.T) { "cpu.stat": cpuStatContent, }) - cpu := &cpuGroup{} - err := cpu.GetStats(helper.CgroupData, &actualStats) + cpu := &CpuGroup{} + err := cpu.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failed stat parsing.") } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go index a3d22c9f74..be1805205a 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go @@ -22,10 +22,10 @@ var ( const nanosecondsInSecond = 1000000000 -type cpuacctGroup struct { +type CpuacctGroup struct { } -func (s *cpuacctGroup) Set(d *data) error { +func (s *CpuacctGroup) Set(d *data) error { // we just want to join this group even though we don't set anything if _, err := d.join("cpuacct"); err != nil && err != cgroups.ErrNotFound { return err @@ -33,20 +33,20 @@ func (s *cpuacctGroup) Set(d *data) error { return nil } -func (s *cpuacctGroup) Remove(d *data) error { +func (s *CpuacctGroup) Remove(d *data) error { return removePath(d.path("cpuacct")) } -func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error { +func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error { var ( + err error startCpu, lastCpu, startSystem, lastSystem, startUsage, lastUsage, kernelModeUsage, userModeUsage, percentage uint64 ) - path, err := d.path("cpuacct") - if kernelModeUsage, userModeUsage, err = s.getCpuUsage(d, path); err != nil { + if kernelModeUsage, userModeUsage, err = getCpuUsage(path); err != nil { return err } startCpu = kernelModeUsage + userModeUsage - if startSystem, err = s.getSystemCpuUsage(d); err != nil { + if startSystem, err = getSystemCpuUsage(); err != nil { return err } startUsageTime := time.Now() @@ -55,11 +55,11 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error { } // sample for 100ms time.Sleep(100 * time.Millisecond) - if kernelModeUsage, userModeUsage, err = s.getCpuUsage(d, path); err != nil { + if kernelModeUsage, userModeUsage, err = getCpuUsage(path); err != nil { return err } lastCpu = kernelModeUsage + userModeUsage - if lastSystem, err = s.getSystemCpuUsage(d); err != nil { + if lastSystem, err = getSystemCpuUsage(); err != nil { return err } usageSampleDuration := time.Since(startUsageTime) @@ -80,7 +80,7 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error { stats.CpuStats.CpuUsage.PercentUsage = percentage // Delta usage is in nanoseconds of CPU time so get the usage (in cores) over the sample time. stats.CpuStats.CpuUsage.CurrentUsage = deltaUsage / uint64(usageSampleDuration.Nanoseconds()) - percpuUsage, err := s.getPercpuUsage(path) + percpuUsage, err := getPercpuUsage(path) if err != nil { return err } @@ -92,7 +92,7 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error { } // TODO(vmarmol): Use cgroups stats. -func (s *cpuacctGroup) getSystemCpuUsage(d *data) (uint64, error) { +func getSystemCpuUsage() (uint64, error) { f, err := os.Open("/proc/stat") if err != nil { @@ -125,7 +125,7 @@ func (s *cpuacctGroup) getSystemCpuUsage(d *data) (uint64, error) { return 0, fmt.Errorf("invalid stat format") } -func (s *cpuacctGroup) getCpuUsage(d *data, path string) (uint64, uint64, error) { +func getCpuUsage(path string) (uint64, uint64, error) { kernelModeUsage := uint64(0) userModeUsage := uint64(0) data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.stat")) @@ -146,7 +146,7 @@ func (s *cpuacctGroup) getCpuUsage(d *data, path string) (uint64, uint64, error) return kernelModeUsage, userModeUsage, nil } -func (s *cpuacctGroup) getPercpuUsage(path string) ([]uint64, error) { +func getPercpuUsage(path string) ([]uint64, error) { percpuUsage := []uint64{} data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.usage_percpu")) if err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go index 094e8b382d..9570125fd4 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go @@ -10,10 +10,10 @@ import ( "github.com/docker/libcontainer/cgroups" ) -type cpusetGroup struct { +type CpusetGroup struct { } -func (s *cpusetGroup) Set(d *data) error { +func (s *CpusetGroup) Set(d *data) error { // we don't want to join this cgroup unless it is specified if d.c.CpusetCpus != "" { dir, err := d.path("cpuset") @@ -36,15 +36,15 @@ func (s *cpusetGroup) Set(d *data) error { return nil } -func (s *cpusetGroup) Remove(d *data) error { +func (s *CpusetGroup) Remove(d *data) error { return removePath(d.path("cpuset")) } -func (s *cpusetGroup) GetStats(d *data, stats *cgroups.Stats) error { +func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error { return nil } -func (s *cpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) { +func (s *CpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) { if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus")); err != nil { return } @@ -57,7 +57,7 @@ func (s *cpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []b // ensureParent ensures that the parent directory of current is created // with the proper cpus and mems files copied from it's parent if the values // are a file with a new line char -func (s *cpusetGroup) ensureParent(current string) error { +func (s *CpusetGroup) ensureParent(current string) error { parent := filepath.Dir(current) if _, err := os.Stat(parent); err != nil { @@ -78,7 +78,7 @@ func (s *cpusetGroup) ensureParent(current string) error { // copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent // directory to the current directory if the file's contents are 0 -func (s *cpusetGroup) copyIfNeeded(current, parent string) error { +func (s *CpusetGroup) copyIfNeeded(current, parent string) error { var ( err error currentCpus, currentMems []byte @@ -105,6 +105,6 @@ func (s *cpusetGroup) copyIfNeeded(current, parent string) error { return nil } -func (s *cpusetGroup) isEmpty(b []byte) bool { +func (s *CpusetGroup) isEmpty(b []byte) bool { return len(bytes.Trim(b, "\n")) == 0 } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/devices.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/devices.go index 675cef3fb2..98d5d2d7dd 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/devices.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/devices.go @@ -2,10 +2,10 @@ package fs import "github.com/docker/libcontainer/cgroups" -type devicesGroup struct { +type DevicesGroup struct { } -func (s *devicesGroup) Set(d *data) error { +func (s *DevicesGroup) Set(d *data) error { dir, err := d.join("devices") if err != nil { return err @@ -25,10 +25,10 @@ func (s *devicesGroup) Set(d *data) error { return nil } -func (s *devicesGroup) Remove(d *data) error { +func (s *DevicesGroup) Remove(d *data) error { return removePath(d.path("devices")) } -func (s *devicesGroup) GetStats(d *data, stats *cgroups.Stats) error { +func (s *DevicesGroup) GetStats(path string, stats *cgroups.Stats) error { return nil } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/freezer.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/freezer.go index f6a1044af6..db2a41ca34 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/freezer.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/freezer.go @@ -1,18 +1,16 @@ package fs import ( - "io/ioutil" - "path/filepath" "strings" "time" "github.com/docker/libcontainer/cgroups" ) -type freezerGroup struct { +type FreezerGroup struct { } -func (s *freezerGroup) Set(d *data) error { +func (s *FreezerGroup) Set(d *data) error { switch d.c.Freezer { case cgroups.Frozen, cgroups.Thawed: dir, err := d.path("freezer") @@ -43,29 +41,10 @@ func (s *freezerGroup) Set(d *data) error { return nil } -func (s *freezerGroup) Remove(d *data) error { +func (s *FreezerGroup) Remove(d *data) error { return removePath(d.path("freezer")) } -func getFreezerFileData(path string) (string, error) { - data, err := ioutil.ReadFile(path) - return strings.TrimSuffix(string(data), "\n"), err -} - -func (s *freezerGroup) GetStats(d *data, stats *cgroups.Stats) error { - path, err := d.path("freezer") - if err != nil { - return err - } - var data string - if data, err = getFreezerFileData(filepath.Join(path, "freezer.parent_freezing")); err != nil { - return err - } - stats.FreezerStats.ParentState = data - if data, err = getFreezerFileData(filepath.Join(path, "freezer.self_freezing")); err != nil { - return err - } - stats.FreezerStats.SelfState = data - +func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error { return nil } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go index b4453f4e71..c27150d2bf 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go @@ -9,10 +9,10 @@ import ( "github.com/docker/libcontainer/cgroups" ) -type memoryGroup struct { +type MemoryGroup struct { } -func (s *memoryGroup) Set(d *data) error { +func (s *MemoryGroup) Set(d *data) error { dir, err := d.join("memory") // only return an error for memory if it was not specified if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) { @@ -47,19 +47,17 @@ func (s *memoryGroup) Set(d *data) error { return nil } -func (s *memoryGroup) Remove(d *data) error { +func (s *MemoryGroup) Remove(d *data) error { return removePath(d.path("memory")) } -func (s *memoryGroup) GetStats(d *data, stats *cgroups.Stats) error { - path, err := d.path("memory") - if err != nil { - return err - } - +func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { // Set stats from memory.stat. statsFile, err := os.Open(filepath.Join(path, "memory.stat")) if err != nil { + if os.IsNotExist(err) { + return nil + } return err } defer statsFile.Close() diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory_test.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory_test.go index 8307482bce..e92f1dafe6 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory_test.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory_test.go @@ -24,8 +24,8 @@ func TestMemoryStats(t *testing.T) { "memory.failcnt": memoryFailcnt, }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) if err != nil { t.Fatal(err) } @@ -41,10 +41,10 @@ func TestMemoryStatsNoStatFile(t *testing.T) { "memory.max_usage_in_bytes": memoryMaxUsageContents, }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) - if err == nil { - t.Fatal("Expected failure") + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) + if err != nil { + t.Fatal(err) } } @@ -56,8 +56,8 @@ func TestMemoryStatsNoUsageFile(t *testing.T) { "memory.max_usage_in_bytes": memoryMaxUsageContents, }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } @@ -71,8 +71,8 @@ func TestMemoryStatsNoMaxUsageFile(t *testing.T) { "memory.usage_in_bytes": memoryUsageContents, }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } @@ -87,8 +87,8 @@ func TestMemoryStatsBadStatFile(t *testing.T) { "memory.max_usage_in_bytes": memoryMaxUsageContents, }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } @@ -103,8 +103,8 @@ func TestMemoryStatsBadUsageFile(t *testing.T) { "memory.max_usage_in_bytes": memoryMaxUsageContents, }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } @@ -119,8 +119,8 @@ func TestMemoryStatsBadMaxUsageFile(t *testing.T) { "memory.max_usage_in_bytes": "bad", }) - memory := &memoryGroup{} - err := memory.GetStats(helper.CgroupData, &actualStats) + memory := &MemoryGroup{} + err := memory.GetStats(helper.CgroupPath, &actualStats) if err == nil { t.Fatal("Expected failure") } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/perf_event.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/perf_event.go index b834c3ecae..5f45678ff3 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/perf_event.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/perf_event.go @@ -4,10 +4,10 @@ import ( "github.com/docker/libcontainer/cgroups" ) -type perfEventGroup struct { +type PerfEventGroup struct { } -func (s *perfEventGroup) Set(d *data) error { +func (s *PerfEventGroup) Set(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 && err != cgroups.ErrNotFound { return err @@ -15,10 +15,10 @@ func (s *perfEventGroup) Set(d *data) error { return nil } -func (s *perfEventGroup) Remove(d *data) error { +func (s *PerfEventGroup) Remove(d *data) error { return removePath(d.path("perf_event")) } -func (s *perfEventGroup) GetStats(d *data, stats *cgroups.Stats) error { +func (s *PerfEventGroup) GetStats(path string, stats *cgroups.Stats) error { return nil } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/stats.go b/vendor/src/github.com/docker/libcontainer/cgroups/stats.go index 2640245e51..49913bcefa 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/stats.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/stats.go @@ -55,17 +55,10 @@ type BlkioStats struct { SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"` } -// TODO(Vishh): Remove freezer from stats since it does not logically belong in stats. -type FreezerStats struct { - ParentState string `json:"parent_state,omitempty"` - SelfState string `json:"self_state,omitempty"` -} - type Stats struct { - CpuStats CpuStats `json:"cpu_stats,omitempty"` - MemoryStats MemoryStats `json:"memory_stats,omitempty"` - BlkioStats BlkioStats `json:"blkio_stats,omitempty"` - FreezerStats FreezerStats `json:"freezer_stats,omitempty"` + CpuStats CpuStats `json:"cpu_stats,omitempty"` + MemoryStats MemoryStats `json:"memory_stats,omitempty"` + BlkioStats BlkioStats `json:"blkio_stats,omitempty"` } func NewStats() *Stats { diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_nosystemd.go b/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_nosystemd.go index 6dcfdffd48..685591090b 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_nosystemd.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_nosystemd.go @@ -23,3 +23,7 @@ func GetPids(c *cgroups.Cgroup) ([]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/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go b/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go index 6a0ce950c1..5755a5f4b7 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go @@ -15,6 +15,7 @@ import ( systemd1 "github.com/coreos/go-systemd/dbus" "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/cgroups/fs" "github.com/dotcloud/docker/pkg/systemd" "github.com/godbus/dbus" ) @@ -23,10 +24,24 @@ type systemdCgroup struct { cleanupDirs []string } +type subsystem interface { + GetStats(string, *cgroups.Stats) error +} + var ( connLock sync.Mutex theConn *systemd1.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 UseSystemd() bool { @@ -316,7 +331,7 @@ func (c *systemdCgroup) Cleanup() error { } func joinFreezer(c *cgroups.Cgroup, pid int) (string, error) { - path, err := getFreezerPath(c) + path, err := getSubsystemPath(c, "freezer") if err != nil { return "", err } @@ -332,23 +347,27 @@ func joinFreezer(c *cgroups.Cgroup, pid int) (string, error) { return path, nil } -func getFreezerPath(c *cgroups.Cgroup) (string, error) { - mountpoint, err := cgroups.FindCgroupMountpoint("freezer") +func getSubsystemPath(c *cgroups.Cgroup, subsystem string) (string, error) { + mountpoint, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { return "", err } - initPath, err := cgroups.GetInitCgroupDir("freezer") + initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err } - return filepath.Join(mountpoint, initPath, fmt.Sprintf("%s-%s", c.Parent, c.Name)), nil + slice := "system.slice" + if c.Slice != "" { + slice = c.Slice + } + return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil } func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error { - path, err := getFreezerPath(c) + path, err := getSubsystemPath(c, "freezer") if err != nil { return err } @@ -389,3 +408,32 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) { 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 err == cgroups.ErrNotFound { + continue + } + + return nil, err + } + + if err := sys.GetStats(subsystemPath, stats); err != nil { + return nil, err + } + } + + return stats, nil +} diff --git a/vendor/src/github.com/docker/libcontainer/config.go b/vendor/src/github.com/docker/libcontainer/config.go new file mode 100644 index 0000000000..8fe95c24f7 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/config.go @@ -0,0 +1,86 @@ +package libcontainer + +import ( + "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/mount" + "github.com/docker/libcontainer/network" +) + +type MountConfig mount.MountConfig + +type Network network.Network + +// Config defines configuration options for executing a process inside a contained environment. +type Config struct { + // Mount specific options. + MountConfig *MountConfig `json:"mount_config,omitempty"` + + // Hostname optionally sets the container's hostname if provided + Hostname string `json:"hostname,omitempty"` + + // User will set the uid and gid of the executing process running inside the container + User string `json:"user,omitempty"` + + // WorkingDir will change the processes current working directory inside the container's rootfs + WorkingDir string `json:"working_dir,omitempty"` + + // Env will populate the processes environment with the provided values + // Any values from the parent processes will be cleared before the values + // provided in Env are provided to the process + Env []string `json:"environment,omitempty"` + + // Tty when true will allocate a pty slave on the host for access by the container's process + // and ensure that it is mounted inside the container's rootfs + Tty bool `json:"tty,omitempty"` + + // Namespaces specifies the container's namespaces that it should setup when cloning the init process + // If a namespace is not provided that namespace is shared from the container's parent process + Namespaces map[string]bool `json:"namespaces,omitempty"` + + // Capabilities specify the capabilities to keep when executing the process inside the container + // All capbilities not specified will be dropped from the processes capability mask + Capabilities []string `json:"capabilities,omitempty"` + + // Networks specifies the container's network setup to be created + Networks []*Network `json:"networks,omitempty"` + + // Routes can be specified to create entries in the route table as the container is started + Routes []*Route `json:"routes,omitempty"` + + // Cgroups specifies specific cgroup settings for the various subsystems that the container is + // placed into to limit the resources the container has available + Cgroups *cgroups.Cgroup `json:"cgroups,omitempty"` + + // AppArmorProfile specifies the profile to apply to the process running in the container and is + // change at the time the process is execed + AppArmorProfile string `json:"apparmor_profile,omitempty"` + + // ProcessLabel specifies the label to apply to the process running in the container. It is + // commonly used by selinux + ProcessLabel string `json:"process_label,omitempty"` + + // RestrictSys will remount /proc/sys, /sys, and mask over sysrq-trigger as well as /proc/irq and + // /proc/bus + RestrictSys bool `json:"restrict_sys,omitempty"` +} + +// Routes can be specified to create entries in the route table as the container is started +// +// All of destination, source, and gateway should be either IPv4 or IPv6. +// One of the three options must be present, and ommitted entries will use their +// IP family default for the route table. For IPv4 for example, setting the +// gateway to 1.2.3.4 and the interface to eth0 will set up a standard +// destination of 0.0.0.0(or *) when viewed in the route table. +type Route struct { + // Sets the destination and mask, should be a CIDR. Accepts IPv4 and IPv6 + Destination string `json:"destination,omitempty"` + + // Sets the source and mask, should be a CIDR. Accepts IPv4 and IPv6 + Source string `json:"source,omitempty"` + + // Sets the gateway. Accepts IPv4 and IPv6 + Gateway string `json:"gateway,omitempty"` + + // The device to set this route up for, for example: eth0 + InterfaceName string `json:"interface_name,omitempty"` +} diff --git a/vendor/src/github.com/docker/libcontainer/container_test.go b/vendor/src/github.com/docker/libcontainer/config_test.go similarity index 100% rename from vendor/src/github.com/docker/libcontainer/container_test.go rename to vendor/src/github.com/docker/libcontainer/config_test.go diff --git a/vendor/src/github.com/docker/libcontainer/container.go b/vendor/src/github.com/docker/libcontainer/container.go index 8fe95c24f7..5fb2bba651 100644 --- a/vendor/src/github.com/docker/libcontainer/container.go +++ b/vendor/src/github.com/docker/libcontainer/container.go @@ -1,86 +1,63 @@ +/* +NOTE: The API is in flux and mainly not implemented. Proceed with caution until further notice. +*/ package libcontainer -import ( - "github.com/docker/libcontainer/cgroups" - "github.com/docker/libcontainer/mount" - "github.com/docker/libcontainer/network" -) - -type MountConfig mount.MountConfig - -type Network network.Network - -// Config defines configuration options for executing a process inside a contained environment. -type Config struct { - // Mount specific options. - MountConfig *MountConfig `json:"mount_config,omitempty"` - - // Hostname optionally sets the container's hostname if provided - Hostname string `json:"hostname,omitempty"` - - // User will set the uid and gid of the executing process running inside the container - User string `json:"user,omitempty"` - - // WorkingDir will change the processes current working directory inside the container's rootfs - WorkingDir string `json:"working_dir,omitempty"` - - // Env will populate the processes environment with the provided values - // Any values from the parent processes will be cleared before the values - // provided in Env are provided to the process - Env []string `json:"environment,omitempty"` - - // Tty when true will allocate a pty slave on the host for access by the container's process - // and ensure that it is mounted inside the container's rootfs - Tty bool `json:"tty,omitempty"` - - // Namespaces specifies the container's namespaces that it should setup when cloning the init process - // If a namespace is not provided that namespace is shared from the container's parent process - Namespaces map[string]bool `json:"namespaces,omitempty"` - - // Capabilities specify the capabilities to keep when executing the process inside the container - // All capbilities not specified will be dropped from the processes capability mask - Capabilities []string `json:"capabilities,omitempty"` - - // Networks specifies the container's network setup to be created - Networks []*Network `json:"networks,omitempty"` - - // Routes can be specified to create entries in the route table as the container is started - Routes []*Route `json:"routes,omitempty"` - - // Cgroups specifies specific cgroup settings for the various subsystems that the container is - // placed into to limit the resources the container has available - Cgroups *cgroups.Cgroup `json:"cgroups,omitempty"` - - // AppArmorProfile specifies the profile to apply to the process running in the container and is - // change at the time the process is execed - AppArmorProfile string `json:"apparmor_profile,omitempty"` - - // ProcessLabel specifies the label to apply to the process running in the container. It is - // commonly used by selinux - ProcessLabel string `json:"process_label,omitempty"` - - // RestrictSys will remount /proc/sys, /sys, and mask over sysrq-trigger as well as /proc/irq and - // /proc/bus - RestrictSys bool `json:"restrict_sys,omitempty"` -} - -// Routes can be specified to create entries in the route table as the container is started +// A libcontainer container object. // -// All of destination, source, and gateway should be either IPv4 or IPv6. -// One of the three options must be present, and ommitted entries will use their -// IP family default for the route table. For IPv4 for example, setting the -// gateway to 1.2.3.4 and the interface to eth0 will set up a standard -// destination of 0.0.0.0(or *) when viewed in the route table. -type Route struct { - // Sets the destination and mask, should be a CIDR. Accepts IPv4 and IPv6 - Destination string `json:"destination,omitempty"` +// Each container is thread-safe within the same process. Since a container can +// be destroyed by a separate process, any function may return that the container +// was not found. +type Container interface { + // Returns the path to the container which contains the state + Path() string - // Sets the source and mask, should be a CIDR. Accepts IPv4 and IPv6 - Source string `json:"source,omitempty"` + // Returns the current run state of the container. + // + // Errors: container no longer exists, + // system error. + RunState() (*RunState, error) - // Sets the gateway. Accepts IPv4 and IPv6 - Gateway string `json:"gateway,omitempty"` + // Returns the current config of the container. + Config() *Config - // The device to set this route up for, for example: eth0 - InterfaceName string `json:"interface_name,omitempty"` + // Destroys the container after killing all running processes. + // + // Any event registrations are removed before the container is destroyed. + // No error is returned if the container is already destroyed. + // + // Errors: system error. + Destroy() error + + // Returns the PIDs inside this container. The PIDs are in the namespace of the calling process. + // + // Errors: container no longer exists, + // system error. + // + // Some of the returned PIDs may no longer refer to processes in the Container, unless + // the Container state is PAUSED in which case every PID in the slice is valid. + Processes() ([]int, error) + + // Returns statistics for the container. + // + // Errors: container no longer exists, + // system error. + Stats() (*ContainerStats, error) + + // If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses + // the execution of any user processes. Asynchronously, when the container finished being paused the + // state is changed to PAUSED. + // If the Container state is PAUSED, do nothing. + // + // Errors: container no longer exists, + // system error. + Pause() error + + // If the Container state is PAUSED, resumes the execution of any user processes in the + // Container before setting the Container state to RUNNING. + // If the Container state is RUNNING, do nothing. + // + // Errors: container no longer exists, + // system error. + Resume() error } diff --git a/vendor/src/github.com/docker/libcontainer/factory.go b/vendor/src/github.com/docker/libcontainer/factory.go new file mode 100644 index 0000000000..9161ff05f3 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/factory.go @@ -0,0 +1,25 @@ +package libcontainer + +type Factory interface { + // Creates a new container in the given path. A unique ID is generated for the container and + // starts the initial process inside the container. + // + // Returns the new container with a running process. + // + // Errors: + // Path already exists + // Config or initialConfig is invalid + // System error + // + // On error, any partially created container parts are cleaned up (the operation is atomic). + Create(path string, config *Config) (Container, error) + + // Load takes the path for an existing container and reconstructs the container + // from the state. + // + // Errors: + // Path does not exist + // Container is stopped + // System error + Load(path string) (Container, error) +} diff --git a/vendor/src/github.com/docker/libcontainer/label/label.go b/vendor/src/github.com/docker/libcontainer/label/label.go index 434e1c5725..5c8228cdde 100644 --- a/vendor/src/github.com/docker/libcontainer/label/label.go +++ b/vendor/src/github.com/docker/libcontainer/label/label.go @@ -18,6 +18,10 @@ func SetFileLabel(path string, fileLabel string) error { return nil } +func Relabel(path string, fileLabel string, relabel string) error { + return nil +} + func GetPidCon(pid int) (string, error) { return "", nil } diff --git a/vendor/src/github.com/docker/libcontainer/label/label_selinux.go b/vendor/src/github.com/docker/libcontainer/label/label_selinux.go index 0452144482..aa502a3d6f 100644 --- a/vendor/src/github.com/docker/libcontainer/label/label_selinux.go +++ b/vendor/src/github.com/docker/libcontainer/label/label_selinux.go @@ -66,6 +66,23 @@ func SetFileLabel(path string, fileLabel string) error { return nil } +// Change the label of path to the filelabel string. If the relabel string +// is "z", relabel will change the MCS label to s0. This will allow all +// containers to share the content. If the relabel string is a "Z" then +// the MCS label should continue to be used. SELinux will use this field +// to make sure the content can not be shared by other containes. +func Relabel(path string, fileLabel string, relabel string) error { + if fileLabel == "" { + return nil + } + if relabel == "z" { + c := selinux.NewContext(fileLabel) + c["level"] = "s0" + fileLabel = c.Get() + } + return selinux.Chcon(path, fileLabel, true) +} + func GetPidCon(pid int) (string, error) { if !selinux.SelinuxEnabled() { return "", nil diff --git a/vendor/src/github.com/docker/libcontainer/mount/init.go b/vendor/src/github.com/docker/libcontainer/mount/init.go index 34fad6dd19..10f0738903 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/init.go +++ b/vendor/src/github.com/docker/libcontainer/mount/init.go @@ -44,7 +44,7 @@ func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig) if err := mountSystem(rootfs, mountConfig); err != nil { return fmt.Errorf("mount system %s", err) } - if err := setupBindmounts(rootfs, mountConfig.Mounts); err != nil { + if err := setupBindmounts(rootfs, mountConfig); err != nil { return fmt.Errorf("bind mounts %s", err) } if err := nodes.CreateDeviceNodes(rootfs, mountConfig.DeviceNodes); err != nil { @@ -144,7 +144,8 @@ func setupDevSymlinks(rootfs string) error { return nil } -func setupBindmounts(rootfs string, bindMounts Mounts) error { +func setupBindmounts(rootfs string, mountConfig *MountConfig) error { + bindMounts := mountConfig.Mounts for _, m := range bindMounts.OfType("bind") { var ( flags = syscall.MS_BIND | syscall.MS_REC @@ -176,6 +177,11 @@ func setupBindmounts(rootfs string, bindMounts Mounts) error { return fmt.Errorf("remounting %s into %s %s", m.Source, dest, err) } } + if m.Relabel != "" { + if err := label.Relabel(m.Source, mountConfig.MountLabel, m.Relabel); err != nil { + return fmt.Errorf("relabeling %s to %s %s", m.Source, mountConfig.MountLabel, err) + } + } if m.Private { if err := system.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil { return fmt.Errorf("mounting %s private %s", dest, err) diff --git a/vendor/src/github.com/docker/libcontainer/mount/types.go b/vendor/src/github.com/docker/libcontainer/mount/types.go index a2659e582e..063bbac1c5 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/types.go +++ b/vendor/src/github.com/docker/libcontainer/mount/types.go @@ -30,6 +30,7 @@ type Mount struct { Source string `json:"source,omitempty"` // Source path, in the host namespace Destination string `json:"destination,omitempty"` // Destination path, in the container Writable bool `json:"writable,omitempty"` + Relabel string `json:"relabel,omitempty"` // Relabel source if set, "z" indicates shared, "Z" indicates unshared Private bool `json:"private,omitempty"` } diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go index 0aa2bb9c7a..9053f632a4 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go @@ -12,6 +12,7 @@ import ( "github.com/docker/libcontainer/cgroups/fs" "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/network" + "github.com/docker/libcontainer/syncpipe" "github.com/dotcloud/docker/pkg/system" ) @@ -28,7 +29,7 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string // create a pipe so that we can syncronize with the namespaced process and // pass the veth name to the child - syncPipe, err := NewSyncPipe() + syncPipe, err := syncpipe.NewSyncPipe() if err != nil { return -1, err } @@ -42,7 +43,7 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string term.SetMaster(master) } - command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args) + command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.Child(), args) if err := term.Attach(command); err != nil { return -1, err @@ -166,7 +167,7 @@ func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgro // 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 *libcontainer.Config, nspid int, pipe *SyncPipe, networkState *network.NetworkState) error { +func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *syncpipe.SyncPipe, networkState *network.NetworkState) error { for _, config := range container.Networks { strategy, err := network.GetStrategy(config.Type) if err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/execin.go b/vendor/src/github.com/docker/libcontainer/namespaces/execin.go index d349282e84..3e79f4cda8 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/execin.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/execin.go @@ -30,8 +30,8 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, args []st panic("unreachable") } -// NsEnter is run after entering the namespace. -func NsEnter(container *libcontainer.Config, nspid int, args []string) error { +// Run a command in a container after entering the namespace. +func NsEnter(container *libcontainer.Config, args []string) error { // clear the current processes env and replace it with the environment // defined on the container if err := LoadContainerEnvironment(container); err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/init.go b/vendor/src/github.com/docker/libcontainer/namespaces/init.go index 53d2611b89..4674944cb7 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/init.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/init.go @@ -18,6 +18,7 @@ import ( "github.com/docker/libcontainer/network" "github.com/docker/libcontainer/security/capabilities" "github.com/docker/libcontainer/security/restrict" + "github.com/docker/libcontainer/syncpipe" "github.com/docker/libcontainer/utils" "github.com/dotcloud/docker/pkg/system" "github.com/dotcloud/docker/pkg/user" @@ -27,7 +28,7 @@ import ( // Move this to libcontainer package. // Init is the init process that first runs inside a new namespace to setup mounts, users, networking, // and other options required for the new container. -func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) (err error) { +func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *syncpipe.SyncPipe, args []string) (err error) { defer func() { if err != nil { syncPipe.ReportChildError(err) diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/main.go b/vendor/src/github.com/docker/libcontainer/nsinit/cli.go similarity index 86% rename from vendor/src/github.com/docker/libcontainer/nsinit/main.go rename to vendor/src/github.com/docker/libcontainer/nsinit/cli.go index 20132de0e0..d4235aef86 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/main.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/cli.go @@ -1,4 +1,4 @@ -package main +package nsinit import ( "log" @@ -19,7 +19,7 @@ func preload(context *cli.Context) error { return nil } -func main() { +func NsInit() { app := cli.NewApp() app.Name = "nsinit" app.Version = "0.1" @@ -30,8 +30,10 @@ func main() { execCommand, initCommand, statsCommand, - specCommand, + configCommand, nsenterCommand, + pauseCommand, + unpauseCommand, } if err := app.Run(os.Args); err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/config.go b/vendor/src/github.com/docker/libcontainer/nsinit/config.go new file mode 100644 index 0000000000..5beb04acb3 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/nsinit/config.go @@ -0,0 +1,29 @@ +package nsinit + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/codegangsta/cli" +) + +var configCommand = cli.Command{ + Name: "config", + Usage: "display the container configuration", + Action: configAction, +} + +func configAction(context *cli.Context) { + container, err := loadContainer() + if err != nil { + log.Fatal(err) + } + + data, err := json.MarshalIndent(container, "", "\t") + if err != nil { + log.Fatal(err) + } + + fmt.Printf("%s", data) +} diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go index c58c30664e..eb734545b5 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go @@ -1,4 +1,4 @@ -package main +package nsinit import ( "fmt" diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/init.go b/vendor/src/github.com/docker/libcontainer/nsinit/init.go index eedb961054..0dd964115c 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/init.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/init.go @@ -1,4 +1,4 @@ -package main +package nsinit import ( "log" @@ -7,6 +7,7 @@ import ( "github.com/codegangsta/cli" "github.com/docker/libcontainer/namespaces" + "github.com/docker/libcontainer/syncpipe" ) var ( @@ -37,7 +38,7 @@ func initAction(context *cli.Context) { log.Fatal(err) } - syncPipe, err := namespaces.NewSyncPipeFromFd(0, uintptr(pipeFd)) + syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(pipeFd)) if err != nil { log.Fatalf("unable to create sync pipe: %s", err) } diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go b/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go index faa61315e0..743b20a929 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/nsenter.go @@ -1,4 +1,4 @@ -package main +package nsinit import ( "log" @@ -34,7 +34,7 @@ func nsenterAction(context *cli.Context) { log.Fatalf("cannot enter into namespaces without valid pid: %q", nspid) } - if err := namespaces.NsEnter(container, nspid, args); err != nil { + if err := namespaces.NsEnter(container, args); err != nil { log.Fatalf("failed to nsenter: %s", err) } } diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/nsinit/nsinit.go b/vendor/src/github.com/docker/libcontainer/nsinit/nsinit/nsinit.go new file mode 100644 index 0000000000..816c4da5f9 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/nsinit/nsinit/nsinit.go @@ -0,0 +1,7 @@ +package main + +import "github.com/docker/libcontainer/nsinit" + +func main() { + nsinit.NsInit() +} diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/pause.go b/vendor/src/github.com/docker/libcontainer/nsinit/pause.go new file mode 100644 index 0000000000..492a0e858a --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/nsinit/pause.go @@ -0,0 +1,49 @@ +package nsinit + +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{ + Name: "pause", + Usage: "pause the container's processes", + Action: pauseAction, +} + +var unpauseCommand = cli.Command{ + Name: "unpause", + Usage: "unpause the container's processes", + Action: unpauseAction, +} + +func pauseAction(context *cli.Context) { + if err := toggle(cgroups.Frozen); err != nil { + log.Fatal(err) + } +} + +func unpauseAction(context *cli.Context) { + if err := toggle(cgroups.Thawed); err != nil { + log.Fatal(err) + } +} + +func toggle(state cgroups.FreezerState) error { + container, err := loadContainer() + if err != nil { + return err + } + + if systemd.UseSystemd() { + err = systemd.Freeze(container.Cgroups, state) + } else { + err = fs.Freeze(container.Cgroups, state) + } + + return err +} diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/spec.go b/vendor/src/github.com/docker/libcontainer/nsinit/spec.go deleted file mode 100644 index beadc9d87a..0000000000 --- a/vendor/src/github.com/docker/libcontainer/nsinit/spec.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "log" - - "github.com/codegangsta/cli" - "github.com/docker/libcontainer" -) - -var specCommand = cli.Command{ - Name: "spec", - Usage: "display the container specification", - Action: specAction, -} - -func specAction(context *cli.Context) { - container, err := loadContainer() - if err != nil { - log.Fatal(err) - } - - spec, err := getContainerSpec(container) - if err != nil { - log.Fatalf("Failed to get spec - %v\n", err) - } - - fmt.Printf("Spec:\n%v\n", spec) -} - -// returns the container spec in json format. -func getContainerSpec(container *libcontainer.Config) (string, error) { - spec, err := json.MarshalIndent(container, "", "\t") - if err != nil { - return "", err - } - - return string(spec), nil -} diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/stats.go b/vendor/src/github.com/docker/libcontainer/nsinit/stats.go index eae9833808..3e59305b03 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/stats.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/stats.go @@ -1,4 +1,4 @@ -package main +package nsinit import ( "encoding/json" @@ -21,30 +21,19 @@ func statsAction(context *cli.Context) { log.Fatal(err) } - runtimeCkpt, err := libcontainer.GetState(dataPath) + state, err := libcontainer.GetState(dataPath) if err != nil { log.Fatal(err) } - stats, err := getStats(container, runtimeCkpt) - if err != nil { - log.Fatalf("Failed to get stats - %v\n", err) - } - - fmt.Printf("Stats:\n%v\n", stats) -} - -// returns the container stats in json format. -func getStats(container *libcontainer.Config, state *libcontainer.State) (string, error) { stats, err := libcontainer.GetStats(container, state) if err != nil { - return "", err + log.Fatal(err) } - - out, err := json.MarshalIndent(stats, "", "\t") + data, err := json.MarshalIndent(stats, "", "\t") if err != nil { - return "", err + log.Fatal(err) } - return string(out), nil + fmt.Printf("%s", data) } diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/utils.go b/vendor/src/github.com/docker/libcontainer/nsinit/utils.go index 44194d885b..8525ba9a6d 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/utils.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/utils.go @@ -1,4 +1,4 @@ -package main +package nsinit import ( "encoding/json" diff --git a/vendor/src/github.com/docker/libcontainer/process.go b/vendor/src/github.com/docker/libcontainer/process.go new file mode 100644 index 0000000000..489666a587 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/process.go @@ -0,0 +1,27 @@ +package libcontainer + +import "io" + +// Configuration for a process to be run inside a container. +type ProcessConfig struct { + // The command to be run followed by any arguments. + Args []string + + // Map of environment variables to their values. + Env []string + + // Stdin is a pointer to a reader which provides the standard input stream. + // Stdout is a pointer to a writer which receives the standard output stream. + // Stderr is a pointer to a writer which receives the standard error stream. + // + // If a reader or writer is nil, the input stream is assumed to be empty and the output is + // discarded. + // + // The readers and writers, if supplied, are closed when the process terminates. Their Close + // methods should be idempotent. + // + // Stdout and Stderr may refer to the same writer in which case the output is interspersed. + Stdin io.ReadCloser + Stdout io.WriteCloser + Stderr io.WriteCloser +} diff --git a/vendor/src/github.com/docker/libcontainer/security/capabilities/capabilities.go b/vendor/src/github.com/docker/libcontainer/security/capabilities/capabilities.go index 21e4de26e0..7aef5fa67f 100644 --- a/vendor/src/github.com/docker/libcontainer/security/capabilities/capabilities.go +++ b/vendor/src/github.com/docker/libcontainer/security/capabilities/capabilities.go @@ -27,7 +27,7 @@ func DropBoundingSet(capabilities []string) error { return nil } -// DropCapabilities drops all capabilities for the current process expect those specified in the container configuration. +// DropCapabilities drops all capabilities for the current process except those specified in the container configuration. func DropCapabilities(capList []string) error { c, err := capability.NewPid(os.Getpid()) if err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/security/capabilities/types.go b/vendor/src/github.com/docker/libcontainer/security/capabilities/types.go index feb38e3338..a960b804c6 100644 --- a/vendor/src/github.com/docker/libcontainer/security/capabilities/types.go +++ b/vendor/src/github.com/docker/libcontainer/security/capabilities/types.go @@ -64,8 +64,6 @@ var capabilityList = Capabilities{ {Key: "MAC_ADMIN", Value: capability.CAP_MAC_ADMIN}, {Key: "NET_ADMIN", Value: capability.CAP_NET_ADMIN}, {Key: "SYSLOG", Value: capability.CAP_SYSLOG}, - {Key: "SETUID", Value: capability.CAP_SETUID}, - {Key: "SETGID", Value: capability.CAP_SETGID}, {Key: "CHOWN", Value: capability.CAP_CHOWN}, {Key: "NET_RAW", Value: capability.CAP_NET_RAW}, {Key: "DAC_OVERRIDE", Value: capability.CAP_DAC_OVERRIDE}, diff --git a/vendor/src/github.com/docker/libcontainer/selinux/selinux.go b/vendor/src/github.com/docker/libcontainer/selinux/selinux.go index 6cf7bd7104..709eb9d815 100644 --- a/vendor/src/github.com/docker/libcontainer/selinux/selinux.go +++ b/vendor/src/github.com/docker/libcontainer/selinux/selinux.go @@ -9,6 +9,7 @@ import ( "github.com/dotcloud/docker/pkg/system" "io" "os" + "path/filepath" "regexp" "strconv" "strings" @@ -76,7 +77,7 @@ func SelinuxEnabled() bool { } selinuxEnabledChecked = true if fs := getSelinuxMountPoint(); fs != "" { - if con, _ := getcon(); con != "kernel" { + if con, _ := Getcon(); con != "kernel" { selinuxEnabled = true } } @@ -145,6 +146,12 @@ func Setfilecon(path string, scon string) error { return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0) } +// Return the SELinux label for this path +func Getfilecon(path string) (string, error) { + con, err := system.Lgetxattr(path, xattrNameSelinux) + return string(con), err +} + func Setfscreatecon(scon string) error { return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", system.Gettid()), scon) } @@ -153,7 +160,8 @@ func Getfscreatecon() (string, error) { return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", system.Gettid())) } -func getcon() (string, error) { +// Return the SELinux label of the current process thread. +func Getcon() (string, error) { return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", system.Gettid())) } @@ -396,3 +404,36 @@ func CopyLevel(src, dest string) (string, error) { tcon["level"] = scon["level"] return tcon.Get(), nil } + +// Prevent users from relabing system files +func badPrefix(fpath string) error { + var badprefixes = []string{"/usr"} + + for _, prefix := range badprefixes { + if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) { + return fmt.Errorf("Relabeling content in %s is not allowed.", prefix) + } + } + return nil +} + +// Change the fpath file object to the SELinux label scon. +// If the fpath is a directory and recurse is true Chcon will walk the +// directory tree setting the label +func Chcon(fpath string, scon string, recurse bool) error { + if !SelinuxEnabled() { + return nil + } + if err := badPrefix(fpath); err != nil { + return err + } + callback := func(p string, info os.FileInfo, err error) error { + return Setfilecon(p, scon) + } + + if recurse { + return filepath.Walk(fpath, callback) + } + + return Setfilecon(fpath, scon) +} diff --git a/vendor/src/github.com/docker/libcontainer/state.go b/vendor/src/github.com/docker/libcontainer/state.go index a055bb0ffe..ee5d14d2ec 100644 --- a/vendor/src/github.com/docker/libcontainer/state.go +++ b/vendor/src/github.com/docker/libcontainer/state.go @@ -12,14 +12,33 @@ import ( type State struct { // InitPid is the init process id in the parent namespace InitPid int `json:"init_pid,omitempty"` + // InitStartTime is the init process start time InitStartTime string `json:"init_start_time,omitempty"` + // Network runtime state. NetworkState network.NetworkState `json:"network_state,omitempty"` } -// The name of the runtime state file -const stateFile = "state.json" +// The running state of the container. +type RunState int + +const ( + // The name of the runtime state file + stateFile = "state.json" + + // The container exists and is running. + Running RunState = iota + + // The container exists, it is in the process of being paused. + Pausing + + // The container exists, but all its processes are paused. + Paused + + // The container does not exist. + Destroyed +) // SaveState writes the container's runtime state to a state.json file // in the specified path diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go b/vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe.go similarity index 98% rename from vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go rename to vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe.go index dcb5d9749d..10a21a9efd 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go +++ b/vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe.go @@ -1,4 +1,4 @@ -package namespaces +package syncpipe import ( "encoding/json" diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go b/vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe_linux.go similarity index 95% rename from vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go rename to vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe_linux.go index ad61e75d29..bea4b52f9e 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go +++ b/vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe_linux.go @@ -1,4 +1,4 @@ -package namespaces +package syncpipe import ( "os" diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go b/vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe_test.go similarity index 98% rename from vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go rename to vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe_test.go index 69bd0abbfb..3f99a7d1fa 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go +++ b/vendor/src/github.com/docker/libcontainer/syncpipe/sync_pipe_test.go @@ -1,4 +1,4 @@ -package namespaces +package syncpipe import ( "fmt"