浏览代码

Merge pull request #6125 from crosbymichael/systemd-freezer

Implement systemd support for freezer
Victor Vieux 11 年之前
父节点
当前提交
2f514fb891

+ 10 - 3
pkg/libcontainer/cgroups/cgroups.go

@@ -10,6 +10,14 @@ var (
 	ErrNotFound = errors.New("mountpoint not found")
 )
 
+type FreezerState string
+
+const (
+	Undefined FreezerState = ""
+	Frozen    FreezerState = "FROZEN"
+	Thawed    FreezerState = "THAWED"
+)
+
 type Cgroup struct {
 	Name   string `json:"name,omitempty"`
 	Parent string `json:"parent,omitempty"` // name of parent cgroup or slice
@@ -23,9 +31,8 @@ type Cgroup struct {
 	CpuQuota          int64             `json:"cpu_quota,omitempty"`          // CPU hardcap limit (in usecs). Allowed cpu time in a given period.
 	CpuPeriod         int64             `json:"cpu_period,omitempty"`         // CPU period to be used for hardcapping (in usecs). 0 to use system default.
 	CpusetCpus        string            `json:"cpuset_cpus,omitempty"`        // CPU to use
-	Freezer           string            `json:"freezer,omitempty"`            // set the freeze value for the process
-
-	Slice string `json:"slice,omitempty"` // Parent slice to use for systemd
+	Freezer           FreezerState      `json:"freezer,omitempty"`            // set the freeze value for the process
+	Slice             string            `json:"slice,omitempty"`              // Parent slice to use for systemd
 }
 
 type ActiveCgroup interface {

+ 38 - 51
pkg/libcontainer/cgroups/fs/apply_raw.go

@@ -37,65 +37,28 @@ type data struct {
 }
 
 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:
-	// http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups/
-	//
-	// we can pick any subsystem to find the root
-
-	cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
+	d, err := getCgroupData(c, pid)
 	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,
-	}
 	for _, sys := range subsystems {
 		if err := sys.Set(d); err != nil {
 			d.Cleanup()
 			return nil, err
 		}
 	}
+
 	return d, nil
 }
 
 func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) {
 	stats := cgroups.NewStats()
-	cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
+
+	d, err := getCgroupData(c, 0)
 	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,
-	}
 
 	for _, sys := range subsystems {
 		if err := sys.GetStats(d, stats); err != nil {
@@ -106,7 +69,37 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) {
 	return stats, nil
 }
 
+// Freeze toggles the container's freezer cgroup depending on the state
+// provided
+func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error {
+	d, err := getCgroupData(c, 0)
+	if err != nil {
+		return err
+	}
+
+	c.Freezer = state
+
+	freezer := subsystems["freezer"]
+
+	return freezer.Set(d)
+}
+
 func GetPids(c *cgroups.Cgroup) ([]int, error) {
+	d, err := getCgroupData(c, 0)
+	if err != nil {
+		return nil, err
+	}
+
+	dir, err := d.path("devices")
+	if err != nil {
+		return nil, err
+	}
+
+	return cgroups.ReadProcsFile(dir)
+}
+
+func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) {
+	// we can pick any subsystem to find the root
 	cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
 	if err != nil {
 		return nil, err
@@ -114,7 +107,7 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) {
 	cgroupRoot = filepath.Dir(cgroupRoot)
 
 	if _, err := os.Stat(cgroupRoot); err != nil {
-		return nil, fmt.Errorf("cgroup root %s not found", cgroupRoot)
+		return nil, fmt.Errorf("cgroups fs not found")
 	}
 
 	cgroup := c.Name
@@ -122,18 +115,12 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) {
 		cgroup = filepath.Join(c.Parent, cgroup)
 	}
 
-	d := &data{
+	return &data{
 		root:   cgroupRoot,
 		cgroup: cgroup,
 		c:      c,
-	}
-
-	dir, err := d.path("devices")
-	if err != nil {
-		return nil, err
-	}
-
-	return cgroups.ReadProcsFile(dir)
+		pid:    pid,
+	}, nil
 }
 
 func (raw *data) parent(subsystem string) (string, error) {

+ 3 - 2
pkg/libcontainer/cgroups/fs/freezer.go

@@ -20,11 +20,12 @@ func (s *freezerGroup) Set(d *data) error {
 		return nil
 	}
 
-	if d.c.Freezer != "" {
-		if err := writeFile(dir, "freezer.state", d.c.Freezer); err != nil {
+	if d.c.Freezer != cgroups.Undefined {
+		if err := writeFile(dir, "freezer.state", string(d.c.Freezer)); err != nil {
 			return err
 		}
 	}
+
 	return nil
 }
 

+ 4 - 0
pkg/libcontainer/cgroups/systemd/apply_nosystemd.go

@@ -19,3 +19,7 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 func GetPids(c *cgroups.Cgroup) ([]int, error) {
 	return nil, fmt.Errorf("Systemd not supported")
 }
+
+func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error {
+	return fmt.Errorf("Systemd not supported")
+}

+ 56 - 5
pkg/libcontainer/cgroups/systemd/apply_systemd.go

@@ -218,6 +218,14 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 		}
 	}
 
