From b85f5791ad470c9c002014d98fb6676a89b4c8da Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 13 Apr 2014 14:20:04 +0000 Subject: [PATCH 01/25] Use apparmor_parser directly The current load script does alot of things. If it does not find the parser loaded on the system it will just exit 0 and not load the profile. We think it should fail loudly if it cannot load the profile and apparmor is enabled on the system. Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 5f4bc4f916f433a4ba258980a6c2fbdbd76d64f3 Component: engine --- .../pkg/libcontainer/apparmor/apparmor.go | 8 +++- .../engine/pkg/libcontainer/apparmor/setup.go | 48 ++++++------------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/components/engine/pkg/libcontainer/apparmor/apparmor.go b/components/engine/pkg/libcontainer/apparmor/apparmor.go index 5de241dd97..0987398124 100644 --- a/components/engine/pkg/libcontainer/apparmor/apparmor.go +++ b/components/engine/pkg/libcontainer/apparmor/apparmor.go @@ -8,12 +8,16 @@ package apparmor import "C" import ( "io/ioutil" + "os" "unsafe" ) func IsEnabled() bool { - buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") - return err == nil && len(buf) > 1 && buf[0] == 'Y' + if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil { + buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + return err == nil && len(buf) > 1 && buf[0] == 'Y' + } + return false } func ApplyProfile(pid int, name string) error { diff --git a/components/engine/pkg/libcontainer/apparmor/setup.go b/components/engine/pkg/libcontainer/apparmor/setup.go index 548e72f550..e32e8156ca 100644 --- a/components/engine/pkg/libcontainer/apparmor/setup.go +++ b/components/engine/pkg/libcontainer/apparmor/setup.go @@ -14,8 +14,6 @@ const ( ) const DefaultProfile = ` -# AppArmor profile from lxc for containers. - #include profile docker-default flags=(attach_disconnected,mediate_deleted) { #include @@ -24,43 +22,28 @@ profile docker-default flags=(attach_disconnected,mediate_deleted) { file, umount, - # ignore DENIED message on / remount - deny mount options=(ro, remount) -> /, - - # allow tmpfs mounts everywhere mount fstype=tmpfs, - - # allow mqueue mounts everywhere mount fstype=mqueue, - - # allow fuse mounts everywhere mount fstype=fuse.*, - - # allow bind mount of /lib/init/fstab for lxcguest - mount options=(rw, bind) /lib/init/fstab.lxc/ -> /lib/init/fstab/, - - # deny writes in /proc/sys/fs but allow binfmt_misc to be mounted mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, - deny @{PROC}/sys/fs/** wklx, - - # allow efivars to be mounted, writing to it will be blocked though mount fstype=efivarfs -> /sys/firmware/efi/efivars/, + mount fstype=fusectl -> /sys/fs/fuse/connections/, + mount fstype=securityfs -> /sys/kernel/security/, + mount fstype=debugfs -> /sys/kernel/debug/, + mount fstype=proc -> /proc/, + mount fstype=sysfs -> /sys/, - # block some other dangerous paths + deny @{PROC}/sys/fs/** wklx, deny @{PROC}/sysrq-trigger rwklx, deny @{PROC}/mem rwklx, deny @{PROC}/kmem rwklx, deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, deny @{PROC}/sys/kernel/*/** wklx, - # deny writes in /sys except for /sys/fs/cgroup, also allow - # fusectl, securityfs and debugfs to be mounted there (read-only) - mount fstype=fusectl -> /sys/fs/fuse/connections/, - mount fstype=securityfs -> /sys/kernel/security/, - mount fstype=debugfs -> /sys/kernel/debug/, + deny mount options=(ro, remount) -> /, deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, - mount fstype=proc -> /proc/, - mount fstype=sysfs -> /sys/, + deny mount fstype=devpts, + deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, deny /sys/fs/[^c]*/** wklx, @@ -68,12 +51,6 @@ profile docker-default flags=(attach_disconnected,mediate_deleted) { deny /sys/fs/cg[^r]*/** wklx, deny /sys/firmware/efi/efivars/** rwklx, deny /sys/kernel/security/** rwklx, - mount options=(move) /sys/fs/cgroup/cgmanager/ -> /sys/fs/cgroup/cgmanager.lower/, - - # the container may never be allowed to mount devpts. If it does, it - # will remount the host's devpts. We could allow it to do it with - # the newinstance option (but, right now, we don't). - deny mount fstype=devpts, } ` @@ -101,11 +78,13 @@ func InstallDefaultProfile(backupPath string) error { return err } defer f.Close() + src, err := os.Open(DefaultProfilePath) if err != nil { return err } defer src.Close() + if _, err := io.Copy(f, src); err != nil { return err } @@ -120,7 +99,10 @@ func InstallDefaultProfile(backupPath string) error { return err } - output, err := exec.Command("/lib/init/apparmor-profile-load", "docker").CombinedOutput() + // the current functionality of the load script is the exit 0 if the parser does not exist. + // we think we should fail loudly if you have apparmor enabled but not the parser to load + // the profile for use. + output, err := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker").CombinedOutput() if err != nil { return fmt.Errorf("Error loading docker profile: %s (%s)", err, output) } From ebb2ad0565cf3d7303374bfb33834de093c4f947 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 13 Apr 2014 23:33:25 +0000 Subject: [PATCH 02/25] Move apparmor to top level pkg Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 052cc5a6378ee4bbe1ef79e5632e2439d68ddbde Component: engine --- components/engine/pkg/{libcontainer => }/apparmor/apparmor.go | 0 .../engine/pkg/{libcontainer => }/apparmor/apparmor_disabled.go | 0 components/engine/pkg/{libcontainer => }/apparmor/setup.go | 0 components/engine/pkg/libcontainer/nsinit/init.go | 2 +- components/engine/runtime/execdriver/native/create.go | 2 +- components/engine/runtime/execdriver/native/driver.go | 2 +- .../runtime/execdriver/native/template/default_template.go | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) rename components/engine/pkg/{libcontainer => }/apparmor/apparmor.go (100%) rename components/engine/pkg/{libcontainer => }/apparmor/apparmor_disabled.go (100%) rename components/engine/pkg/{libcontainer => }/apparmor/setup.go (100%) diff --git a/components/engine/pkg/libcontainer/apparmor/apparmor.go b/components/engine/pkg/apparmor/apparmor.go similarity index 100% rename from components/engine/pkg/libcontainer/apparmor/apparmor.go rename to components/engine/pkg/apparmor/apparmor.go diff --git a/components/engine/pkg/libcontainer/apparmor/apparmor_disabled.go b/components/engine/pkg/apparmor/apparmor_disabled.go similarity index 100% rename from components/engine/pkg/libcontainer/apparmor/apparmor_disabled.go rename to components/engine/pkg/apparmor/apparmor_disabled.go diff --git a/components/engine/pkg/libcontainer/apparmor/setup.go b/components/engine/pkg/apparmor/setup.go similarity index 100% rename from components/engine/pkg/libcontainer/apparmor/setup.go rename to components/engine/pkg/apparmor/setup.go diff --git a/components/engine/pkg/libcontainer/nsinit/init.go b/components/engine/pkg/libcontainer/nsinit/init.go index b6c02eafd5..0e85c0e4be 100644 --- a/components/engine/pkg/libcontainer/nsinit/init.go +++ b/components/engine/pkg/libcontainer/nsinit/init.go @@ -8,9 +8,9 @@ import ( "runtime" "syscall" + "github.com/dotcloud/docker/pkg/apparmor" "github.com/dotcloud/docker/pkg/label" "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/libcontainer/apparmor" "github.com/dotcloud/docker/pkg/libcontainer/capabilities" "github.com/dotcloud/docker/pkg/libcontainer/network" "github.com/dotcloud/docker/pkg/libcontainer/utils" diff --git a/components/engine/runtime/execdriver/native/create.go b/components/engine/runtime/execdriver/native/create.go index 12546145f9..ac67839e4b 100644 --- a/components/engine/runtime/execdriver/native/create.go +++ b/components/engine/runtime/execdriver/native/create.go @@ -4,9 +4,9 @@ import ( "fmt" "os" + "github.com/dotcloud/docker/pkg/apparmor" "github.com/dotcloud/docker/pkg/label" "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/libcontainer/apparmor" "github.com/dotcloud/docker/runtime/execdriver" "github.com/dotcloud/docker/runtime/execdriver/native/configuration" "github.com/dotcloud/docker/runtime/execdriver/native/template" diff --git a/components/engine/runtime/execdriver/native/driver.go b/components/engine/runtime/execdriver/native/driver.go index d18865e508..c99cae31dd 100644 --- a/components/engine/runtime/execdriver/native/driver.go +++ b/components/engine/runtime/execdriver/native/driver.go @@ -3,9 +3,9 @@ package native import ( "encoding/json" "fmt" + "github.com/dotcloud/docker/pkg/apparmor" "github.com/dotcloud/docker/pkg/cgroups" "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/libcontainer/apparmor" "github.com/dotcloud/docker/pkg/libcontainer/nsinit" "github.com/dotcloud/docker/pkg/system" "github.com/dotcloud/docker/runtime/execdriver" diff --git a/components/engine/runtime/execdriver/native/template/default_template.go b/components/engine/runtime/execdriver/native/template/default_template.go index d3c433a317..c354637fcb 100644 --- a/components/engine/runtime/execdriver/native/template/default_template.go +++ b/components/engine/runtime/execdriver/native/template/default_template.go @@ -1,9 +1,9 @@ package template import ( + "github.com/dotcloud/docker/pkg/apparmor" "github.com/dotcloud/docker/pkg/cgroups" "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/libcontainer/apparmor" ) // New returns the docker default configuration for libcontainer From 4b3fd1c81f45e3883cb9f01da0ce52961c3bbf9c Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 13 Apr 2014 23:37:12 +0000 Subject: [PATCH 03/25] Ignore is not exist error Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 6c26a87901d12188dfd9986d9211f6077a286f9d Component: engine --- components/engine/pkg/apparmor/setup.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/engine/pkg/apparmor/setup.go b/components/engine/pkg/apparmor/setup.go index e32e8156ca..349476219b 100644 --- a/components/engine/pkg/apparmor/setup.go +++ b/components/engine/pkg/apparmor/setup.go @@ -99,11 +99,15 @@ func InstallDefaultProfile(backupPath string) error { return err } - // the current functionality of the load script is the exit 0 if the parser does not exist. - // we think we should fail loudly if you have apparmor enabled but not the parser to load - // the profile for use. output, err := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker").CombinedOutput() - if err != nil { + if err != nil && !os.IsNotExist(err) { + if e, ok := err.(*exec.Error); ok { + // keeping with the current profile load code, if the parser does not exist then + // just return + if e.Err == exec.ErrNotFound || os.IsNotExist(e.Err) { + return nil + } + } return fmt.Errorf("Error loading docker profile: %s (%s)", err, output) } return nil From d953b1e434ab00d19ef651e305c428b06be08b72 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 14 Apr 2014 05:22:45 +0000 Subject: [PATCH 04/25] Generate imports based on what is avaliable Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 3061a6a2ab0395c626f9acaa2e5d9c17152b0475 Component: engine --- components/engine/pkg/apparmor/gen.go | 92 +++++++++++++++++++++++++ components/engine/pkg/apparmor/setup.go | 61 ++++------------ 2 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 components/engine/pkg/apparmor/gen.go diff --git a/components/engine/pkg/apparmor/gen.go b/components/engine/pkg/apparmor/gen.go new file mode 100644 index 0000000000..bf9be2ae0b --- /dev/null +++ b/components/engine/pkg/apparmor/gen.go @@ -0,0 +1,92 @@ +package apparmor + +import ( + "io" + "os" + "text/template" +) + +type data struct { + Name string + Imports []string + InnerImports []string +} + +const baseTemplate = ` +{{range $value := .Imports}} +{{$value}} +{{end}} + +profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { +{{range $value := .InnerImports}} + {{$value}} +{{end}} + + network, + capability, + file, + umount, + + mount fstype=tmpfs, + mount fstype=mqueue, + mount fstype=fuse.*, + mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, + mount fstype=efivarfs -> /sys/firmware/efi/efivars/, + mount fstype=fusectl -> /sys/fs/fuse/connections/, + mount fstype=securityfs -> /sys/kernel/security/, + mount fstype=debugfs -> /sys/kernel/debug/, + mount fstype=proc -> /proc/, + mount fstype=sysfs -> /sys/, + + deny @{PROC}/sys/fs/** wklx, + deny @{PROC}/sysrq-trigger rwklx, + deny @{PROC}/mem rwklx, + deny @{PROC}/kmem rwklx, + deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, + deny @{PROC}/sys/kernel/*/** wklx, + + deny mount options=(ro, remount) -> /, + deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, + deny mount fstype=devpts, + + deny /sys/[^f]*/** wklx, + deny /sys/f[^s]*/** wklx, + deny /sys/fs/[^c]*/** wklx, + deny /sys/fs/c[^g]*/** wklx, + deny /sys/fs/cg[^r]*/** wklx, + deny /sys/firmware/efi/efivars/** rwklx, + deny /sys/kernel/security/** rwklx, +} +` + +func generateProfile(out io.Writer) error { + compiled, err := template.New("apparmor_profile").Parse(baseTemplate) + if err != nil { + return err + } + data := &data{ + Name: "docker-default", + } + if tuntablesExists() { + data.Imports = append(data.Imports, "#include ") + } + if abstrctionsEsists() { + data.InnerImports = append(data.InnerImports, "#include ") + } + if err := compiled.Execute(out, data); err != nil { + return err + } + return nil +} + +// check if the tunables/global exist +func tuntablesExists() bool { + _, err := os.Stat("/etc/apparmor.d/tunables/global") + return err == nil +} + +// check if abstractions/base exist +func abstrctionsEsists() bool { + _, err := os.Stat("/etc/apparmor.d/abstractions/base") + return err == nil +} diff --git a/components/engine/pkg/apparmor/setup.go b/components/engine/pkg/apparmor/setup.go index 349476219b..2401f63414 100644 --- a/components/engine/pkg/apparmor/setup.go +++ b/components/engine/pkg/apparmor/setup.go @@ -3,7 +3,6 @@ package apparmor import ( "fmt" "io" - "io/ioutil" "os" "os/exec" "path" @@ -13,47 +12,6 @@ const ( DefaultProfilePath = "/etc/apparmor.d/docker" ) -const DefaultProfile = ` -#include -profile docker-default flags=(attach_disconnected,mediate_deleted) { - #include - network, - capability, - file, - umount, - - mount fstype=tmpfs, - mount fstype=mqueue, - mount fstype=fuse.*, - mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, - mount fstype=efivarfs -> /sys/firmware/efi/efivars/, - mount fstype=fusectl -> /sys/fs/fuse/connections/, - mount fstype=securityfs -> /sys/kernel/security/, - mount fstype=debugfs -> /sys/kernel/debug/, - mount fstype=proc -> /proc/, - mount fstype=sysfs -> /sys/, - - deny @{PROC}/sys/fs/** wklx, - deny @{PROC}/sysrq-trigger rwklx, - deny @{PROC}/mem rwklx, - deny @{PROC}/kmem rwklx, - deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, - deny @{PROC}/sys/kernel/*/** wklx, - - deny mount options=(ro, remount) -> /, - deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, - deny mount fstype=devpts, - - deny /sys/[^f]*/** wklx, - deny /sys/f[^s]*/** wklx, - deny /sys/fs/[^c]*/** wklx, - deny /sys/fs/c[^g]*/** wklx, - deny /sys/fs/cg[^r]*/** wklx, - deny /sys/firmware/efi/efivars/** rwklx, - deny /sys/kernel/security/** rwklx, -} -` - func InstallDefaultProfile(backupPath string) error { if !IsEnabled() { return nil @@ -95,15 +53,26 @@ func InstallDefaultProfile(backupPath string) error { return err } - if err := ioutil.WriteFile(DefaultProfilePath, []byte(DefaultProfile), 0644); err != nil { + f, err := os.OpenFile(DefaultProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { return err } + if err := generateProfile(f); err != nil { + f.Close() + return err + } + f.Close() - output, err := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker").CombinedOutput() + cmd := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker") + // to use the parser directly we have to make sure we are in the correct + // dir with the profile + cmd.Dir = "/etc/apparmor.d" + + output, err := cmd.CombinedOutput() if err != nil && !os.IsNotExist(err) { if e, ok := err.(*exec.Error); ok { - // keeping with the current profile load code, if the parser does not exist then - // just return + // keeping with the current profile load code, if the parser does not + // exist then just return if e.Err == exec.ErrNotFound || os.IsNotExist(e.Err) { return nil } From dbcd3000c90928085cf5d0782639e7e28e402f97 Mon Sep 17 00:00:00 2001 From: Kato Kazuyoshi Date: Thu, 17 Apr 2014 00:16:07 +0900 Subject: [PATCH 05/25] This permission should be interpreted as octal, not decimal Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi (github: kzys) Upstream-commit: e1e512e2da5f642ded2eba6baa851f52bae0b05c Component: engine --- components/engine/archive/diff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/engine/archive/diff.go b/components/engine/archive/diff.go index e20e4b1f02..87e8ac7dc4 100644 --- a/components/engine/archive/diff.go +++ b/components/engine/archive/diff.go @@ -68,7 +68,7 @@ func ApplyLayer(dest string, layer ArchiveReader) error { parent := filepath.Dir(hdr.Name) parentPath := filepath.Join(dest, parent) if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) { - err = os.MkdirAll(parentPath, 600) + err = os.MkdirAll(parentPath, 0600) if err != nil { return err } From da097b4451c38aacfca9b802ae31e4f164e4829c Mon Sep 17 00:00:00 2001 From: Kato Kazuyoshi Date: Thu, 17 Apr 2014 00:41:19 +0900 Subject: [PATCH 06/25] SQLite is also available in FreeBSD Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi (github: kzys) Upstream-commit: 92ea101bc4a498e952ede00bff53d0123f22f41c Component: engine --- components/engine/hack/make.sh | 8 ++++++++ .../engine/pkg/graphdb/{conn_linux.go => conn_sqlite3.go} | 2 +- components/engine/pkg/graphdb/conn_unsupported.go | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) rename components/engine/pkg/graphdb/{conn_linux.go => conn_sqlite3.go} (92%) diff --git a/components/engine/hack/make.sh b/components/engine/hack/make.sh index f3264c9ce3..46df398c57 100755 --- a/components/engine/hack/make.sh +++ b/components/engine/hack/make.sh @@ -117,6 +117,14 @@ if [ "$(uname -s)" = 'FreeBSD' ]; then LDFLAGS="$LDFLAGS -extld clang" fi +# If sqlite3.h doesn't exist under /usr/include, +# check /usr/local/include also just in case +# (e.g. FreeBSD Ports installs it under the directory) +if [ ! -e /usr/include/sqlite3.h ] && [ -e /usr/local/include/sqlite3.h ]; then + export CGO_CFLAGS='-I/usr/local/include' + export CGO_LDFLAGS='-L/usr/local/lib' +fi + HAVE_GO_TEST_COVER= if \ go help testflag | grep -- -cover > /dev/null \ diff --git a/components/engine/pkg/graphdb/conn_linux.go b/components/engine/pkg/graphdb/conn_sqlite3.go similarity index 92% rename from components/engine/pkg/graphdb/conn_linux.go rename to components/engine/pkg/graphdb/conn_sqlite3.go index 7a1ab8c92f..5b5f8e6bfc 100644 --- a/components/engine/pkg/graphdb/conn_linux.go +++ b/components/engine/pkg/graphdb/conn_sqlite3.go @@ -1,4 +1,4 @@ -// +build amd64 +// +build linux,amd64 freebsd,cgo package graphdb diff --git a/components/engine/pkg/graphdb/conn_unsupported.go b/components/engine/pkg/graphdb/conn_unsupported.go index c2d602569f..0a48634336 100644 --- a/components/engine/pkg/graphdb/conn_unsupported.go +++ b/components/engine/pkg/graphdb/conn_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux !amd64 +// +build !linux,!freebsd linux,!amd64 freebsd,!cgo package graphdb From 0b62a2c5be7992d56fdb62e39bc10fbff2253ec8 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 18 Apr 2014 21:14:58 -0700 Subject: [PATCH 07/25] Refactor cgroups file locations Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 42fb2973c690fe4e4f65da235ce4dfa4c388e8a3 Component: engine --- components/engine/pkg/cgroups/cgroups.go | 70 +----------------- components/engine/pkg/cgroups/utils.go | 73 +++++++++++++++++++ .../engine/pkg/libcontainer/nsinit/exec.go | 2 +- 3 files changed, 75 insertions(+), 70 deletions(-) create mode 100644 components/engine/pkg/cgroups/utils.go diff --git a/components/engine/pkg/cgroups/cgroups.go b/components/engine/pkg/cgroups/cgroups.go index e5e8f82db6..343e70f215 100644 --- a/components/engine/pkg/cgroups/cgroups.go +++ b/components/engine/pkg/cgroups/cgroups.go @@ -1,14 +1,7 @@ package cgroups import ( - "bufio" "errors" - "github.com/dotcloud/docker/pkg/mount" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" ) var ( @@ -32,68 +25,7 @@ type ActiveCgroup interface { Cleanup() error } -// https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt -func FindCgroupMountpoint(subsystem string) (string, error) { - mounts, err := mount.GetMounts() - if err != nil { - return "", err - } - - for _, mount := range mounts { - if mount.Fstype == "cgroup" { - for _, opt := range strings.Split(mount.VfsOpts, ",") { - if opt == subsystem { - return mount.Mountpoint, nil - } - } - } - } - return "", ErrNotFound -} - -// Returns the relative path to the cgroup docker is running in. -func GetThisCgroupDir(subsystem string) (string, error) { - f, err := os.Open("/proc/self/cgroup") - if err != nil { - return "", err - } - defer f.Close() - - return parseCgroupFile(subsystem, f) -} - -func GetInitCgroupDir(subsystem string) (string, error) { - f, err := os.Open("/proc/1/cgroup") - if err != nil { - return "", err - } - defer f.Close() - - return parseCgroupFile(subsystem, f) -} - -func parseCgroupFile(subsystem string, r io.Reader) (string, error) { - s := bufio.NewScanner(r) - for s.Scan() { - if err := s.Err(); err != nil { - return "", err - } - text := s.Text() - parts := strings.Split(text, ":") - for _, subs := range strings.Split(parts[1], ",") { - if subs == subsystem { - return parts[2], nil - } - } - } - return "", ErrNotFound -} - -func writeFile(dir, file, data string) error { - return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) -} - -func (c *Cgroup) Apply(pid int) (ActiveCgroup, error) { +func Apply(c *Cgroup, pid int) (ActiveCgroup, error) { // We have two implementation of cgroups support, one is based on // systemd and the dbus api, and one is based on raw cgroup fs operations // following the pre-single-writer model docs at: diff --git a/components/engine/pkg/cgroups/utils.go b/components/engine/pkg/cgroups/utils.go new file mode 100644 index 0000000000..82d5a955a3 --- /dev/null +++ b/components/engine/pkg/cgroups/utils.go @@ -0,0 +1,73 @@ +package cgroups + +import ( + "bufio" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/dotcloud/docker/pkg/mount" +) + +// https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt +func FindCgroupMountpoint(subsystem string) (string, error) { + mounts, err := mount.GetMounts() + if err != nil { + return "", err + } + + for _, mount := range mounts { + if mount.Fstype == "cgroup" { + for _, opt := range strings.Split(mount.VfsOpts, ",") { + if opt == subsystem { + return mount.Mountpoint, nil + } + } + } + } + return "", ErrNotFound +} + +// Returns the relative path to the cgroup docker is running in. +func GetThisCgroupDir(subsystem string) (string, error) { + f, err := os.Open("/proc/self/cgroup") + if err != nil { + return "", err + } + defer f.Close() + + return parseCgroupFile(subsystem, f) +} + +func GetInitCgroupDir(subsystem string) (string, error) { + f, err := os.Open("/proc/1/cgroup") + if err != nil { + return "", err + } + defer f.Close() + + return parseCgroupFile(subsystem, f) +} + +func parseCgroupFile(subsystem string, r io.Reader) (string, error) { + s := bufio.NewScanner(r) + for s.Scan() { + if err := s.Err(); err != nil { + return "", err + } + text := s.Text() + parts := strings.Split(text, ":") + for _, subs := range strings.Split(parts[1], ",") { + if subs == subsystem { + return parts[2], nil + } + } + } + return "", ErrNotFound +} + +func writeFile(dir, file, data string) error { + return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) +} diff --git a/components/engine/pkg/libcontainer/nsinit/exec.go b/components/engine/pkg/libcontainer/nsinit/exec.go index c07c45de3c..4e2fcefd47 100644 --- a/components/engine/pkg/libcontainer/nsinit/exec.go +++ b/components/engine/pkg/libcontainer/nsinit/exec.go @@ -99,7 +99,7 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, args [ func (ns *linuxNs) SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveCgroup, error) { if container.Cgroups != nil { - return container.Cgroups.Apply(nspid) + return cgroups.Apply(container.Cgroups, nspid) } return nil, nil } From 91235494a69a267cc7cca47b3a1234841bc1ee70 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 18 Apr 2014 21:30:08 -0700 Subject: [PATCH 08/25] Move systemd code into pkg Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: ec43ec50b44cff3f043c78cad97466c68e2ba8cd Component: engine --- .../engine/pkg/cgroups/apply_nosystemd.go | 15 ------- components/engine/pkg/cgroups/cgroups.go | 13 ------ .../pkg/cgroups/systemd/apply_nosystemd.go | 16 +++++++ .../cgroups/{ => systemd}/apply_systemd.go | 45 ++++++++++--------- .../engine/pkg/libcontainer/nsinit/exec.go | 7 ++- 5 files changed, 46 insertions(+), 50 deletions(-) delete mode 100644 components/engine/pkg/cgroups/apply_nosystemd.go create mode 100644 components/engine/pkg/cgroups/systemd/apply_nosystemd.go rename components/engine/pkg/cgroups/{ => systemd}/apply_systemd.go (86%) diff --git a/components/engine/pkg/cgroups/apply_nosystemd.go b/components/engine/pkg/cgroups/apply_nosystemd.go deleted file mode 100644 index f94d475907..0000000000 --- a/components/engine/pkg/cgroups/apply_nosystemd.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !linux - -package cgroups - -import ( - "fmt" -) - -func useSystemd() bool { - return false -} - -func systemdApply(c *Cgroup, pid int) (ActiveCgroup, error) { - return nil, fmt.Errorf("Systemd not supported") -} diff --git a/components/engine/pkg/cgroups/cgroups.go b/components/engine/pkg/cgroups/cgroups.go index 343e70f215..3aac971340 100644 --- a/components/engine/pkg/cgroups/cgroups.go +++ b/components/engine/pkg/cgroups/cgroups.go @@ -24,16 +24,3 @@ type Cgroup struct { type ActiveCgroup interface { Cleanup() error } - -func Apply(c *Cgroup, pid int) (ActiveCgroup, error) { - // We have two implementation of cgroups support, one is based on - // systemd and the dbus api, and one is based on raw cgroup fs operations - // following the pre-single-writer model docs at: - // http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups/ - - if useSystemd() { - return systemdApply(c, pid) - } else { - return rawApply(c, pid) - } -} diff --git a/components/engine/pkg/cgroups/systemd/apply_nosystemd.go b/components/engine/pkg/cgroups/systemd/apply_nosystemd.go new file mode 100644 index 0000000000..226aa59f9d --- /dev/null +++ b/components/engine/pkg/cgroups/systemd/apply_nosystemd.go @@ -0,0 +1,16 @@ +// +build !linux + +package systemd + +import ( + "fmt" + "github.com/dotcloud/docker/pkg/cgroups" +) + +func UseSystemd() bool { + return false +} + +func systemdApply(c *Cgroup, pid int) (cgroups.ActiveCgroup, error) { + return nil, fmt.Errorf("Systemd not supported") +} diff --git a/components/engine/pkg/cgroups/apply_systemd.go b/components/engine/pkg/cgroups/systemd/apply_systemd.go similarity index 86% rename from components/engine/pkg/cgroups/apply_systemd.go rename to components/engine/pkg/cgroups/systemd/apply_systemd.go index a9b3a8d301..7c26080d6e 100644 --- a/components/engine/pkg/cgroups/apply_systemd.go +++ b/components/engine/pkg/cgroups/systemd/apply_systemd.go @@ -1,27 +1,35 @@ // +build linux -package cgroups +package systemd import ( "fmt" - systemd1 "github.com/coreos/go-systemd/dbus" - "github.com/dotcloud/docker/pkg/systemd" - "github.com/godbus/dbus" + "io/ioutil" "path/filepath" "strings" "sync" + + systemd1 "github.com/coreos/go-systemd/dbus" + "github.com/dotcloud/docker/pkg/cgroups" + "github.com/dotcloud/docker/pkg/systemd" + "github.com/godbus/dbus" ) type systemdCgroup struct { } +type DeviceAllow struct { + Node string + Permissions string +} + var ( connLock sync.Mutex theConn *systemd1.Conn hasStartTransientUnit bool ) -func useSystemd() bool { +func UseSystemd() bool { if !systemd.SdBooted() { return false } @@ -48,15 +56,9 @@ func useSystemd() bool { } } } - return hasStartTransientUnit } -type DeviceAllow struct { - Node string - Permissions string -} - func getIfaceForUnit(unitName string) string { if strings.HasSuffix(unitName, ".scope") { return "Scope" @@ -67,11 +69,12 @@ func getIfaceForUnit(unitName string) string { return "Unit" } -func systemdApply(c *Cgroup, pid int) (ActiveCgroup, error) { - unitName := c.Parent + "-" + c.Name + ".scope" - slice := "system.slice" - - var properties []systemd1.Property +func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { + var ( + unitName = c.Parent + "-" + c.Name + ".scope" + slice = "system.slice" + properties []systemd1.Property + ) for _, v := range c.UnitProperties { switch v[0] { @@ -85,7 +88,8 @@ func systemdApply(c *Cgroup, pid int) (ActiveCgroup, error) { properties = append(properties, systemd1.Property{"Slice", dbus.MakeVariant(slice)}, systemd1.Property{"Description", dbus.MakeVariant("docker container " + c.Name)}, - systemd1.Property{"PIDs", dbus.MakeVariant([]uint32{uint32(pid)})}) + systemd1.Property{"PIDs", dbus.MakeVariant([]uint32{uint32(pid)})}, + ) if !c.DeviceAccess { properties = append(properties, @@ -138,7 +142,7 @@ func systemdApply(c *Cgroup, pid int) (ActiveCgroup, error) { cgroup := props["ControlGroup"].(string) if !c.DeviceAccess { - mountpoint, err := FindCgroupMountpoint("devices") + mountpoint, err := cgroups.FindCgroupMountpoint("devices") if err != nil { return nil, err } @@ -146,15 +150,14 @@ func systemdApply(c *Cgroup, pid int) (ActiveCgroup, error) { path := filepath.Join(mountpoint, cgroup) // /dev/pts/* - if err := writeFile(path, "devices.allow", "c 136:* rwm"); err != nil { + if err := ioutil.WriteFile(filepath.Join(path, "devices.allow"), []byte("c 136:* rwm"), 0700); err != nil { return nil, err } // tuntap - if err := writeFile(path, "devices.allow", "c 10:200 rwm"); err != nil { + if err := ioutil.WriteFile(filepath.Join(path, "devices.allow"), []byte("c 10:200 rwm"), 0700); err != nil { return nil, err } } - return &systemdCgroup{}, nil } diff --git a/components/engine/pkg/libcontainer/nsinit/exec.go b/components/engine/pkg/libcontainer/nsinit/exec.go index 4e2fcefd47..7a315d6f80 100644 --- a/components/engine/pkg/libcontainer/nsinit/exec.go +++ b/components/engine/pkg/libcontainer/nsinit/exec.go @@ -8,6 +8,7 @@ import ( "syscall" "github.com/dotcloud/docker/pkg/cgroups" + "github.com/dotcloud/docker/pkg/cgroups/systemd" "github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer/network" "github.com/dotcloud/docker/pkg/system" @@ -99,7 +100,11 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, args [ func (ns *linuxNs) SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveCgroup, error) { if container.Cgroups != nil { - return cgroups.Apply(container.Cgroups, nspid) + c := container.Cgroups + if systemd.UseSystemd() { + return systemd.Apply(c, nspid) + } + return rawApply(c, nspid) } return nil, nil } From fec63c3950110726746a66a6789390f6462b0e42 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 18 Apr 2014 21:34:26 -0700 Subject: [PATCH 09/25] Move raw cgroups into fs package (filesystem) Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 06db0604e5e5438dc14e13a069ebddcab7bb4bc6 Component: engine --- .../engine/pkg/cgroups/{ => fs}/apply_raw.go | 41 +++++++++++-------- components/engine/pkg/cgroups/utils.go | 6 --- .../engine/pkg/libcontainer/nsinit/exec.go | 3 +- 3 files changed, 26 insertions(+), 24 deletions(-) rename components/engine/pkg/cgroups/{ => fs}/apply_raw.go (78%) diff --git a/components/engine/pkg/cgroups/apply_raw.go b/components/engine/pkg/cgroups/fs/apply_raw.go similarity index 78% rename from components/engine/pkg/cgroups/apply_raw.go rename to components/engine/pkg/cgroups/fs/apply_raw.go index 471d3fcf53..d8267bf4fa 100644 --- a/components/engine/pkg/cgroups/apply_raw.go +++ b/components/engine/pkg/cgroups/fs/apply_raw.go @@ -1,10 +1,13 @@ -package cgroups +package fs import ( "fmt" + "io/ioutil" "os" "path/filepath" "strconv" + + "github.com/dotcloud/docker/pkg/cgroups" ) type rawCgroup struct { @@ -12,7 +15,7 @@ type rawCgroup struct { cgroup string } -func rawApply(c *Cgroup, pid int) (ActiveCgroup, error) { +func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { // We have two implementation of cgroups support, one is based on // systemd and the dbus api, and one is based on raw cgroup fs operations // following the pre-single-writer model docs at: @@ -20,7 +23,7 @@ func rawApply(c *Cgroup, pid int) (ActiveCgroup, error) { // // we can pick any subsystem to find the root - cgroupRoot, err := FindCgroupMountpoint("cpu") + cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { return nil, err } @@ -39,7 +42,7 @@ func rawApply(c *Cgroup, pid int) (ActiveCgroup, error) { root: cgroupRoot, cgroup: cgroup, } - for _, g := range []func(*Cgroup, int) error{ + for _, g := range []func(*cgroups.Cgroup, int) error{ raw.setupDevices, raw.setupMemory, raw.setupCpu, @@ -58,7 +61,7 @@ func rawApply(c *Cgroup, pid int) (ActiveCgroup, error) { } func (raw *rawCgroup) path(subsystem string) (string, error) { - initPath, err := GetInitCgroupDir(subsystem) + initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err } @@ -79,7 +82,7 @@ func (raw *rawCgroup) join(subsystem string, pid int) (string, error) { return path, nil } -func (raw *rawCgroup) setupDevices(c *Cgroup, pid int) (err error) { +func (raw *rawCgroup) setupDevices(c *cgroups.Cgroup, pid int) (err error) { dir, err := raw.join("devices", pid) if err != nil { return err @@ -133,7 +136,7 @@ func (raw *rawCgroup) setupDevices(c *Cgroup, pid int) (err error) { return nil } -func (raw *rawCgroup) setupMemory(c *Cgroup, pid int) (err error) { +func (raw *rawCgroup) setupMemory(c *cgroups.Cgroup, pid int) (err error) { dir, err := raw.join("memory", pid) // only return an error for memory if it was not specified if err != nil && (c.Memory != 0 || c.MemorySwap != 0) { @@ -165,7 +168,7 @@ func (raw *rawCgroup) setupMemory(c *Cgroup, pid int) (err error) { return nil } -func (raw *rawCgroup) setupCpu(c *Cgroup, pid int) (err error) { +func (raw *rawCgroup) setupCpu(c *cgroups.Cgroup, pid int) (err error) { // We always want to join the cpu group, to allow fair cpu scheduling // on a container basis dir, err := raw.join("cpu", pid) @@ -180,7 +183,7 @@ func (raw *rawCgroup) setupCpu(c *Cgroup, pid int) (err error) { return nil } -func (raw *rawCgroup) setupCpuset(c *Cgroup, pid int) (err error) { +func (raw *rawCgroup) setupCpuset(c *cgroups.Cgroup, pid int) (err error) { // we don't want to join this cgroup unless it is specified if c.CpusetCpus != "" { dir, err := raw.join("cpuset", pid) @@ -200,33 +203,33 @@ func (raw *rawCgroup) setupCpuset(c *Cgroup, pid int) (err error) { return nil } -func (raw *rawCgroup) setupCpuacct(c *Cgroup, pid int) error { +func (raw *rawCgroup) setupCpuacct(c *cgroups.Cgroup, pid int) error { // we just want to join this group even though we don't set anything - if _, err := raw.join("cpuacct", pid); err != nil && err != ErrNotFound { + if _, err := raw.join("cpuacct", pid); err != nil && err != cgroups.ErrNotFound { return err } return nil } -func (raw *rawCgroup) setupBlkio(c *Cgroup, pid int) error { +func (raw *rawCgroup) setupBlkio(c *cgroups.Cgroup, pid int) error { // we just want to join this group even though we don't set anything - if _, err := raw.join("blkio", pid); err != nil && err != ErrNotFound { + if _, err := raw.join("blkio", pid); err != nil && err != cgroups.ErrNotFound { return err } return nil } -func (raw *rawCgroup) setupPerfevent(c *Cgroup, pid int) error { +func (raw *rawCgroup) setupPerfevent(c *cgroups.Cgroup, pid int) error { // we just want to join this group even though we don't set anything - if _, err := raw.join("perf_event", pid); err != nil && err != ErrNotFound { + if _, err := raw.join("perf_event", pid); err != nil && err != cgroups.ErrNotFound { return err } return nil } -func (raw *rawCgroup) setupFreezer(c *Cgroup, pid int) error { +func (raw *rawCgroup) setupFreezer(c *cgroups.Cgroup, pid int) error { // we just want to join this group even though we don't set anything - if _, err := raw.join("freezer", pid); err != nil && err != ErrNotFound { + if _, err := raw.join("freezer", pid); err != nil && err != cgroups.ErrNotFound { return err } return nil @@ -254,3 +257,7 @@ func (raw *rawCgroup) Cleanup() error { } return nil } + +func writeFile(dir, file, data string) error { + return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) +} diff --git a/components/engine/pkg/cgroups/utils.go b/components/engine/pkg/cgroups/utils.go index 82d5a955a3..02a7f357f6 100644 --- a/components/engine/pkg/cgroups/utils.go +++ b/components/engine/pkg/cgroups/utils.go @@ -3,9 +3,7 @@ package cgroups import ( "bufio" "io" - "io/ioutil" "os" - "path/filepath" "strings" "github.com/dotcloud/docker/pkg/mount" @@ -67,7 +65,3 @@ func parseCgroupFile(subsystem string, r io.Reader) (string, error) { } return "", ErrNotFound } - -func writeFile(dir, file, data string) error { - return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) -} diff --git a/components/engine/pkg/libcontainer/nsinit/exec.go b/components/engine/pkg/libcontainer/nsinit/exec.go index 7a315d6f80..e76e060d1c 100644 --- a/components/engine/pkg/libcontainer/nsinit/exec.go +++ b/components/engine/pkg/libcontainer/nsinit/exec.go @@ -8,6 +8,7 @@ import ( "syscall" "github.com/dotcloud/docker/pkg/cgroups" + "github.com/dotcloud/docker/pkg/cgroups/fs" "github.com/dotcloud/docker/pkg/cgroups/systemd" "github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer/network" @@ -104,7 +105,7 @@ func (ns *linuxNs) SetupCgroups(container *libcontainer.Container, nspid int) (c if systemd.UseSystemd() { return systemd.Apply(c, nspid) } - return rawApply(c, nspid) + return fs.Apply(c, nspid) } return nil, nil } From 39b03cf53c37ccff96dd3f26368082599539df31 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 18 Apr 2014 21:55:06 -0700 Subject: [PATCH 10/25] Break down groups into subsystems Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: e92f2fd3950644a6e5eb38259cee9036648090cb Component: engine --- components/engine/pkg/cgroups/fs/apply_raw.go | 202 +++--------------- components/engine/pkg/cgroups/fs/blkio.go | 16 ++ components/engine/pkg/cgroups/fs/cpu.go | 23 ++ components/engine/pkg/cgroups/fs/cpuacct.go | 16 ++ components/engine/pkg/cgroups/fs/cpuset.go | 28 +++ components/engine/pkg/cgroups/fs/devices.go | 61 ++++++ components/engine/pkg/cgroups/fs/freezer.go | 16 ++ components/engine/pkg/cgroups/fs/memory.go | 41 ++++ .../engine/pkg/cgroups/fs/perf_event.go | 16 ++ 9 files changed, 247 insertions(+), 172 deletions(-) create mode 100644 components/engine/pkg/cgroups/fs/blkio.go create mode 100644 components/engine/pkg/cgroups/fs/cpu.go create mode 100644 components/engine/pkg/cgroups/fs/cpuacct.go create mode 100644 components/engine/pkg/cgroups/fs/cpuset.go create mode 100644 components/engine/pkg/cgroups/fs/devices.go create mode 100644 components/engine/pkg/cgroups/fs/freezer.go create mode 100644 components/engine/pkg/cgroups/fs/memory.go create mode 100644 components/engine/pkg/cgroups/fs/perf_event.go diff --git a/components/engine/pkg/cgroups/fs/apply_raw.go b/components/engine/pkg/cgroups/fs/apply_raw.go index d8267bf4fa..4f1b379726 100644 --- a/components/engine/pkg/cgroups/fs/apply_raw.go +++ b/components/engine/pkg/cgroups/fs/apply_raw.go @@ -10,9 +10,28 @@ import ( "github.com/dotcloud/docker/pkg/cgroups" ) -type rawCgroup struct { +var ( + subsystems = []subsystem{ + &devicesGroup{}, + &memoryGroup{}, + &cpuGroup{}, + &cpusetGroup{}, + &cpuacctGroup{}, + &blkioGroup{}, + &perfEventGroup{}, + &freezerGroup{}, + } +) + +type subsystem interface { + Set(*data) error +} + +type data struct { root string cgroup string + c *cgroups.Cgroup + pid int } func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { @@ -38,29 +57,21 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { cgroup = filepath.Join(c.Parent, cgroup) } - raw := &rawCgroup{ + d := &data{ root: cgroupRoot, cgroup: cgroup, + c: c, + pid: pid, } - for _, g := range []func(*cgroups.Cgroup, int) error{ - raw.setupDevices, - raw.setupMemory, - raw.setupCpu, - raw.setupCpuset, - raw.setupCpuacct, - raw.setupBlkio, - raw.setupPerfevent, - raw.setupFreezer, - } { - if err := g(c, pid); err != nil { + for _, sys := range subsystems { + if err := sys.Set(d); err != nil { return nil, err } } - - return raw, nil + return d, nil } -func (raw *rawCgroup) path(subsystem string) (string, error) { +func (raw *data) path(subsystem string) (string, error) { initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err @@ -68,7 +79,7 @@ func (raw *rawCgroup) path(subsystem string) (string, error) { return filepath.Join(raw.root, subsystem, initPath, raw.cgroup), nil } -func (raw *rawCgroup) join(subsystem string, pid int) (string, error) { +func (raw *data) join(subsystem string) (string, error) { path, err := raw.path(subsystem) if err != nil { return "", err @@ -76,166 +87,13 @@ func (raw *rawCgroup) join(subsystem string, pid int) (string, error) { if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { return "", err } - if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil { + if err := writeFile(path, "cgroup.procs", strconv.Itoa(raw.pid)); err != nil { return "", err } return path, nil } -func (raw *rawCgroup) setupDevices(c *cgroups.Cgroup, pid int) (err error) { - dir, err := raw.join("devices", pid) - if err != nil { - return err - } - defer func() { - if err != nil { - os.RemoveAll(dir) - } - }() - - if !c.DeviceAccess { - - if err := writeFile(dir, "devices.deny", "a"); err != nil { - return err - } - - allow := []string{ - // allow mknod for any device - "c *:* m", - "b *:* m", - - // /dev/null, zero, full - "c 1:3 rwm", - "c 1:5 rwm", - "c 1:7 rwm", - - // consoles - "c 5:1 rwm", - "c 5:0 rwm", - "c 4:0 rwm", - "c 4:1 rwm", - - // /dev/urandom,/dev/random - "c 1:9 rwm", - "c 1:8 rwm", - - // /dev/pts/ - pts namespaces are "coming soon" - "c 136:* rwm", - "c 5:2 rwm", - - // tuntap - "c 10:200 rwm", - } - - for _, val := range allow { - if err := writeFile(dir, "devices.allow", val); err != nil { - return err - } - } - } - return nil -} - -func (raw *rawCgroup) setupMemory(c *cgroups.Cgroup, pid int) (err error) { - dir, err := raw.join("memory", pid) - // only return an error for memory if it was not specified - if err != nil && (c.Memory != 0 || c.MemorySwap != 0) { - return err - } - defer func() { - if err != nil { - os.RemoveAll(dir) - } - }() - - if c.Memory != 0 || c.MemorySwap != 0 { - if c.Memory != 0 { - if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(c.Memory, 10)); err != nil { - return err - } - if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(c.Memory, 10)); err != nil { - return err - } - } - // By default, MemorySwap is set to twice the size of RAM. - // If you want to omit MemorySwap, set it to `-1'. - if c.MemorySwap != -1 { - if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(c.Memory*2, 10)); err != nil { - return err - } - } - } - return nil -} - -func (raw *rawCgroup) setupCpu(c *cgroups.Cgroup, pid int) (err error) { - // We always want to join the cpu group, to allow fair cpu scheduling - // on a container basis - dir, err := raw.join("cpu", pid) - if err != nil { - return err - } - if c.CpuShares != 0 { - if err := writeFile(dir, "cpu.shares", strconv.FormatInt(c.CpuShares, 10)); err != nil { - return err - } - } - return nil -} - -func (raw *rawCgroup) setupCpuset(c *cgroups.Cgroup, pid int) (err error) { - // we don't want to join this cgroup unless it is specified - if c.CpusetCpus != "" { - dir, err := raw.join("cpuset", pid) - if err != nil && c.CpusetCpus != "" { - return err - } - defer func() { - if err != nil { - os.RemoveAll(dir) - } - }() - - if err := writeFile(dir, "cpuset.cpus", c.CpusetCpus); err != nil { - return err - } - } - return nil -} - -func (raw *rawCgroup) setupCpuacct(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("cpuacct", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) setupBlkio(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("blkio", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) setupPerfevent(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("perf_event", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) setupFreezer(c *cgroups.Cgroup, pid int) error { - // we just want to join this group even though we don't set anything - if _, err := raw.join("freezer", pid); err != nil && err != cgroups.ErrNotFound { - return err - } - return nil -} - -func (raw *rawCgroup) Cleanup() error { +func (raw *data) Cleanup() error { get := func(subsystem string) string { path, _ := raw.path(subsystem) return path diff --git a/components/engine/pkg/cgroups/fs/blkio.go b/components/engine/pkg/cgroups/fs/blkio.go new file mode 100644 index 0000000000..f0096f8767 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/blkio.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type blkioGroup struct { +} + +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 + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/cpu.go b/components/engine/pkg/cgroups/fs/cpu.go new file mode 100644 index 0000000000..33879bad14 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/cpu.go @@ -0,0 +1,23 @@ +package fs + +import ( + "strconv" +) + +type cpuGroup struct { +} + +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") + if err != nil { + return err + } + if d.c.CpuShares != 0 { + if err := writeFile(dir, "cpu.shares", strconv.FormatInt(d.c.CpuShares, 10)); err != nil { + return err + } + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go new file mode 100644 index 0000000000..603b100571 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type cpuacctGroup struct { +} + +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 + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/cpuset.go b/components/engine/pkg/cgroups/fs/cpuset.go new file mode 100644 index 0000000000..5108365ebd --- /dev/null +++ b/components/engine/pkg/cgroups/fs/cpuset.go @@ -0,0 +1,28 @@ +package fs + +import ( + "os" +) + +type cpusetGroup struct { +} + +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.join("cpuset") + if err != nil && d.c.CpusetCpus != "" { + return err + } + defer func() { + if err != nil { + os.RemoveAll(dir) + } + }() + + if err := writeFile(dir, "cpuset.cpus", d.c.CpusetCpus); err != nil { + return err + } + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/devices.go b/components/engine/pkg/cgroups/fs/devices.go new file mode 100644 index 0000000000..769df39283 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/devices.go @@ -0,0 +1,61 @@ +package fs + +import ( + "os" +) + +type devicesGroup struct { +} + +func (s *devicesGroup) Set(d *data) error { + dir, err := d.join("devices") + if err != nil { + return err + } + defer func() { + if err != nil { + os.RemoveAll(dir) + } + }() + + if !d.c.DeviceAccess { + if err := writeFile(dir, "devices.deny", "a"); err != nil { + return err + } + + allow := []string{ + // allow mknod for any device + "c *:* m", + "b *:* m", + + // /dev/null, zero, full + "c 1:3 rwm", + "c 1:5 rwm", + "c 1:7 rwm", + + // consoles + "c 5:1 rwm", + "c 5:0 rwm", + "c 4:0 rwm", + "c 4:1 rwm", + + // /dev/urandom,/dev/random + "c 1:9 rwm", + "c 1:8 rwm", + + // /dev/pts/ - pts namespaces are "coming soon" + "c 136:* rwm", + "c 5:2 rwm", + + // tuntap + "c 10:200 rwm", + } + + for _, val := range allow { + if err := writeFile(dir, "devices.allow", val); err != nil { + return err + } + } + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/freezer.go b/components/engine/pkg/cgroups/fs/freezer.go new file mode 100644 index 0000000000..51db689b0a --- /dev/null +++ b/components/engine/pkg/cgroups/fs/freezer.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type freezerGroup struct { +} + +func (s *freezerGroup) Set(d *data) error { + // we just want to join this group even though we don't set anything + if _, err := d.join("freezer"); err != nil && err != cgroups.ErrNotFound { + return err + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/memory.go b/components/engine/pkg/cgroups/fs/memory.go new file mode 100644 index 0000000000..cf33d66117 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/memory.go @@ -0,0 +1,41 @@ +package fs + +import ( + "os" + "strconv" +) + +type memoryGroup struct { +} + +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.MemorySwap != 0) { + return err + } + defer func() { + if err != nil { + os.RemoveAll(dir) + } + }() + + if d.c.Memory != 0 || d.c.MemorySwap != 0 { + if d.c.Memory != 0 { + if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil { + return err + } + if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil { + return err + } + } + // By default, MemorySwap is set to twice the size of RAM. + // If you want to omit MemorySwap, set it to `-1'. + if d.c.MemorySwap != -1 { + if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil { + return err + } + } + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/perf_event.go b/components/engine/pkg/cgroups/fs/perf_event.go new file mode 100644 index 0000000000..2af6d7a512 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/perf_event.go @@ -0,0 +1,16 @@ +package fs + +import ( + "github.com/dotcloud/docker/pkg/cgroups" +) + +type perfEventGroup struct { +} + +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 + } + return nil +} From 112b738831f4f147d5a257fa6cfba73792b9beb6 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 18 Apr 2014 22:17:31 -0700 Subject: [PATCH 11/25] Add remove method to subsystems Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 7fdeda87173ee6722ef1cbe7b21a13ac8b173365 Component: engine --- components/engine/pkg/cgroups/fs/apply_raw.go | 31 ++++++++----------- components/engine/pkg/cgroups/fs/blkio.go | 4 +++ components/engine/pkg/cgroups/fs/cpu.go | 4 +++ components/engine/pkg/cgroups/fs/cpuacct.go | 4 +++ components/engine/pkg/cgroups/fs/cpuset.go | 4 +++ components/engine/pkg/cgroups/fs/devices.go | 4 +++ components/engine/pkg/cgroups/fs/freezer.go | 4 +++ components/engine/pkg/cgroups/fs/memory.go | 4 +++ .../engine/pkg/cgroups/fs/perf_event.go | 4 +++ 9 files changed, 45 insertions(+), 18 deletions(-) diff --git a/components/engine/pkg/cgroups/fs/apply_raw.go b/components/engine/pkg/cgroups/fs/apply_raw.go index 4f1b379726..cdb2b354c6 100644 --- a/components/engine/pkg/cgroups/fs/apply_raw.go +++ b/components/engine/pkg/cgroups/fs/apply_raw.go @@ -25,6 +25,7 @@ var ( type subsystem interface { Set(*data) error + Remove(*data) error } type data struct { @@ -94,24 +95,8 @@ func (raw *data) join(subsystem string) (string, error) { } func (raw *data) Cleanup() error { - get := func(subsystem string) string { - path, _ := raw.path(subsystem) - return path - } - - for _, path := range []string{ - get("memory"), - get("devices"), - get("cpu"), - get("cpuset"), - get("cpuacct"), - get("blkio"), - get("perf_event"), - get("freezer"), - } { - if path != "" { - os.RemoveAll(path) - } + for _, sys := range subsystems { + sys.Remove(raw) } return nil } @@ -119,3 +104,13 @@ func (raw *data) Cleanup() error { func writeFile(dir, file, data string) error { return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) } + +func removePath(p string, err error) error { + if err != nil { + return err + } + if p != "" { + return os.RemoveAll(p) + } + return nil +} diff --git a/components/engine/pkg/cgroups/fs/blkio.go b/components/engine/pkg/cgroups/fs/blkio.go index f0096f8767..48dcf1a54d 100644 --- a/components/engine/pkg/cgroups/fs/blkio.go +++ b/components/engine/pkg/cgroups/fs/blkio.go @@ -14,3 +14,7 @@ func (s *blkioGroup) Set(d *data) error { } return nil } + +func (s *blkioGroup) Remove(d *data) error { + return removePath(d.path("blkio")) +} diff --git a/components/engine/pkg/cgroups/fs/cpu.go b/components/engine/pkg/cgroups/fs/cpu.go index 33879bad14..f458d7915e 100644 --- a/components/engine/pkg/cgroups/fs/cpu.go +++ b/components/engine/pkg/cgroups/fs/cpu.go @@ -21,3 +21,7 @@ func (s *cpuGroup) Set(d *data) error { } return nil } + +func (s *cpuGroup) Remove(d *data) error { + return removePath(d.path("cpu")) +} diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index 603b100571..22dfb4185f 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -14,3 +14,7 @@ func (s *cpuacctGroup) Set(d *data) error { } return nil } + +func (s *cpuacctGroup) Remove(d *data) error { + return removePath(d.path("cpuacct")) +} diff --git a/components/engine/pkg/cgroups/fs/cpuset.go b/components/engine/pkg/cgroups/fs/cpuset.go index 5108365ebd..3d3b15f113 100644 --- a/components/engine/pkg/cgroups/fs/cpuset.go +++ b/components/engine/pkg/cgroups/fs/cpuset.go @@ -26,3 +26,7 @@ func (s *cpusetGroup) Set(d *data) error { } return nil } + +func (s *cpusetGroup) Remove(d *data) error { + return removePath(d.path("cpuset")) +} diff --git a/components/engine/pkg/cgroups/fs/devices.go b/components/engine/pkg/cgroups/fs/devices.go index 769df39283..fc5d83b9c9 100644 --- a/components/engine/pkg/cgroups/fs/devices.go +++ b/components/engine/pkg/cgroups/fs/devices.go @@ -59,3 +59,7 @@ func (s *devicesGroup) Set(d *data) error { } return nil } + +func (s *devicesGroup) Remove(d *data) error { + return removePath(d.path("devices")) +} diff --git a/components/engine/pkg/cgroups/fs/freezer.go b/components/engine/pkg/cgroups/fs/freezer.go index 51db689b0a..05bc584cf4 100644 --- a/components/engine/pkg/cgroups/fs/freezer.go +++ b/components/engine/pkg/cgroups/fs/freezer.go @@ -14,3 +14,7 @@ func (s *freezerGroup) Set(d *data) error { } return nil } + +func (s *freezerGroup) Remove(d *data) error { + return removePath(d.path("freezer")) +} diff --git a/components/engine/pkg/cgroups/fs/memory.go b/components/engine/pkg/cgroups/fs/memory.go index cf33d66117..a098f21df9 100644 --- a/components/engine/pkg/cgroups/fs/memory.go +++ b/components/engine/pkg/cgroups/fs/memory.go @@ -39,3 +39,7 @@ func (s *memoryGroup) Set(d *data) error { } return nil } + +func (s *memoryGroup) Remove(d *data) error { + return removePath(d.path("memory")) +} diff --git a/components/engine/pkg/cgroups/fs/perf_event.go b/components/engine/pkg/cgroups/fs/perf_event.go index 2af6d7a512..b5ec6c6fd3 100644 --- a/components/engine/pkg/cgroups/fs/perf_event.go +++ b/components/engine/pkg/cgroups/fs/perf_event.go @@ -14,3 +14,7 @@ func (s *perfEventGroup) Set(d *data) error { } return nil } + +func (s *perfEventGroup) Remove(d *data) error { + return removePath(d.path("perf_event")) +} From 4690619ea9d0a82cd9c35959545a0916652c4613 Mon Sep 17 00:00:00 2001 From: Lance Chen Date: Mon, 21 Apr 2014 01:27:00 +0800 Subject: [PATCH 12/25] Add missing blank lines in between list items Lists with paragraphs as items need blank lines in between items to generate correct layout. Docker-DCO-1.1-Signed-off-by: Lance Chen (github: Lance0312) Upstream-commit: b87cb76976da57a6765acd9a85494c68a4e6b948 Component: engine --- .../engine/docs/sources/reference/api/registry_index_spec.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/engine/docs/sources/reference/api/registry_index_spec.md b/components/engine/docs/sources/reference/api/registry_index_spec.md index 53006cf0b5..aa18a2e3c5 100644 --- a/components/engine/docs/sources/reference/api/registry_index_spec.md +++ b/components/engine/docs/sources/reference/api/registry_index_spec.md @@ -644,17 +644,20 @@ You have 3 options: > - X-Docker-Token: Token > signature=123abc,repository=”foo/bar”,access=read > + 2. Provide user credentials only > **Header**: > : Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== > + 3. Provide Token > **Header**: > : Authorization: Token > signature=123abc,repository=”foo/bar”,access=read > + ### 6.2 On the Registry The Registry only supports the Token challenge: From 1b76554adc53f167797186a3fd9ac11fbb58bc60 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 11:34:28 -0700 Subject: [PATCH 13/25] Squashed commit of the following: commit 75af1649b063abbc5d662fd2f8bc4ff62c927687 Author: Evan Hazlett Date: Sun Apr 20 01:32:42 2014 -0400 more refactor commit 43b36d0f15d634497127bcb17dacaa70ae92e903 Author: Evan Hazlett Date: Sun Apr 20 01:11:49 2014 -0400 refactored cgroup param parsing to util func commit e3738b0168a075bd92ec828879b0e46bdbbe3845 Author: Evan Hazlett Date: Sun Apr 20 00:57:19 2014 -0400 dat error checking commit 57872bcc59403ecd308cfe97c78f73d6ca58d165 Author: Evan Hazlett Date: Sun Apr 20 00:43:25 2014 -0400 proper use of fmt.Errorf commit 43dad6acc0cb21aac2b04ce074699879898ee820 Author: Evan Hazlett Date: Sun Apr 20 00:36:45 2014 -0400 proper placement of defer commit b7f20b934b2bc92cd39397dbc608b77bff28493c Author: Evan Hazlett Date: Sun Apr 20 00:34:39 2014 -0400 defers, error checking, panic avoidance commit 7a9a6ff267f8806dfe6676486f73fe89b72968fb Author: Evan Hazlett Date: Sun Apr 20 00:22:00 2014 -0400 data param to use container info instead of host commit 0e0cf7309be1644687160d6519db792b23cd26e9 Author: Evan Hazlett Date: Sun Apr 20 00:11:29 2014 -0400 added stats for cpuacct, memory, and blkio Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 86e34ce59fb7f6e6e284a33f2538bafdc9114c89 Component: engine --- components/engine/pkg/cgroups/fs/blkio.go | 36 +++++++++++ components/engine/pkg/cgroups/fs/cpuacct.go | 69 +++++++++++++++++++++ components/engine/pkg/cgroups/fs/memory.go | 26 ++++++++ components/engine/pkg/cgroups/fs/utils.go | 24 +++++++ 4 files changed, 155 insertions(+) create mode 100644 components/engine/pkg/cgroups/fs/utils.go diff --git a/components/engine/pkg/cgroups/fs/blkio.go b/components/engine/pkg/cgroups/fs/blkio.go index 48dcf1a54d..fae8d5a037 100644 --- a/components/engine/pkg/cgroups/fs/blkio.go +++ b/components/engine/pkg/cgroups/fs/blkio.go @@ -1,6 +1,11 @@ package fs import ( + "bufio" + "fmt" + "os" + "path/filepath" + "github.com/dotcloud/docker/pkg/cgroups" ) @@ -18,3 +23,34 @@ func (s *blkioGroup) Set(d *data) error { func (s *blkioGroup) Remove(d *data) error { return removePath(d.path("blkio")) } + +func (s *blkioGroup) Stats(d *data) (map[string]float64, error) { + paramData := make(map[string]float64) + path, err := d.path("blkio") + if err != nil { + return paramData, fmt.Errorf("Unable to read %s cgroup param: %s", path, err) + } + params := []string{ + "sectors", + "io_service_bytes", + "io_serviced", + "io_queued", + } + for _, param := range params { + p := fmt.Sprintf("blkio.%s", param) + f, err := os.Open(filepath.Join(path, p)) + if err != nil { + return paramData, err + } + defer f.Close() + sc := bufio.NewScanner(f) + for sc.Scan() { + _, v, err := getCgroupParamKeyValue(sc.Text()) + if err != nil { + return paramData, fmt.Errorf("Error parsing param data: %s", err) + } + paramData[param] = v + } + } + return paramData, nil +} diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index 22dfb4185f..621592e31f 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -1,6 +1,14 @@ package fs import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "github.com/dotcloud/docker/pkg/cgroups" ) @@ -18,3 +26,64 @@ func (s *cpuacctGroup) Set(d *data) error { func (s *cpuacctGroup) Remove(d *data) error { return removePath(d.path("cpuacct")) } + +func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { + paramData := make(map[string]float64) + path, err := d.path("cpuacct") + if err != nil { + return paramData, fmt.Errorf("Unable to read %s cgroup param: %s", path, err) + } + f, err := os.Open(filepath.Join(path, "cpuacct.stat")) + if err != nil { + return paramData, err + } + defer f.Close() + sc := bufio.NewScanner(f) + cpuTotal := 0.0 + for sc.Scan() { + t, v, err := getCgroupParamKeyValue(sc.Text()) + if err != nil { + return paramData, fmt.Errorf("Error parsing param data: %s", err) + } + // set the raw data in map + paramData[t] = v + cpuTotal += v + } + // calculate percentage from jiffies + // get sys uptime + uf, err := os.Open("/proc/uptime") + if err != nil { + return paramData, fmt.Errorf("Unable to open /proc/uptime") + } + defer uf.Close() + uptimeData, err := ioutil.ReadAll(uf) + if err != nil { + return paramData, fmt.Errorf("Error reading /proc/uptime: %s", err) + } + uptimeFields := strings.Fields(string(uptimeData)) + uptime, err := strconv.ParseFloat(uptimeFields[0], 64) + if err != nil { + return paramData, fmt.Errorf("Error parsing cpu stats: %s", err) + } + // find starttime of process + pf, err := os.Open(filepath.Join(path, "cgroup.procs")) + if err != nil { + return paramData, fmt.Errorf("Error parsing cpu stats: %s", err) + } + defer pf.Close() + pr := bufio.NewReader(pf) + l, _, err := pr.ReadLine() + if err != nil { + return paramData, fmt.Errorf("Error reading param file: %s", err) + } + starttime, err := strconv.ParseFloat(string(l), 64) + if err != nil { + return paramData, fmt.Errorf("Unable to parse starttime: %s", err) + } + // get total elapsed seconds since proc start + seconds := uptime - (starttime / 100) + // finally calc percentage + cpuPercentage := 100.0 * ((cpuTotal / 100.0) / float64(seconds)) + paramData["percentage"] = cpuPercentage + return paramData, nil +} diff --git a/components/engine/pkg/cgroups/fs/memory.go b/components/engine/pkg/cgroups/fs/memory.go index a098f21df9..26281c1c75 100644 --- a/components/engine/pkg/cgroups/fs/memory.go +++ b/components/engine/pkg/cgroups/fs/memory.go @@ -1,7 +1,10 @@ package fs import ( + "bufio" + "fmt" "os" + "path/filepath" "strconv" ) @@ -43,3 +46,26 @@ func (s *memoryGroup) Set(d *data) error { func (s *memoryGroup) Remove(d *data) error { return removePath(d.path("memory")) } + +func (s *memoryGroup) Stats(d *data) (map[string]float64, error) { + paramData := make(map[string]float64) + path, err := d.path("memory") + if err != nil { + fmt.Errorf("Unable to read %s cgroup param: %s", path, err) + return paramData, err + } + f, err := os.Open(filepath.Join(path, "memory.stat")) + if err != nil { + return paramData, err + } + defer f.Close() + sc := bufio.NewScanner(f) + for sc.Scan() { + t, v, err := getCgroupParamKeyValue(sc.Text()) + if err != nil { + return paramData, fmt.Errorf("Error parsing param data: %s", err) + } + paramData[t] = v + } + return paramData, nil +} diff --git a/components/engine/pkg/cgroups/fs/utils.go b/components/engine/pkg/cgroups/fs/utils.go new file mode 100644 index 0000000000..260cf13a52 --- /dev/null +++ b/components/engine/pkg/cgroups/fs/utils.go @@ -0,0 +1,24 @@ +package fs + +import ( + "fmt" + "strconv" + "strings" +) + +// Parses a cgroup param and returns as name, value +// i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234 +func getCgroupParamKeyValue(t string) (string, float64, error) { + parts := strings.Fields(t) + switch len(parts) { + case 2: + name := parts[0] + value, err := strconv.ParseFloat(parts[1], 64) + if err != nil { + return "", 0.0, fmt.Errorf("Unable to convert param value to float: %s", err) + } + return name, value, nil + default: + return "", 0.0, fmt.Errorf("Unable to parse cgroup param: not enough parts; expected 2") + } +} From af2fbf289d8cbbd2bd07c032e3a478bb2874b9db Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 12:02:39 -0700 Subject: [PATCH 14/25] Refactor stats and add them to all subsystems Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 9b65f1635515fa35ed38f8a76b6d8f73ab3a1d02 Component: engine --- components/engine/pkg/cgroups/fs/apply_raw.go | 1 + components/engine/pkg/cgroups/fs/blkio.go | 28 ++++--- components/engine/pkg/cgroups/fs/cpu.go | 4 + components/engine/pkg/cgroups/fs/cpuacct.go | 84 +++++++++---------- components/engine/pkg/cgroups/fs/cpuset.go | 4 + components/engine/pkg/cgroups/fs/devices.go | 4 + components/engine/pkg/cgroups/fs/freezer.go | 4 + components/engine/pkg/cgroups/fs/memory.go | 10 +-- .../engine/pkg/cgroups/fs/perf_event.go | 4 + components/engine/pkg/cgroups/fs/utils.go | 6 +- 10 files changed, 88 insertions(+), 61 deletions(-) diff --git a/components/engine/pkg/cgroups/fs/apply_raw.go b/components/engine/pkg/cgroups/fs/apply_raw.go index cdb2b354c6..ecc4bb62e9 100644 --- a/components/engine/pkg/cgroups/fs/apply_raw.go +++ b/components/engine/pkg/cgroups/fs/apply_raw.go @@ -26,6 +26,7 @@ var ( type subsystem interface { Set(*data) error Remove(*data) error + Stats(*data) (map[string]float64, error) } type data struct { diff --git a/components/engine/pkg/cgroups/fs/blkio.go b/components/engine/pkg/cgroups/fs/blkio.go index fae8d5a037..abf8fb6227 100644 --- a/components/engine/pkg/cgroups/fs/blkio.go +++ b/components/engine/pkg/cgroups/fs/blkio.go @@ -25,29 +25,33 @@ func (s *blkioGroup) Remove(d *data) error { } func (s *blkioGroup) Stats(d *data) (map[string]float64, error) { - paramData := make(map[string]float64) + var ( + paramData = make(map[string]float64) + params = []string{ + "sectors", + "io_service_bytes", + "io_serviced", + "io_queued", + } + ) + path, err := d.path("blkio") if err != nil { - return paramData, fmt.Errorf("Unable to read %s cgroup param: %s", path, err) - } - params := []string{ - "sectors", - "io_service_bytes", - "io_serviced", - "io_queued", + return nil, err } + for _, param := range params { - p := fmt.Sprintf("blkio.%s", param) - f, err := os.Open(filepath.Join(path, p)) + f, err := os.Open(filepath.Join(path, fmt.Sprintf("blkio.%s", param))) if err != nil { - return paramData, err + return nil, err } defer f.Close() + sc := bufio.NewScanner(f) for sc.Scan() { _, v, err := getCgroupParamKeyValue(sc.Text()) if err != nil { - return paramData, fmt.Errorf("Error parsing param data: %s", err) + return nil, err } paramData[param] = v } diff --git a/components/engine/pkg/cgroups/fs/cpu.go b/components/engine/pkg/cgroups/fs/cpu.go index f458d7915e..5534443412 100644 --- a/components/engine/pkg/cgroups/fs/cpu.go +++ b/components/engine/pkg/cgroups/fs/cpu.go @@ -25,3 +25,7 @@ func (s *cpuGroup) Set(d *data) error { func (s *cpuGroup) Remove(d *data) error { return removePath(d.path("cpu")) } + +func (s *cpuGroup) Stats(d *data) (map[string]float64, error) { + return nil, ErrNotSupportStat +} diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index 621592e31f..b0b14a1475 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -2,7 +2,6 @@ package fs import ( "bufio" - "fmt" "io/ioutil" "os" "path/filepath" @@ -10,6 +9,7 @@ import ( "strings" "github.com/dotcloud/docker/pkg/cgroups" + "github.com/dotcloud/docker/pkg/system" ) type cpuacctGroup struct { @@ -28,62 +28,62 @@ func (s *cpuacctGroup) Remove(d *data) error { } func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { - paramData := make(map[string]float64) + var ( + uptime, startTime float64 + paramData = make(map[string]float64) + cpuTotal = 0.0 + ) + path, err := d.path("cpuacct") - if err != nil { - return paramData, fmt.Errorf("Unable to read %s cgroup param: %s", path, err) - } - f, err := os.Open(filepath.Join(path, "cpuacct.stat")) if err != nil { return paramData, err } + f, err := os.Open(filepath.Join(path, "cpuacct.stat")) + if err != nil { + return nil, err + } defer f.Close() + sc := bufio.NewScanner(f) - cpuTotal := 0.0 for sc.Scan() { t, v, err := getCgroupParamKeyValue(sc.Text()) if err != nil { - return paramData, fmt.Errorf("Error parsing param data: %s", err) + return paramData, err } // set the raw data in map paramData[t] = v cpuTotal += v } - // calculate percentage from jiffies - // get sys uptime - uf, err := os.Open("/proc/uptime") - if err != nil { - return paramData, fmt.Errorf("Unable to open /proc/uptime") + + if uptime, err = s.getUptime(); err != nil { + return nil, err } - defer uf.Close() - uptimeData, err := ioutil.ReadAll(uf) - if err != nil { - return paramData, fmt.Errorf("Error reading /proc/uptime: %s", err) + if startTime, err = s.getProcStarttime(d); err != nil { + return nil, err } - uptimeFields := strings.Fields(string(uptimeData)) - uptime, err := strconv.ParseFloat(uptimeFields[0], 64) - if err != nil { - return paramData, fmt.Errorf("Error parsing cpu stats: %s", err) - } - // find starttime of process - pf, err := os.Open(filepath.Join(path, "cgroup.procs")) - if err != nil { - return paramData, fmt.Errorf("Error parsing cpu stats: %s", err) - } - defer pf.Close() - pr := bufio.NewReader(pf) - l, _, err := pr.ReadLine() - if err != nil { - return paramData, fmt.Errorf("Error reading param file: %s", err) - } - starttime, err := strconv.ParseFloat(string(l), 64) - if err != nil { - return paramData, fmt.Errorf("Unable to parse starttime: %s", err) - } - // get total elapsed seconds since proc start - seconds := uptime - (starttime / 100) - // finally calc percentage - cpuPercentage := 100.0 * ((cpuTotal / 100.0) / float64(seconds)) - paramData["percentage"] = cpuPercentage + paramData["percentage"] = 100.0 * ((cpuTotal/100.0)/uptime - (startTime / 100)) + return paramData, nil } + +func (s *cpuacctGroup) getUptime() (float64, error) { + f, err := os.Open("/proc/uptime") + if err != nil { + return 0, err + } + defer f.Close() + + data, err := ioutil.ReadAll(f) + if err != nil { + return 0, err + } + return strconv.ParseFloat(strings.Fields(string(data))[0], 64) +} + +func (s *cpuacctGroup) getProcStarttime(d *data) (float64, error) { + rawStart, err := system.GetProcessStartTime(d.pid) + if err != nil { + return 0, err + } + return strconv.ParseFloat(rawStart, 64) +} diff --git a/components/engine/pkg/cgroups/fs/cpuset.go b/components/engine/pkg/cgroups/fs/cpuset.go index 3d3b15f113..8a13c56cea 100644 --- a/components/engine/pkg/cgroups/fs/cpuset.go +++ b/components/engine/pkg/cgroups/fs/cpuset.go @@ -30,3 +30,7 @@ func (s *cpusetGroup) Set(d *data) error { func (s *cpusetGroup) Remove(d *data) error { return removePath(d.path("cpuset")) } + +func (s *cpusetGroup) Stats(d *data) (map[string]float64, error) { + return nil, ErrNotSupportStat +} diff --git a/components/engine/pkg/cgroups/fs/devices.go b/components/engine/pkg/cgroups/fs/devices.go index fc5d83b9c9..a2f91eda14 100644 --- a/components/engine/pkg/cgroups/fs/devices.go +++ b/components/engine/pkg/cgroups/fs/devices.go @@ -63,3 +63,7 @@ func (s *devicesGroup) Set(d *data) error { func (s *devicesGroup) Remove(d *data) error { return removePath(d.path("devices")) } + +func (s *devicesGroup) Stats(d *data) (map[string]float64, error) { + return nil, ErrNotSupportStat +} diff --git a/components/engine/pkg/cgroups/fs/freezer.go b/components/engine/pkg/cgroups/fs/freezer.go index 05bc584cf4..878a3a5fe9 100644 --- a/components/engine/pkg/cgroups/fs/freezer.go +++ b/components/engine/pkg/cgroups/fs/freezer.go @@ -18,3 +18,7 @@ func (s *freezerGroup) Set(d *data) error { func (s *freezerGroup) Remove(d *data) error { return removePath(d.path("freezer")) } + +func (s *freezerGroup) Stats(d *data) (map[string]float64, error) { + return nil, ErrNotSupportStat +} diff --git a/components/engine/pkg/cgroups/fs/memory.go b/components/engine/pkg/cgroups/fs/memory.go index 26281c1c75..cf4bf5ab73 100644 --- a/components/engine/pkg/cgroups/fs/memory.go +++ b/components/engine/pkg/cgroups/fs/memory.go @@ -2,7 +2,6 @@ package fs import ( "bufio" - "fmt" "os" "path/filepath" "strconv" @@ -51,19 +50,20 @@ func (s *memoryGroup) Stats(d *data) (map[string]float64, error) { paramData := make(map[string]float64) path, err := d.path("memory") if err != nil { - fmt.Errorf("Unable to read %s cgroup param: %s", path, err) - return paramData, err + return nil, err } + f, err := os.Open(filepath.Join(path, "memory.stat")) if err != nil { - return paramData, err + return nil, err } defer f.Close() + sc := bufio.NewScanner(f) for sc.Scan() { t, v, err := getCgroupParamKeyValue(sc.Text()) if err != nil { - return paramData, fmt.Errorf("Error parsing param data: %s", err) + return nil, err } paramData[t] = v } diff --git a/components/engine/pkg/cgroups/fs/perf_event.go b/components/engine/pkg/cgroups/fs/perf_event.go index b5ec6c6fd3..789b3e59ad 100644 --- a/components/engine/pkg/cgroups/fs/perf_event.go +++ b/components/engine/pkg/cgroups/fs/perf_event.go @@ -18,3 +18,7 @@ func (s *perfEventGroup) Set(d *data) error { func (s *perfEventGroup) Remove(d *data) error { return removePath(d.path("perf_event")) } + +func (s *perfEventGroup) Stats(d *data) (map[string]float64, error) { + return nil, ErrNotSupportStat +} diff --git a/components/engine/pkg/cgroups/fs/utils.go b/components/engine/pkg/cgroups/fs/utils.go index 260cf13a52..6a0838f3a2 100644 --- a/components/engine/pkg/cgroups/fs/utils.go +++ b/components/engine/pkg/cgroups/fs/utils.go @@ -1,23 +1,25 @@ package fs import ( + "errors" "fmt" "strconv" "strings" ) +var ErrNotSupportStat = errors.New("stats are not supported for subsystem") + // Parses a cgroup param and returns as name, value // i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234 func getCgroupParamKeyValue(t string) (string, float64, error) { parts := strings.Fields(t) switch len(parts) { case 2: - name := parts[0] value, err := strconv.ParseFloat(parts[1], 64) if err != nil { return "", 0.0, fmt.Errorf("Unable to convert param value to float: %s", err) } - return name, value, nil + return parts[0], value, nil default: return "", 0.0, fmt.Errorf("Unable to parse cgroup param: not enough parts; expected 2") } From 030a007d36ac6567b72fd4dd0b14f1a28f16b7ac Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 17:36:20 -0700 Subject: [PATCH 15/25] Add external function to get cgroup stats Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 7f12260fd13329f3bafe4b42ad4193ff963bb1e2 Component: engine --- components/engine/pkg/cgroups/fs/apply_raw.go | 47 +++++++++++++++---- components/engine/pkg/cgroups/fs/blkio.go | 30 ++++++++++++ components/engine/pkg/cgroups/fs/cpuacct.go | 3 +- 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/components/engine/pkg/cgroups/fs/apply_raw.go b/components/engine/pkg/cgroups/fs/apply_raw.go index ecc4bb62e9..60f318e9ef 100644 --- a/components/engine/pkg/cgroups/fs/apply_raw.go +++ b/components/engine/pkg/cgroups/fs/apply_raw.go @@ -11,15 +11,15 @@ import ( ) var ( - subsystems = []subsystem{ - &devicesGroup{}, - &memoryGroup{}, - &cpuGroup{}, - &cpusetGroup{}, - &cpuacctGroup{}, - &blkioGroup{}, - &perfEventGroup{}, - &freezerGroup{}, + subsystems = map[string]subsystem{ + "devices": &devicesGroup{}, + "memory": &memoryGroup{}, + "cpu": &cpuGroup{}, + "cpuset": &cpusetGroup{}, + "cpuacct": &cpuacctGroup{}, + "blkio": &blkioGroup{}, + "perf_event": &perfEventGroup{}, + "freezer": &freezerGroup{}, } ) @@ -73,6 +73,35 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { return d, nil } +func GetStats(c *cgroups.Cgroup, subsystem string, pid int) (map[string]float64, error) { + cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu") + if err != nil { + return nil, err + } + cgroupRoot = filepath.Dir(cgroupRoot) + + if _, err := os.Stat(cgroupRoot); err != nil { + return nil, fmt.Errorf("cgroups fs not found") + } + + cgroup := c.Name + if c.Parent != "" { + cgroup = filepath.Join(c.Parent, cgroup) + } + + d := &data{ + root: cgroupRoot, + cgroup: cgroup, + c: c, + pid: pid, + } + sys, exists := subsystems[subsystem] + if !exists { + return nil, fmt.Errorf("subsystem %s does not exist", subsystem) + } + return sys.Stats(d) +} + func (raw *data) path(subsystem string) (string, error) { initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { diff --git a/components/engine/pkg/cgroups/fs/blkio.go b/components/engine/pkg/cgroups/fs/blkio.go index abf8fb6227..151f2b450d 100644 --- a/components/engine/pkg/cgroups/fs/blkio.go +++ b/components/engine/pkg/cgroups/fs/blkio.go @@ -24,6 +24,36 @@ func (s *blkioGroup) Remove(d *data) error { return removePath(d.path("blkio")) } +/* +examples: + + blkio.sectors + 8:0 6792 + + blkio.io_service_bytes + 8:0 Read 1282048 + 8:0 Write 2195456 + 8:0 Sync 2195456 + 8:0 Async 1282048 + 8:0 Total 3477504 + Total 3477504 + + blkio.io_serviced + 8:0 Read 124 + 8:0 Write 104 + 8:0 Sync 104 + 8:0 Async 124 + 8:0 Total 228 + Total 228 + + blkio.io_queued + 8:0 Read 0 + 8:0 Write 0 + 8:0 Sync 0 + 8:0 Async 0 + 8:0 Total 0 + Total 0 +*/ func (s *blkioGroup) Stats(d *data) (map[string]float64, error) { var ( paramData = make(map[string]float64) diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index b0b14a1475..a2cbb81bc3 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -61,7 +61,8 @@ func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { if startTime, err = s.getProcStarttime(d); err != nil { return nil, err } - paramData["percentage"] = 100.0 * ((cpuTotal/100.0)/uptime - (startTime / 100)) + //paramData["percentage"] = 100.0 * ((cpuTotal/100.0)/uptime - (startTime / 100)) + paramData["percentage"] = cpuTotal / (uptime - (startTime / 100)) return paramData, nil } From 2f3e3558eb20856703a4190b7f219452950f83e8 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 18:18:17 -0700 Subject: [PATCH 16/25] Fix parsing of blkio files Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 37248039e186f57768bb5c4fad23b1bca65448f7 Component: engine --- components/engine/pkg/cgroups/fs/blkio.go | 47 +++++++++++++++++++---- components/engine/pkg/cgroups/fs/utils.go | 7 +++- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/components/engine/pkg/cgroups/fs/blkio.go b/components/engine/pkg/cgroups/fs/blkio.go index 151f2b450d..79e14fa2dc 100644 --- a/components/engine/pkg/cgroups/fs/blkio.go +++ b/components/engine/pkg/cgroups/fs/blkio.go @@ -3,8 +3,11 @@ package fs import ( "bufio" "fmt" + "io/ioutil" "os" "path/filepath" + "strconv" + "strings" "github.com/dotcloud/docker/pkg/cgroups" ) @@ -58,10 +61,9 @@ func (s *blkioGroup) Stats(d *data) (map[string]float64, error) { var ( paramData = make(map[string]float64) params = []string{ - "sectors", - "io_service_bytes", - "io_serviced", - "io_queued", + "io_service_bytes_recursive", + "io_serviced_recursive", + "io_queued_recursive", } ) @@ -70,6 +72,12 @@ func (s *blkioGroup) Stats(d *data) (map[string]float64, error) { return nil, err } + k, v, err := s.getSectors(path) + if err != nil { + return nil, err + } + paramData[fmt.Sprintf("blkio.sectors_recursive:%s", k)] = v + for _, param := range params { f, err := os.Open(filepath.Join(path, fmt.Sprintf("blkio.%s", param))) if err != nil { @@ -79,12 +87,35 @@ func (s *blkioGroup) Stats(d *data) (map[string]float64, error) { sc := bufio.NewScanner(f) for sc.Scan() { - _, v, err := getCgroupParamKeyValue(sc.Text()) - if err != nil { - return nil, err + // format: dev type amount + fields := strings.Fields(sc.Text()) + switch len(fields) { + case 3: + v, err := strconv.ParseFloat(fields[2], 64) + if err != nil { + return nil, err + } + paramData[fmt.Sprintf("%s:%s:%s", param, fields[0], fields[1])] = v + case 2: + // this is the total line, skip + default: + return nil, ErrNotValidFormat } - paramData[param] = v } } return paramData, nil } + +func (s *blkioGroup) getSectors(path string) (string, float64, error) { + f, err := os.Open(filepath.Join(path, "blkio.sectors_recursive")) + if err != nil { + return "", 0, err + } + defer f.Close() + + data, err := ioutil.ReadAll(f) + if err != nil { + return "", 0, err + } + return getCgroupParamKeyValue(string(data)) +} diff --git a/components/engine/pkg/cgroups/fs/utils.go b/components/engine/pkg/cgroups/fs/utils.go index 6a0838f3a2..f4c4846b8c 100644 --- a/components/engine/pkg/cgroups/fs/utils.go +++ b/components/engine/pkg/cgroups/fs/utils.go @@ -7,7 +7,10 @@ import ( "strings" ) -var ErrNotSupportStat = errors.New("stats are not supported for subsystem") +var ( + ErrNotSupportStat = errors.New("stats are not supported for subsystem") + ErrNotValidFormat = errors.New("line is not a valid key value format") +) // Parses a cgroup param and returns as name, value // i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234 @@ -21,6 +24,6 @@ func getCgroupParamKeyValue(t string) (string, float64, error) { } return parts[0], value, nil default: - return "", 0.0, fmt.Errorf("Unable to parse cgroup param: not enough parts; expected 2") + return "", 0.0, ErrNotValidFormat } } From a0be7fcb46b7a6a75a307520b7867181e4464b86 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 18:20:44 -0700 Subject: [PATCH 17/25] Reuse cpuacct stats for cpu subsystem Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 3bfe13de2c38fda5b57e2499f474da701495c5ba Component: engine --- components/engine/pkg/cgroups/fs/cpu.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/engine/pkg/cgroups/fs/cpu.go b/components/engine/pkg/cgroups/fs/cpu.go index 5534443412..8eb0c4ff46 100644 --- a/components/engine/pkg/cgroups/fs/cpu.go +++ b/components/engine/pkg/cgroups/fs/cpu.go @@ -27,5 +27,7 @@ func (s *cpuGroup) Remove(d *data) error { } func (s *cpuGroup) Stats(d *data) (map[string]float64, error) { - return nil, ErrNotSupportStat + // we can reuse the cpuacct subsystem to get the cpu stats + sys := subsystems["cpuacct"] + return sys.Stats(d) } From d5fdf0aaaafa478b711dcc15b3fada0093753690 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 18:35:33 -0700 Subject: [PATCH 18/25] Add freezer stats This one is a problem because the most useful stat is a string and not a float like verything else. We may have to change the return type Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: bce49dff0d46dec620e755ed859efa791054a843 Component: engine --- components/engine/pkg/cgroups/fs/freezer.go | 40 ++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/components/engine/pkg/cgroups/fs/freezer.go b/components/engine/pkg/cgroups/fs/freezer.go index 878a3a5fe9..ebf5bb9672 100644 --- a/components/engine/pkg/cgroups/fs/freezer.go +++ b/components/engine/pkg/cgroups/fs/freezer.go @@ -1,7 +1,13 @@ package fs import ( + "fmt" "github.com/dotcloud/docker/pkg/cgroups" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" ) type freezerGroup struct { @@ -20,5 +26,37 @@ func (s *freezerGroup) Remove(d *data) error { } func (s *freezerGroup) Stats(d *data) (map[string]float64, error) { - return nil, ErrNotSupportStat + var ( + paramData = make(map[string]float64) + params = []string{ + "parent_freezing", + "self_freezing", + // comment out right now because this is string "state", + } + ) + + path, err := d.path("freezer") + if err != nil { + return nil, err + } + + for _, param := range params { + f, err := os.Open(filepath.Join(path, fmt.Sprintf("freezer.%s", param))) + if err != nil { + return nil, err + } + defer f.Close() + + data, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + + v, err := strconv.ParseFloat(strings.TrimSuffix(string(data), "\n"), 64) + if err != nil { + return nil, err + } + paramData[param] = v + } + return paramData, nil } From 3973334e17935ee7cbdf35ca9c53712b7a8763b9 Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Sun, 20 Apr 2014 23:27:05 -0400 Subject: [PATCH 19/25] work on cpu stats Docker-DCO-1.1-Signed-off-by: Evan Hazlett (github: ehazlett) Upstream-commit: 2f24b5a9dcc9ca5da07563fb0dd381e49ed844cc Component: engine --- components/engine/pkg/cgroups/fs/cpuacct.go | 114 ++++++++++++-------- 1 file changed, 72 insertions(+), 42 deletions(-) diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index a2cbb81bc3..aa2cac5d8f 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -2,11 +2,13 @@ package fs import ( "bufio" - "io/ioutil" + "fmt" "os" "path/filepath" + "runtime" "strconv" "strings" + "time" "github.com/dotcloud/docker/pkg/cgroups" "github.com/dotcloud/docker/pkg/system" @@ -29,58 +31,36 @@ func (s *cpuacctGroup) Remove(d *data) error { func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { var ( - uptime, startTime float64 - paramData = make(map[string]float64) - cpuTotal = 0.0 + startCpu, lastCpu, startSystem, lastSystem float64 + paramData = make(map[string]float64) + percentage = 0.0 ) - path, err := d.path("cpuacct") - if err != nil { - return paramData, err - } - f, err := os.Open(filepath.Join(path, "cpuacct.stat")) - if err != nil { + if startCpu, err = s.getCpuUsage(d, path); err != nil { return nil, err } - defer f.Close() - - sc := bufio.NewScanner(f) - for sc.Scan() { - t, v, err := getCgroupParamKeyValue(sc.Text()) - if err != nil { - return paramData, err - } - // set the raw data in map - paramData[t] = v - cpuTotal += v - } - - if uptime, err = s.getUptime(); err != nil { + if startSystem, err = s.getSystemCpuUsage(d); err != nil { return nil, err } - if startTime, err = s.getProcStarttime(d); err != nil { + // sample for 100ms + time.Sleep(100 * time.Millisecond) + if lastCpu, err = s.getCpuUsage(d, path); err != nil { return nil, err } - //paramData["percentage"] = 100.0 * ((cpuTotal/100.0)/uptime - (startTime / 100)) - paramData["percentage"] = cpuTotal / (uptime - (startTime / 100)) - + if lastSystem, err = s.getSystemCpuUsage(d); err != nil { + return nil, err + } + var ( + deltaProc = lastCpu - startCpu + deltaSystem = lastSystem - startSystem + ) + if deltaSystem > 0.0 { + percentage = ((deltaProc / deltaSystem) * 100.0) * float64(runtime.NumCPU()) + } + paramData["percentage"] = percentage return paramData, nil } -func (s *cpuacctGroup) getUptime() (float64, error) { - f, err := os.Open("/proc/uptime") - if err != nil { - return 0, err - } - defer f.Close() - - data, err := ioutil.ReadAll(f) - if err != nil { - return 0, err - } - return strconv.ParseFloat(strings.Fields(string(data))[0], 64) -} - func (s *cpuacctGroup) getProcStarttime(d *data) (float64, error) { rawStart, err := system.GetProcessStartTime(d.pid) if err != nil { @@ -88,3 +68,53 @@ func (s *cpuacctGroup) getProcStarttime(d *data) (float64, error) { } return strconv.ParseFloat(rawStart, 64) } + +func (s *cpuacctGroup) getSystemCpuUsage(d *data) (float64, error) { + total := 0.0 + f, err := os.Open("/proc/stat") + if err != nil { + return 0, err + } + defer f.Close() + + sc := bufio.NewScanner(f) + for sc.Scan() { + txt := sc.Text() + if strings.Index(txt, "cpu") == 0 { + parts := strings.Fields(txt) + partsLength := len(parts) + if partsLength != 11 { + return 0.0, fmt.Errorf("Unable to parse cpu usage: expected 11 fields ; received %d", partsLength) + } + for _, i := range parts[1:10] { + val, err := strconv.ParseFloat(i, 64) + if err != nil { + return 0.0, fmt.Errorf("Unable to convert value to float: %s", err) + } + total += val + } + break + } + } + return total, nil +} + +func (s *cpuacctGroup) getCpuUsage(d *data, path string) (float64, error) { + cpuTotal := 0.0 + f, err := os.Open(filepath.Join(path, "cpuacct.stat")) + if err != nil { + return 0.0, err + } + defer f.Close() + + sc := bufio.NewScanner(f) + for sc.Scan() { + _, v, err := getCgroupParamKeyValue(sc.Text()) + if err != nil { + return 0.0, err + } + // set the raw data in map + cpuTotal += v + } + return cpuTotal, nil +} From f2dbe8f1d11692f96b6a7a1449fec8773950163f Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 20 Apr 2014 20:45:08 -0700 Subject: [PATCH 20/25] Refactor stat parsing to use only 8 fields Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: f59be989dc92503f29aa94ebf9ea4097ec28b8c9 Component: engine --- components/engine/pkg/cgroups/fs/cpuacct.go | 38 +++++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index aa2cac5d8f..8c123b79ee 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -14,6 +14,8 @@ import ( "github.com/dotcloud/docker/pkg/system" ) +var cpuCount = float64(runtime.NumCPU()) + type cpuacctGroup struct { } @@ -32,8 +34,8 @@ func (s *cpuacctGroup) Remove(d *data) error { func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { var ( startCpu, lastCpu, startSystem, lastSystem float64 + percentage float64 paramData = make(map[string]float64) - percentage = 0.0 ) path, err := d.path("cpuacct") if startCpu, err = s.getCpuUsage(d, path); err != nil { @@ -50,13 +52,16 @@ func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { if lastSystem, err = s.getSystemCpuUsage(d); err != nil { return nil, err } + var ( deltaProc = lastCpu - startCpu deltaSystem = lastSystem - startSystem ) if deltaSystem > 0.0 { - percentage = ((deltaProc / deltaSystem) * 100.0) * float64(runtime.NumCPU()) + percentage = ((deltaProc / deltaSystem) * 100.0) * cpuCount } + // NOTE: a percentage over 100% is valid for POSIX because that means the + // processes is using multiple cores paramData["percentage"] = percentage return paramData, nil } @@ -70,7 +75,7 @@ func (s *cpuacctGroup) getProcStarttime(d *data) (float64, error) { } func (s *cpuacctGroup) getSystemCpuUsage(d *data) (float64, error) { - total := 0.0 + f, err := os.Open("/proc/stat") if err != nil { return 0, err @@ -79,24 +84,27 @@ func (s *cpuacctGroup) getSystemCpuUsage(d *data) (float64, error) { sc := bufio.NewScanner(f) for sc.Scan() { - txt := sc.Text() - if strings.Index(txt, "cpu") == 0 { - parts := strings.Fields(txt) - partsLength := len(parts) - if partsLength != 11 { - return 0.0, fmt.Errorf("Unable to parse cpu usage: expected 11 fields ; received %d", partsLength) + parts := strings.Fields(sc.Text()) + switch parts[0] { + case "cpu": + if len(parts) < 8 { + return 0, fmt.Errorf("invalid number of cpu fields") } - for _, i := range parts[1:10] { - val, err := strconv.ParseFloat(i, 64) + + var total float64 + for _, i := range parts[1:8] { + v, err := strconv.ParseFloat(i, 64) if err != nil { - return 0.0, fmt.Errorf("Unable to convert value to float: %s", err) + return 0.0, fmt.Errorf("Unable to convert value %s to float: %s", i, err) } - total += val + total += v } - break + return total, nil + default: + continue } } - return total, nil + return 0, fmt.Errorf("invalid stat format") } func (s *cpuacctGroup) getCpuUsage(d *data, path string) (float64, error) { From 7aff9b75c921a86d20979936c07f38fa17d1a8ab Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 21 Apr 2014 10:26:03 -0700 Subject: [PATCH 21/25] Use cgo to get systems clock ticks for metrics Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) Upstream-commit: 004cf556e86a03d8961416b3e8a0a476a424b10f Component: engine --- components/engine/pkg/cgroups/fs/cpuacct.go | 7 +++++-- components/engine/pkg/system/sysconfig.go | 13 +++++++++++++ components/engine/pkg/system/sysconfig_nocgo.go | 9 +++++++++ components/engine/pkg/system/unsupported.go | 6 ++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 components/engine/pkg/system/sysconfig.go create mode 100644 components/engine/pkg/system/sysconfig_nocgo.go diff --git a/components/engine/pkg/cgroups/fs/cpuacct.go b/components/engine/pkg/cgroups/fs/cpuacct.go index 8c123b79ee..4ea2b1f51b 100644 --- a/components/engine/pkg/cgroups/fs/cpuacct.go +++ b/components/engine/pkg/cgroups/fs/cpuacct.go @@ -14,7 +14,10 @@ import ( "github.com/dotcloud/docker/pkg/system" ) -var cpuCount = float64(runtime.NumCPU()) +var ( + cpuCount = float64(runtime.NumCPU()) + clockTicks = float64(system.GetClockTicks()) +) type cpuacctGroup struct { } @@ -58,7 +61,7 @@ func (s *cpuacctGroup) Stats(d *data) (map[string]float64, error) { deltaSystem = lastSystem - startSystem ) if deltaSystem > 0.0 { - percentage = ((deltaProc / deltaSystem) * 100.0) * cpuCount + percentage = ((deltaProc / deltaSystem) * clockTicks) * cpuCount } // NOTE: a percentage over 100% is valid for POSIX because that means the // processes is using multiple cores diff --git a/components/engine/pkg/system/sysconfig.go b/components/engine/pkg/system/sysconfig.go new file mode 100644 index 0000000000..dcbe6c9cdd --- /dev/null +++ b/components/engine/pkg/system/sysconfig.go @@ -0,0 +1,13 @@ +// +build linux,cgo + +package system + +/* +#include +int get_hz(void) { return sysconf(_SC_CLK_TCK); } +*/ +import "C" + +func GetClockTicks() int { + return int(C.get_hz()) +} diff --git a/components/engine/pkg/system/sysconfig_nocgo.go b/components/engine/pkg/system/sysconfig_nocgo.go new file mode 100644 index 0000000000..7ca3488154 --- /dev/null +++ b/components/engine/pkg/system/sysconfig_nocgo.go @@ -0,0 +1,9 @@ +// +build linux,!cgo + +package system + +func GetClockTicks() int { + // when we cannot call out to C to get the sysconf it is fairly safe to + // just return 100 + return 100 +} diff --git a/components/engine/pkg/system/unsupported.go b/components/engine/pkg/system/unsupported.go index c52a1e5d00..4ae2a488aa 100644 --- a/components/engine/pkg/system/unsupported.go +++ b/components/engine/pkg/system/unsupported.go @@ -17,3 +17,9 @@ func UsetCloseOnExec(fd uintptr) error { func Gettid() int { return 0 } + +func GetClockTicks() int { + // when we cannot call out to C to get the sysconf it is fairly safe to + // just return 100 + return 100 +} From eec18ea7478483517e2349b9835b69548bd1f13f Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 21 Apr 2014 10:28:04 -0700 Subject: [PATCH 22/25] Make sure @proc is defined Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes (github: creack) Upstream-commit: ac814ee3c76a3851d361e8dddfed7ac93ddf10e2 Component: engine --- components/engine/pkg/apparmor/gen.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/engine/pkg/apparmor/gen.go b/components/engine/pkg/apparmor/gen.go index bf9be2ae0b..825e646d92 100644 --- a/components/engine/pkg/apparmor/gen.go +++ b/components/engine/pkg/apparmor/gen.go @@ -69,6 +69,8 @@ func generateProfile(out io.Writer) error { } if tuntablesExists() { data.Imports = append(data.Imports, "#include ") + } else { + data.Imports = append(data.Imports, "@{PROC}=/proc/") } if abstrctionsEsists() { data.InnerImports = append(data.InnerImports, "#include ") From 87bda4c4e9b3069e42ca31d3a10a3576382c668a Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Mon, 21 Apr 2014 17:31:08 -0700 Subject: [PATCH 23/25] Freeze server/server.go for deprecation * Add notice in server/server.go explaining not to add stuff there, and what to do instead. * Make myself a sole maintainer of server/ to avoid concurrent edits while refactoring. Docker-DCO-1.1-Signed-off-by: Solomon Hykes (github: shykes) Upstream-commit: 8bcbc9fe9937b20c9086e0d8c810a257face46a3 Component: engine --- components/engine/server/MAINTAINERS | 1 + components/engine/server/server.go | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 components/engine/server/MAINTAINERS diff --git a/components/engine/server/MAINTAINERS b/components/engine/server/MAINTAINERS new file mode 100644 index 0000000000..db33365bcd --- /dev/null +++ b/components/engine/server/MAINTAINERS @@ -0,0 +1 @@ +Solomon Hykes diff --git a/components/engine/server/server.go b/components/engine/server/server.go index 72244f4e6b..0ab0a4a00b 100644 --- a/components/engine/server/server.go +++ b/components/engine/server/server.go @@ -1,3 +1,24 @@ +// DEPRECATION NOTICE. PLEASE DO NOT ADD ANYTHING TO THIS FILE. +// +// server/server.go is deprecated. We are working on breaking it up into smaller, cleaner +// pieces which will be easier to find and test. This will help make the code less +// redundant and more readable. +// +// Contributors, please don't add anything to server/server.go, unless it has the explicit +// goal of helping the deprecation effort. +// +// Maintainers, please refuse patches which add code to server/server.go. +// +// Instead try the following files: +// * For code related to local image management, try graph/ +// * For code related to image downloading, uploading, remote search etc, try registry/ +// * For code related to the docker daemon, try daemon/ +// * For small utilities which could potentially be useful outside of Docker, try pkg/ +// * For miscalleneous "util" functions which are docker-specific, try encapsulating them +// inside one of the subsystems above. If you really think they should be more widely +// available, are you sure you can't remove the docker dependencies and move them to +// pkg? In last resort, you can add them to utils/ (but please try not to). + package server import ( From 44ed49fbeb780f07daa48983c2d32dc092caeafc Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Mon, 21 Apr 2014 17:01:34 -0700 Subject: [PATCH 24/25] Clean up MAINTAINERS files * Remove out of date "vacation mode" * Fix my email address * Remove infrastructure maintainers to reflect reality (core maintainers are currently maintaining their own infrastructure). Docker-DCO-1.1-Signed-off-by: Solomon Hykes (github: shykes) Upstream-commit: 19e6614eeb31d6a986ef61486e15aeb09cc952b8 Component: engine --- components/engine/MAINTAINERS | 2 +- components/engine/engine/MAINTAINERS | 2 +- components/engine/hack/infrastructure/MAINTAINERS | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 components/engine/hack/infrastructure/MAINTAINERS diff --git a/components/engine/MAINTAINERS b/components/engine/MAINTAINERS index d1f4d15491..581953cf8d 100644 --- a/components/engine/MAINTAINERS +++ b/components/engine/MAINTAINERS @@ -1,4 +1,4 @@ -Solomon Hykes (@shykes) +Solomon Hykes (@shykes) Guillaume J. Charmes (@creack) Victor Vieux (@vieux) Michael Crosby (@crosbymichael) diff --git a/components/engine/engine/MAINTAINERS b/components/engine/engine/MAINTAINERS index 354798f72e..db33365bcd 100644 --- a/components/engine/engine/MAINTAINERS +++ b/components/engine/engine/MAINTAINERS @@ -1 +1 @@ -#Solomon Hykes Temporarily unavailable +Solomon Hykes diff --git a/components/engine/hack/infrastructure/MAINTAINERS b/components/engine/hack/infrastructure/MAINTAINERS deleted file mode 100644 index bd089c55f4..0000000000 --- a/components/engine/hack/infrastructure/MAINTAINERS +++ /dev/null @@ -1,2 +0,0 @@ -Ken Cochrane (@kencochrane) -Jerome Petazzoni (@jpetazzo) From 20d84aa049744768163facc5f5f94478d926971a Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Tue, 22 Apr 2014 06:43:08 -0600 Subject: [PATCH 25/25] Update contributed man page file names and compilation script for the eventual possibility of non-man1 man pages (hopefully a Dockerfile.5.md, for example) Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) Upstream-commit: f763075c74aeb8a829cb310164f36015fb4bc806 Component: engine --- .../md/{docker-attach.md => docker-attach.1.md} | 0 .../man/md/{docker-build.md => docker-build.1.md} | 0 .../md/{docker-commit.md => docker-commit.1.md} | 0 .../man/md/{docker-cp.md => docker-cp.1.md} | 0 .../man/md/{docker-diff.md => docker-diff.1.md} | 0 .../md/{docker-events.md => docker-events.1.md} | 0 .../md/{docker-export.md => docker-export.1.md} | 0 .../md/{docker-history.md => docker-history.1.md} | 0 .../md/{docker-images.md => docker-images.1.md} | 0 .../md/{docker-import.md => docker-import.1.md} | 0 .../man/md/{docker-info.md => docker-info.1.md} | 0 .../md/{docker-inspect.md => docker-inspect.1.md} | 0 .../man/md/{docker-kill.md => docker-kill.1.md} | 0 .../man/md/{docker-load.md => docker-load.1.md} | 0 .../man/md/{docker-login.md => docker-login.1.md} | 0 .../man/md/{docker-logs.md => docker-logs.1.md} | 0 .../man/md/{docker-port.md => docker-port.1.md} | 0 .../man/md/{docker-ps.md => docker-ps.1.md} | 0 .../man/md/{docker-pull.md => docker-pull.1.md} | 0 .../man/md/{docker-push.md => docker-push.1.md} | 0 .../md/{docker-restart.md => docker-restart.1.md} | 0 .../man/md/{docker-rm.md => docker-rm.1.md} | 0 .../man/md/{docker-rmi.md => docker-rmi.1.md} | 0 .../man/md/{docker-run.md => docker-run.1.md} | 0 .../man/md/{docker-save.md => docker-save.1.md} | 0 .../md/{docker-search.md => docker-search.1.md} | 0 .../man/md/{docker-start.md => docker-start.1.md} | 0 .../man/md/{docker-stop.md => docker-stop.1.md} | 0 .../man/md/{docker-tag.md => docker-tag.1.md} | 0 .../man/md/{docker-top.md => docker-top.1.md} | 0 .../man/md/{docker-wait.md => docker-wait.1.md} | 0 .../contrib/man/md/{docker.md => docker.1.md} | 0 components/engine/contrib/man/md/md2man-all.sh | 14 ++++++++++---- 33 files changed, 10 insertions(+), 4 deletions(-) rename components/engine/contrib/man/md/{docker-attach.md => docker-attach.1.md} (100%) rename components/engine/contrib/man/md/{docker-build.md => docker-build.1.md} (100%) rename components/engine/contrib/man/md/{docker-commit.md => docker-commit.1.md} (100%) rename components/engine/contrib/man/md/{docker-cp.md => docker-cp.1.md} (100%) rename components/engine/contrib/man/md/{docker-diff.md => docker-diff.1.md} (100%) rename components/engine/contrib/man/md/{docker-events.md => docker-events.1.md} (100%) rename components/engine/contrib/man/md/{docker-export.md => docker-export.1.md} (100%) rename components/engine/contrib/man/md/{docker-history.md => docker-history.1.md} (100%) rename components/engine/contrib/man/md/{docker-images.md => docker-images.1.md} (100%) rename components/engine/contrib/man/md/{docker-import.md => docker-import.1.md} (100%) rename components/engine/contrib/man/md/{docker-info.md => docker-info.1.md} (100%) rename components/engine/contrib/man/md/{docker-inspect.md => docker-inspect.1.md} (100%) rename components/engine/contrib/man/md/{docker-kill.md => docker-kill.1.md} (100%) rename components/engine/contrib/man/md/{docker-load.md => docker-load.1.md} (100%) rename components/engine/contrib/man/md/{docker-login.md => docker-login.1.md} (100%) rename components/engine/contrib/man/md/{docker-logs.md => docker-logs.1.md} (100%) rename components/engine/contrib/man/md/{docker-port.md => docker-port.1.md} (100%) rename components/engine/contrib/man/md/{docker-ps.md => docker-ps.1.md} (100%) rename components/engine/contrib/man/md/{docker-pull.md => docker-pull.1.md} (100%) rename components/engine/contrib/man/md/{docker-push.md => docker-push.1.md} (100%) rename components/engine/contrib/man/md/{docker-restart.md => docker-restart.1.md} (100%) rename components/engine/contrib/man/md/{docker-rm.md => docker-rm.1.md} (100%) rename components/engine/contrib/man/md/{docker-rmi.md => docker-rmi.1.md} (100%) rename components/engine/contrib/man/md/{docker-run.md => docker-run.1.md} (100%) rename components/engine/contrib/man/md/{docker-save.md => docker-save.1.md} (100%) rename components/engine/contrib/man/md/{docker-search.md => docker-search.1.md} (100%) rename components/engine/contrib/man/md/{docker-start.md => docker-start.1.md} (100%) rename components/engine/contrib/man/md/{docker-stop.md => docker-stop.1.md} (100%) rename components/engine/contrib/man/md/{docker-tag.md => docker-tag.1.md} (100%) rename components/engine/contrib/man/md/{docker-top.md => docker-top.1.md} (100%) rename components/engine/contrib/man/md/{docker-wait.md => docker-wait.1.md} (100%) rename components/engine/contrib/man/md/{docker.md => docker.1.md} (100%) diff --git a/components/engine/contrib/man/md/docker-attach.md b/components/engine/contrib/man/md/docker-attach.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-attach.md rename to components/engine/contrib/man/md/docker-attach.1.md diff --git a/components/engine/contrib/man/md/docker-build.md b/components/engine/contrib/man/md/docker-build.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-build.md rename to components/engine/contrib/man/md/docker-build.1.md diff --git a/components/engine/contrib/man/md/docker-commit.md b/components/engine/contrib/man/md/docker-commit.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-commit.md rename to components/engine/contrib/man/md/docker-commit.1.md diff --git a/components/engine/contrib/man/md/docker-cp.md b/components/engine/contrib/man/md/docker-cp.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-cp.md rename to components/engine/contrib/man/md/docker-cp.1.md diff --git a/components/engine/contrib/man/md/docker-diff.md b/components/engine/contrib/man/md/docker-diff.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-diff.md rename to components/engine/contrib/man/md/docker-diff.1.md diff --git a/components/engine/contrib/man/md/docker-events.md b/components/engine/contrib/man/md/docker-events.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-events.md rename to components/engine/contrib/man/md/docker-events.1.md diff --git a/components/engine/contrib/man/md/docker-export.md b/components/engine/contrib/man/md/docker-export.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-export.md rename to components/engine/contrib/man/md/docker-export.1.md diff --git a/components/engine/contrib/man/md/docker-history.md b/components/engine/contrib/man/md/docker-history.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-history.md rename to components/engine/contrib/man/md/docker-history.1.md diff --git a/components/engine/contrib/man/md/docker-images.md b/components/engine/contrib/man/md/docker-images.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-images.md rename to components/engine/contrib/man/md/docker-images.1.md diff --git a/components/engine/contrib/man/md/docker-import.md b/components/engine/contrib/man/md/docker-import.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-import.md rename to components/engine/contrib/man/md/docker-import.1.md diff --git a/components/engine/contrib/man/md/docker-info.md b/components/engine/contrib/man/md/docker-info.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-info.md rename to components/engine/contrib/man/md/docker-info.1.md diff --git a/components/engine/contrib/man/md/docker-inspect.md b/components/engine/contrib/man/md/docker-inspect.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-inspect.md rename to components/engine/contrib/man/md/docker-inspect.1.md diff --git a/components/engine/contrib/man/md/docker-kill.md b/components/engine/contrib/man/md/docker-kill.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-kill.md rename to components/engine/contrib/man/md/docker-kill.1.md diff --git a/components/engine/contrib/man/md/docker-load.md b/components/engine/contrib/man/md/docker-load.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-load.md rename to components/engine/contrib/man/md/docker-load.1.md diff --git a/components/engine/contrib/man/md/docker-login.md b/components/engine/contrib/man/md/docker-login.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-login.md rename to components/engine/contrib/man/md/docker-login.1.md diff --git a/components/engine/contrib/man/md/docker-logs.md b/components/engine/contrib/man/md/docker-logs.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-logs.md rename to components/engine/contrib/man/md/docker-logs.1.md diff --git a/components/engine/contrib/man/md/docker-port.md b/components/engine/contrib/man/md/docker-port.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-port.md rename to components/engine/contrib/man/md/docker-port.1.md diff --git a/components/engine/contrib/man/md/docker-ps.md b/components/engine/contrib/man/md/docker-ps.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-ps.md rename to components/engine/contrib/man/md/docker-ps.1.md diff --git a/components/engine/contrib/man/md/docker-pull.md b/components/engine/contrib/man/md/docker-pull.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-pull.md rename to components/engine/contrib/man/md/docker-pull.1.md diff --git a/components/engine/contrib/man/md/docker-push.md b/components/engine/contrib/man/md/docker-push.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-push.md rename to components/engine/contrib/man/md/docker-push.1.md diff --git a/components/engine/contrib/man/md/docker-restart.md b/components/engine/contrib/man/md/docker-restart.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-restart.md rename to components/engine/contrib/man/md/docker-restart.1.md diff --git a/components/engine/contrib/man/md/docker-rm.md b/components/engine/contrib/man/md/docker-rm.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-rm.md rename to components/engine/contrib/man/md/docker-rm.1.md diff --git a/components/engine/contrib/man/md/docker-rmi.md b/components/engine/contrib/man/md/docker-rmi.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-rmi.md rename to components/engine/contrib/man/md/docker-rmi.1.md diff --git a/components/engine/contrib/man/md/docker-run.md b/components/engine/contrib/man/md/docker-run.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-run.md rename to components/engine/contrib/man/md/docker-run.1.md diff --git a/components/engine/contrib/man/md/docker-save.md b/components/engine/contrib/man/md/docker-save.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-save.md rename to components/engine/contrib/man/md/docker-save.1.md diff --git a/components/engine/contrib/man/md/docker-search.md b/components/engine/contrib/man/md/docker-search.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-search.md rename to components/engine/contrib/man/md/docker-search.1.md diff --git a/components/engine/contrib/man/md/docker-start.md b/components/engine/contrib/man/md/docker-start.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-start.md rename to components/engine/contrib/man/md/docker-start.1.md diff --git a/components/engine/contrib/man/md/docker-stop.md b/components/engine/contrib/man/md/docker-stop.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-stop.md rename to components/engine/contrib/man/md/docker-stop.1.md diff --git a/components/engine/contrib/man/md/docker-tag.md b/components/engine/contrib/man/md/docker-tag.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-tag.md rename to components/engine/contrib/man/md/docker-tag.1.md diff --git a/components/engine/contrib/man/md/docker-top.md b/components/engine/contrib/man/md/docker-top.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-top.md rename to components/engine/contrib/man/md/docker-top.1.md diff --git a/components/engine/contrib/man/md/docker-wait.md b/components/engine/contrib/man/md/docker-wait.1.md similarity index 100% rename from components/engine/contrib/man/md/docker-wait.md rename to components/engine/contrib/man/md/docker-wait.1.md diff --git a/components/engine/contrib/man/md/docker.md b/components/engine/contrib/man/md/docker.1.md similarity index 100% rename from components/engine/contrib/man/md/docker.md rename to components/engine/contrib/man/md/docker.1.md diff --git a/components/engine/contrib/man/md/md2man-all.sh b/components/engine/contrib/man/md/md2man-all.sh index e482da647a..f33557934c 100755 --- a/components/engine/contrib/man/md/md2man-all.sh +++ b/components/engine/contrib/man/md/md2man-all.sh @@ -9,8 +9,14 @@ cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" pwd } -mkdir -p ../man1 - -for FILE in docker*.md; do - pandoc -s -t man "$FILE" -o "../man1/${FILE%.*}.1" +for FILE in *.md; do + base="$(basename "$FILE")" + name="${base%.md}" + num="${name##*.}" + if [ -z "$num" -o "$base" = "$num" ]; then + # skip files that aren't of the format xxxx.N.md (like README.md) + continue + fi + mkdir -p "../man${num}" + pandoc -s -t man "$FILE" -o "../man${num}/${name}" done