From 811d93326bc2d9451eb444e2343bb3063611de7a Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 21 May 2014 20:48:06 +0000 Subject: [PATCH] Move get pid into cgroup implementation Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/native/create.go | 13 +++- daemon/execdriver/native/driver.go | 59 ++++++++----------- pkg/libcontainer/cgroups/fs/apply_raw.go | 30 ++++++++++ pkg/libcontainer/cgroups/fs/devices.go | 9 --- .../cgroups/systemd/apply_nosystemd.go | 6 +- .../cgroups/systemd/apply_systemd.go | 24 +++++++- pkg/libcontainer/cgroups/utils.go | 26 ++++++++ 7 files changed, 118 insertions(+), 49 deletions(-) diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index 76816e0b9c..d177ca7840 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -3,6 +3,7 @@ package native import ( "fmt" "os" + "os/exec" "path/filepath" "github.com/dotcloud/docker/daemon/execdriver" @@ -46,7 +47,11 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container if err := d.setupLabels(container, c); err != nil { return nil, err } - if err := configuration.ParseConfiguration(container, d.activeContainers, c.Config["native"]); err != nil { + cmds := make(map[string]*exec.Cmd) + for k, v := range d.activeContainers { + cmds[k] = v.cmd + } + if err := configuration.ParseConfiguration(container, cmds, c.Config["native"]); err != nil { return nil, err } return container, nil @@ -82,10 +87,12 @@ func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver. } if c.Network.ContainerID != "" { - cmd := d.activeContainers[c.Network.ContainerID] - if cmd == nil || cmd.Process == nil { + active := d.activeContainers[c.Network.ContainerID] + if active == nil || active.cmd.Process == nil { return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) } + cmd := active.cmd + nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net") container.Networks = append(container.Networks, &libcontainer.Network{ Type: "netns", diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 59d193ed00..425403fa4e 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -7,14 +7,14 @@ import ( "os" "os/exec" "path/filepath" - "strconv" "strings" "syscall" "github.com/dotcloud/docker/daemon/execdriver" "github.com/dotcloud/docker/pkg/apparmor" "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/libcontainer/cgroups" + "github.com/dotcloud/docker/pkg/libcontainer/cgroups/fs" + "github.com/dotcloud/docker/pkg/libcontainer/cgroups/systemd" "github.com/dotcloud/docker/pkg/libcontainer/nsinit" "github.com/dotcloud/docker/pkg/system" ) @@ -53,24 +53,31 @@ func init() { }) } +type activeContainer struct { + container *libcontainer.Container + cmd *exec.Cmd +} + type driver struct { root string initPath string - activeContainers map[string]*exec.Cmd + activeContainers map[string]*activeContainer } func NewDriver(root, initPath string) (*driver, error) { if err := os.MkdirAll(root, 0700); err != nil { return nil, err } + // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(filepath.Join(root, "../..", BackupApparmorProfilePath)); err != nil { return nil, err } + return &driver{ root: root, initPath: initPath, - activeContainers: make(map[string]*exec.Cmd), + activeContainers: make(map[string]*activeContainer), }, nil } @@ -80,7 +87,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba if err != nil { return -1, err } - d.activeContainers[c.ID] = &c.Cmd + d.activeContainers[c.ID] = &activeContainer{ + container: container, + cmd: &c.Cmd, + } var ( dataPath = filepath.Join(d.root, c.ID) @@ -175,41 +185,18 @@ func (d *driver) Name() string { return fmt.Sprintf("%s-%s", DriverName, Version) } -// TODO: this can be improved with our driver -// there has to be a better way to do this func (d *driver) GetPidsForContainer(id string) ([]int, error) { - pids := []int{} + active := d.activeContainers[id] - subsystem := "devices" - cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem) - if err != nil { - return pids, err - } - cgroupDir, err := cgroups.GetThisCgroupDir(subsystem) - if err != nil { - return pids, err + if active == nil { + return nil, fmt.Errorf("active container for %s does not exist", id) } + c := active.container.Cgroups - filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks") - if _, err := os.Stat(filename); os.IsNotExist(err) { - filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks") + if systemd.UseSystemd() { + return systemd.GetPids(c) } - - output, err := ioutil.ReadFile(filename) - if err != nil { - return pids, err - } - for _, p := range strings.Split(string(output), "\n") { - if len(p) == 0 { - continue - } - pid, err := strconv.Atoi(p) - if err != nil { - return pids, fmt.Errorf("Invalid pid '%s': %s", p, err) - } - pids = append(pids, pid) - } - return pids, nil + return fs.GetPids(c) } func (d *driver) writeContainerFile(container *libcontainer.Container, id string) error { @@ -225,6 +212,8 @@ func (d *driver) createContainerRoot(id string) error { } func (d *driver) removeContainerRoot(id string) error { + delete(d.activeContainers, id) + return os.RemoveAll(filepath.Join(d.root, id)) } diff --git a/pkg/libcontainer/cgroups/fs/apply_raw.go b/pkg/libcontainer/cgroups/fs/apply_raw.go index 65aabcc52b..fd52c6074a 100644 --- a/pkg/libcontainer/cgroups/fs/apply_raw.go +++ b/pkg/libcontainer/cgroups/fs/apply_raw.go @@ -103,6 +103,36 @@ func GetStats(c *cgroups.Cgroup, subsystem string, pid int) (map[string]float64, return sys.Stats(d) } +func GetPids(c *cgroups.Cgroup) ([]int, 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("cgroup root %s not found", cgroupRoot) + } + + cgroup := c.Name + if c.Parent != "" { + cgroup = filepath.Join(c.Parent, cgroup) + } + + d := &data{ + root: cgroupRoot, + cgroup: cgroup, + c: c, + } + + dir, err := d.path("devices") + if err != nil { + return nil, err + } + + return cgroups.ReadProcsFile(dir) +} + func (raw *data) parent(subsystem string) (string, error) { initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { diff --git a/pkg/libcontainer/cgroups/fs/devices.go b/pkg/libcontainer/cgroups/fs/devices.go index a2f91eda14..fd9a39d9b9 100644 --- a/pkg/libcontainer/cgroups/fs/devices.go +++ b/pkg/libcontainer/cgroups/fs/devices.go @@ -1,9 +1,5 @@ package fs -import ( - "os" -) - type devicesGroup struct { } @@ -12,11 +8,6 @@ func (s *devicesGroup) Set(d *data) error { 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 { diff --git a/pkg/libcontainer/cgroups/systemd/apply_nosystemd.go b/pkg/libcontainer/cgroups/systemd/apply_nosystemd.go index 302fab773b..0fff3e4c6b 100644 --- a/pkg/libcontainer/cgroups/systemd/apply_nosystemd.go +++ b/pkg/libcontainer/cgroups/systemd/apply_nosystemd.go @@ -12,6 +12,10 @@ func UseSystemd() bool { return false } -func Apply(c *Cgroup, pid int) (cgroups.ActiveCgroup, error) { +func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { + return nil, fmt.Errorf("Systemd not supported") +} + +func GetPids(c *cgroups.Cgroup) ([]int, error) { return nil, fmt.Errorf("Systemd not supported") } diff --git a/pkg/libcontainer/cgroups/systemd/apply_systemd.go b/pkg/libcontainer/cgroups/systemd/apply_systemd.go index 4d6b68b2cd..0f6beb658e 100644 --- a/pkg/libcontainer/cgroups/systemd/apply_systemd.go +++ b/pkg/libcontainer/cgroups/systemd/apply_systemd.go @@ -3,6 +3,7 @@ package systemd import ( + "fmt" "io/ioutil" "os" "path/filepath" @@ -78,7 +79,7 @@ type cgroupArg struct { func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { var ( - unitName = c.Parent + "-" + c.Name + ".scope" + unitName = getUnitName(c) slice = "system.slice" properties []systemd1.Property cpuArgs []cgroupArg @@ -303,3 +304,24 @@ func (c *systemdCgroup) Cleanup() error { return nil } + +func GetPids(c *cgroups.Cgroup) ([]int, error) { + unitName := getUnitName(c) + + mountpoint, err := cgroups.FindCgroupMountpoint("cpu") + if err != nil { + return nil, err + } + + props, err := theConn.GetUnitTypeProperties(unitName, getIfaceForUnit(unitName)) + if err != nil { + return nil, err + } + cgroup := props["ControlGroup"].(string) + + return cgroups.ReadProcsFile(filepath.Join(mountpoint, cgroup)) +} + +func getUnitName(c *cgroups.Cgroup) string { + return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name) +} diff --git a/pkg/libcontainer/cgroups/utils.go b/pkg/libcontainer/cgroups/utils.go index 02a7f357f6..111c871477 100644 --- a/pkg/libcontainer/cgroups/utils.go +++ b/pkg/libcontainer/cgroups/utils.go @@ -4,6 +4,8 @@ import ( "bufio" "io" "os" + "path/filepath" + "strconv" "strings" "github.com/dotcloud/docker/pkg/mount" @@ -49,6 +51,30 @@ func GetInitCgroupDir(subsystem string) (string, error) { return parseCgroupFile(subsystem, f) } +func ReadProcsFile(dir string) ([]int, error) { + f, err := os.Open(filepath.Join(dir, "cgroup.procs")) + if err != nil { + return nil, err + } + defer f.Close() + + var ( + s = bufio.NewScanner(f) + out = []int{} + ) + + for s.Scan() { + if t := s.Text(); t != "" { + pid, err := strconv.Atoi(t) + if err != nil { + return nil, err + } + out = append(out, pid) + } + } + return out, nil +} + func parseCgroupFile(subsystem string, r io.Reader) (string, error) { s := bufio.NewScanner(r) for s.Scan() {