Merge pull request #253 from avagin/cr-cgroups

c/r: create cgroups to restore a container
This commit is contained in:
Mrunal Patel 2015-09-11 18:03:40 -07:00
commit ef9471fd5b
4 changed files with 74 additions and 35 deletions

View File

@ -3,27 +3,16 @@
package cgroups package cgroups
import ( import (
"bytes"
"testing" "testing"
) )
const (
cgroupsContents = `11:hugetlb:/
10:perf_event:/
9:blkio:/
8:net_cls:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct,cpu:/
3:cpuset:/
2:name=systemd:/user.slice/user-1000.slice/session-16.scope`
)
func TestParseCgroups(t *testing.T) { func TestParseCgroups(t *testing.T) {
r := bytes.NewBuffer([]byte(cgroupsContents)) cgroups, err := ParseCgroupFile("/proc/self/cgroup")
_, err := ParseCgroupFile("blkio", r)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, ok := cgroups["cpu"]; !ok {
t.Fail()
}
} }

View File

@ -5,7 +5,6 @@ package cgroups
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -105,12 +104,12 @@ type Mount struct {
Subsystems []string Subsystems []string
} }
func (m Mount) GetThisCgroupDir() (string, error) { func (m Mount) GetThisCgroupDir(cgroups map[string]string) (string, error) {
if len(m.Subsystems) == 0 { if len(m.Subsystems) == 0 {
return "", fmt.Errorf("no subsystem for mount") return "", fmt.Errorf("no subsystem for mount")
} }
return GetThisCgroupDir(m.Subsystems[0]) return getControllerPath(m.Subsystems[0], cgroups)
} }
func GetCgroupMounts() ([]Mount, error) { func GetCgroupMounts() ([]Mount, error) {
@ -176,23 +175,22 @@ func GetAllSubsystems() ([]string, error) {
// Returns the relative path to the cgroup docker is running in. // Returns the relative path to the cgroup docker is running in.
func GetThisCgroupDir(subsystem string) (string, error) { func GetThisCgroupDir(subsystem string) (string, error) {
f, err := os.Open("/proc/self/cgroup") cgroups, err := ParseCgroupFile("/proc/self/cgroup")
if err != nil { if err != nil {
return "", err return "", err
} }
defer f.Close()
return ParseCgroupFile(subsystem, f) return getControllerPath(subsystem, cgroups)
} }
func GetInitCgroupDir(subsystem string) (string, error) { func GetInitCgroupDir(subsystem string) (string, error) {
f, err := os.Open("/proc/1/cgroup")
cgroups, err := ParseCgroupFile("/proc/1/cgroup")
if err != nil { if err != nil {
return "", err return "", err
} }
defer f.Close()
return ParseCgroupFile(subsystem, f) return getControllerPath(subsystem, cgroups)
} }
func ReadProcsFile(dir string) ([]int, error) { func ReadProcsFile(dir string) ([]int, error) {
@ -219,23 +217,40 @@ func ReadProcsFile(dir string) ([]int, error) {
return out, nil return out, nil
} }
func ParseCgroupFile(subsystem string, r io.Reader) (string, error) { func ParseCgroupFile(path string) (map[string]string, error) {
s := bufio.NewScanner(r) f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
s := bufio.NewScanner(f)
cgroups := make(map[string]string)
for s.Scan() { for s.Scan() {
if err := s.Err(); err != nil { if err := s.Err(); err != nil {
return "", err return nil, err
} }
text := s.Text() text := s.Text()
parts := strings.Split(text, ":") parts := strings.Split(text, ":")
for _, subs := range strings.Split(parts[1], ",") { for _, subs := range strings.Split(parts[1], ",") {
if subs == subsystem || subs == cgroupNamePrefix+subsystem { cgroups[subs] = parts[2]
return parts[2], nil
}
} }
} }
return cgroups, nil
}
func getControllerPath(subsystem string, cgroups map[string]string) (string, error) {
if p, ok := cgroups[subsystem]; ok {
return p, nil
}
if p, ok := cgroups[cgroupNamePrefix+subsystem]; ok {
return p, nil
}
return "", NewNotFoundError(subsystem) return "", NewNotFoundError(subsystem)
} }

View File

@ -423,7 +423,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
return err return err
} }
err = c.criuSwrk(nil, req, criuOpts) err = c.criuSwrk(nil, req, criuOpts, false)
if err != nil { if err != nil {
return err return err
} }
@ -516,6 +516,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
FileLocks: proto.Bool(criuOpts.FileLocks), FileLocks: proto.Bool(criuOpts.FileLocks),
}, },
} }
for _, m := range c.config.Mounts { for _, m := range c.config.Mounts {
switch m.Device { switch m.Device {
case "bind": case "bind":
@ -573,14 +574,36 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
} }
} }
err = c.criuSwrk(process, req, criuOpts) err = c.criuSwrk(process, req, criuOpts, true)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts) error { func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
if err := c.cgroupManager.Apply(pid); err != nil {
return err
}
path := fmt.Sprintf("/proc/%d/cgroup", pid)
cgroupsPaths, err := cgroups.ParseCgroupFile(path)
if err != nil {
return err
}
for c, p := range cgroupsPaths {
cgroupRoot := &criurpc.CgroupRoot{
Ctrl: proto.String(c),
Path: proto.String(p),
}
req.Opts.CgRoot = append(req.Opts.CgRoot, cgroupRoot)
}
return nil
}
func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, applyCgroups bool) error {
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET|syscall.SOCK_CLOEXEC, 0) fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET|syscall.SOCK_CLOEXEC, 0)
if err != nil { if err != nil {
return err return err
@ -614,6 +637,13 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
} }
}() }()
if applyCgroups {
err := c.criuApplyCgroups(cmd.Process.Pid, req)
if err != nil {
return err
}
}
var extFds []string var extFds []string
if process != nil { if process != nil {
extFds, err = getPipeFds(cmd.Process.Pid) extFds, err = getPipeFds(cmd.Process.Pid)

View File

@ -253,10 +253,15 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
return nil, err return nil, err
} }
cgroupPaths, err := cgroups.ParseCgroupFile("/proc/self/cgroup")
if err != nil {
return nil, err
}
var binds []*configs.Mount var binds []*configs.Mount
for _, mm := range mounts { for _, mm := range mounts {
dir, err := mm.GetThisCgroupDir() dir, err := mm.GetThisCgroupDir(cgroupPaths)
if err != nil { if err != nil {
return nil, err return nil, err
} }