+	// we need to manually join the freezer cgroup in systemd because it does not currently support it
+	// via the dbus api
+	freezerPath, err := joinFreezer(c, pid)
+	if err != nil {
+		return nil, err
+	}
+	res.cleanupDirs = append(res.cleanupDirs, freezerPath)
+
 	if len(cpusetArgs) != 0 {
 		// systemd does not atm set up the cpuset controller, so we must manually
 		// join it. Additionally that is a very finicky controller where each
@@ -227,14 +235,19 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 		if err != nil {
 			return nil, err
 		}
+
 		initPath, err := cgroups.GetInitCgroupDir("cpuset")
 		if err != nil {
 			return nil, err
 		}
 
-		rootPath := filepath.Join(mountpoint, initPath)
+		var (
+			foundCpus bool
+			foundMems bool
 
-		path := filepath.Join(mountpoint, initPath, c.Parent+"-"+c.Name)
+			rootPath = filepath.Join(mountpoint, initPath)
+			path     = filepath.Join(mountpoint, initPath, c.Parent+"-"+c.Name)
+		)
 
 		res.cleanupDirs = append(res.cleanupDirs, path)
 
@@ -242,9 +255,6 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
 			return nil, err
 		}
 
-		foundCpus := false
-		foundMems := false
-
 		for _, arg := range cpusetArgs {
 			if arg.File == "cpuset.cpus" {
 				foundCpus = true
@@ -303,6 +313,47 @@ func (c *systemdCgroup) Cleanup() error {
 	return nil
 }
 
+func joinFreezer(c *cgroups.Cgroup, pid int) (string, error) {
+	path, err := getFreezerPath(c)
+	if err != nil {
+		return "", err
+	}
+
+	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+		return "", err
+	}
+
+	if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
+		return "", err
+	}
+
+	return path, nil
+}
+
+func getFreezerPath(c *cgroups.Cgroup) (string, error) {
+	mountpoint, err := cgroups.FindCgroupMountpoint("freezer")
+	if err != nil {
+		return "", err
+	}
+
+	initPath, err := cgroups.GetInitCgroupDir("freezer")
+	if err != nil {
+		return "", err
+	}
+
+	return filepath.Join(mountpoint, initPath, fmt.Sprintf("%s-%s", c.Parent, c.Name)), nil
+
+}
+
+func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error {
+	path, err := getFreezerPath(c)
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(filepath.Join(path, "freezer.state"), []byte(state), 0)
+}
+
 func GetPids(c *cgroups.Cgroup) ([]int, error) {
 	unitName := getUnitName(c)