| ... | ... |
@@ -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() {
|