Browse code

Move get pid into cgroup implementation Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/05/22 05:48:06
Showing 7 changed files
... ...
@@ -3,6 +3,7 @@ package native
3 3
 import (
4 4
 	"fmt"
5 5
 	"os"
6
+	"os/exec"
6 7
 	"path/filepath"
7 8
 
8 9
 	"github.com/dotcloud/docker/daemon/execdriver"
... ...
@@ -46,7 +47,11 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container
46 46
 	if err := d.setupLabels(container, c); err != nil {
47 47
 		return nil, err
48 48
 	}
49
-	if err := configuration.ParseConfiguration(container, d.activeContainers, c.Config["native"]); err != nil {
49
+	cmds := make(map[string]*exec.Cmd)
50
+	for k, v := range d.activeContainers {
51
+		cmds[k] = v.cmd
52
+	}
53
+	if err := configuration.ParseConfiguration(container, cmds, c.Config["native"]); err != nil {
50 54
 		return nil, err
51 55
 	}
52 56
 	return container, nil
... ...
@@ -82,10 +87,12 @@ func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver.
82 82
 	}
83 83
 
84 84
 	if c.Network.ContainerID != "" {
85
-		cmd := d.activeContainers[c.Network.ContainerID]
86
-		if cmd == nil || cmd.Process == nil {
85
+		active := d.activeContainers[c.Network.ContainerID]
86
+		if active == nil || active.cmd.Process == nil {
87 87
 			return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
88 88
 		}
89
+		cmd := active.cmd
90
+
89 91
 		nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
90 92
 		container.Networks = append(container.Networks, &libcontainer.Network{
91 93
 			Type: "netns",
... ...
@@ -7,14 +7,14 @@ import (
7 7
 	"os"
8 8
 	"os/exec"
9 9
 	"path/filepath"
10
-	"strconv"
11 10
 	"strings"
12 11
 	"syscall"
13 12
 
14 13
 	"github.com/dotcloud/docker/daemon/execdriver"
15 14
 	"github.com/dotcloud/docker/pkg/apparmor"
16 15
 	"github.com/dotcloud/docker/pkg/libcontainer"
17
-	"github.com/dotcloud/docker/pkg/libcontainer/cgroups"
16
+	"github.com/dotcloud/docker/pkg/libcontainer/cgroups/fs"
17
+	"github.com/dotcloud/docker/pkg/libcontainer/cgroups/systemd"
18 18
 	"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
19 19
 	"github.com/dotcloud/docker/pkg/system"
20 20
 )
... ...
@@ -53,24 +53,31 @@ func init() {
53 53
 	})
54 54
 }
55 55
 
56
+type activeContainer struct {
57
+	container *libcontainer.Container
58
+	cmd       *exec.Cmd
59
+}
60
+
56 61
 type driver struct {
57 62
 	root             string
58 63
 	initPath         string
59
-	activeContainers map[string]*exec.Cmd
64
+	activeContainers map[string]*activeContainer
60 65
 }
61 66
 
62 67
 func NewDriver(root, initPath string) (*driver, error) {
63 68
 	if err := os.MkdirAll(root, 0700); err != nil {
64 69
 		return nil, err
65 70
 	}
71
+
66 72
 	// native driver root is at docker_root/execdriver/native. Put apparmor at docker_root
67 73
 	if err := apparmor.InstallDefaultProfile(filepath.Join(root, "../..", BackupApparmorProfilePath)); err != nil {
68 74
 		return nil, err
69 75
 	}
76
+
70 77
 	return &driver{
71 78
 		root:             root,
72 79
 		initPath:         initPath,
73
-		activeContainers: make(map[string]*exec.Cmd),
80
+		activeContainers: make(map[string]*activeContainer),
74 81
 	}, nil
75 82
 }
76 83
 
... ...
@@ -80,7 +87,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
80 80
 	if err != nil {
81 81
 		return -1, err
82 82
 	}
83
-	d.activeContainers[c.ID] = &c.Cmd
83
+	d.activeContainers[c.ID] = &activeContainer{
84
+		container: container,
85
+		cmd:       &c.Cmd,
86
+	}
84 87
 
85 88
 	var (
86 89
 		dataPath = filepath.Join(d.root, c.ID)
... ...
@@ -175,41 +185,18 @@ func (d *driver) Name() string {
175 175
 	return fmt.Sprintf("%s-%s", DriverName, Version)
176 176
 }
177 177
 
178
-// TODO: this can be improved with our driver
179
-// there has to be a better way to do this
180 178
 func (d *driver) GetPidsForContainer(id string) ([]int, error) {
181
-	pids := []int{}
182
-
183
-	subsystem := "devices"
184
-	cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
185
-	if err != nil {
186
-		return pids, err
187
-	}
188
-	cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
189
-	if err != nil {
190
-		return pids, err
191
-	}
179
+	active := d.activeContainers[id]
192 180
 
193
-	filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
194
-	if _, err := os.Stat(filename); os.IsNotExist(err) {
195
-		filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks")
181
+	if active == nil {
182
+		return nil, fmt.Errorf("active container for %s does not exist", id)
196 183
 	}
184
+	c := active.container.Cgroups
197 185
 
198
-	output, err := ioutil.ReadFile(filename)
199
-	if err != nil {
200
-		return pids, err
201
-	}
202
-	for _, p := range strings.Split(string(output), "\n") {
203
-		if len(p) == 0 {
204
-			continue
205
-		}
206
-		pid, err := strconv.Atoi(p)
207
-		if err != nil {
208
-			return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
209
-		}
210
-		pids = append(pids, pid)
186
+	if systemd.UseSystemd() {
187
+		return systemd.GetPids(c)
211 188
 	}
212
-	return pids, nil
189
+	return fs.GetPids(c)
213 190
 }
214 191
 
215 192
 func (d *driver) writeContainerFile(container *libcontainer.Container, id string) error {
... ...
@@ -225,6 +212,8 @@ func (d *driver) createContainerRoot(id string) error {
225 225
 }
226 226
 
227 227
 func (d *driver) removeContainerRoot(id string) error {
228
+	delete(d.activeContainers, id)
229
+
228 230
 	return os.RemoveAll(filepath.Join(d.root, id))
229 231
 }
230 232
 
... ...
@@ -103,6 +103,36 @@ func GetStats(c *cgroups.Cgroup, subsystem string, pid int) (map[string]float64,
103 103
 	return sys.Stats(d)
104 104
 }
105 105
 
106
+func GetPids(c *cgroups.Cgroup) ([]int, error) {
107
+	cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
108
+	if err != nil {
109
+		return nil, err
110
+	}
111
+	cgroupRoot = filepath.Dir(cgroupRoot)
112
+
113
+	if _, err := os.Stat(cgroupRoot); err != nil {
114
+		return nil, fmt.Errorf("cgroup root %s not found", cgroupRoot)
115
+	}
116
+
117
+	cgroup := c.Name
118
+	if c.Parent != "" {
119
+		cgroup = filepath.Join(c.Parent, cgroup)
120
+	}
121
+
122
+	d := &data{
123
+		root:   cgroupRoot,
124
+		cgroup: cgroup,
125
+		c:      c,
126
+	}
127
+
128
+	dir, err := d.path("devices")
129
+	if err != nil {
130
+		return nil, err
131
+	}
132
+
133
+	return cgroups.ReadProcsFile(dir)
134
+}
135
+
106 136
 func (raw *data) parent(subsystem string) (string, error) {
107 137
 	initPath, err := cgroups.GetInitCgroupDir(subsystem)
108 138
 	if err != nil {
... ...
@@ -1,9 +1,5 @@
1 1
 package fs
2 2
 
3
-import (
4
-	"os"
5
-)
6
-
7 3
 type devicesGroup struct {
8 4
 }
9 5
 
... ...
@@ -12,11 +8,6 @@ func (s *devicesGroup) Set(d *data) error {
12 12
 	if err != nil {
13 13
 		return err
14 14
 	}
15
-	defer func() {
16
-		if err != nil {
17
-			os.RemoveAll(dir)
18
-		}
19
-	}()
20 15
 
21 16
 	if !d.c.DeviceAccess {
22 17
 		if err := writeFile(dir, "devices.deny", "a"); err != nil {
... ...
@@ -12,6 +12,10 @@ func UseSystemd() bool {
12 12
 	return false
13 13
 }
14 14
 
15
-func Apply(c *Cgroup, pid int) (cgroups.ActiveCgroup, error) {
15
+func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
16
+	return nil, fmt.Errorf("Systemd not supported")
17
+}
18
+
19
+func GetPids(c *cgroups.Cgroup) ([]int, error) {
16 20
 	return nil, fmt.Errorf("Systemd not supported")
17 21
 }
... ...
@@ -3,6 +3,7 @@
3 3
 package systemd
4 4
 
5 5
 import (
6
+	"fmt"
6 7
 	"io/ioutil"
7 8
 	"os"
8 9
 	"path/filepath"
... ...
@@ -78,7 +79,7 @@ type cgroupArg struct {
78 78
 
79 79
 func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
80 80
 	var (
81
-		unitName   = c.Parent + "-" + c.Name + ".scope"
81
+		unitName   = getUnitName(c)
82 82
 		slice      = "system.slice"
83 83
 		properties []systemd1.Property
84 84
 		cpuArgs    []cgroupArg
... ...
@@ -303,3 +304,24 @@ func (c *systemdCgroup) Cleanup() error {
303 303
 
304 304
 	return nil
305 305
 }
306
+
307
+func GetPids(c *cgroups.Cgroup) ([]int, error) {
308
+	unitName := getUnitName(c)
309
+
310
+	mountpoint, err := cgroups.FindCgroupMountpoint("cpu")
311
+	if err != nil {
312
+		return nil, err
313
+	}
314
+
315
+	props, err := theConn.GetUnitTypeProperties(unitName, getIfaceForUnit(unitName))
316
+	if err != nil {
317
+		return nil, err
318
+	}
319
+	cgroup := props["ControlGroup"].(string)
320
+
321
+	return cgroups.ReadProcsFile(filepath.Join(mountpoint, cgroup))
322
+}
323
+
324
+func getUnitName(c *cgroups.Cgroup) string {
325
+	return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name)
326
+}
... ...
@@ -4,6 +4,8 @@ import (
4 4
 	"bufio"
5 5
 	"io"
6 6
 	"os"
7
+	"path/filepath"
8
+	"strconv"
7 9
 	"strings"
8 10
 
9 11
 	"github.com/dotcloud/docker/pkg/mount"
... ...
@@ -49,6 +51,30 @@ func GetInitCgroupDir(subsystem string) (string, error) {
49 49
 	return parseCgroupFile(subsystem, f)
50 50
 }
51 51
 
52
+func ReadProcsFile(dir string) ([]int, error) {
53
+	f, err := os.Open(filepath.Join(dir, "cgroup.procs"))
54
+	if err != nil {
55
+		return nil, err
56
+	}
57
+	defer f.Close()
58
+
59
+	var (
60
+		s   = bufio.NewScanner(f)
61
+		out = []int{}
62
+	)
63
+
64
+	for s.Scan() {
65
+		if t := s.Text(); t != "" {
66
+			pid, err := strconv.Atoi(t)
67
+			if err != nil {
68
+				return nil, err
69
+			}
70
+			out = append(out, pid)
71
+		}
72
+	}
73
+	return out, nil
74
+}
75
+
52 76
 func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
53 77
 	s := bufio.NewScanner(r)
54 78
 	for s.Scan() {