Enter cgroups while entering namespaces as part of NsEnter.

Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh)
This commit is contained in:
Vishnu Kannan 2014-08-05 22:12:28 +00:00
parent 6940d0ea85
commit ae64fd1e58
11 changed files with 143 additions and 3 deletions

View File

@ -21,12 +21,15 @@ var (
"perf_event": &PerfEventGroup{},
"freezer": &FreezerGroup{},
}
cgroupProcesses = "cgroup.procs"
)
type subsystem interface {
Set(*data) error
Remove(*data) error
Active(d *data) (bool, error)
Enter(string, string) error
GetStats(string, *cgroups.Stats) error
Remove(*data) error
Set(*data) error
}
type data struct {
@ -116,6 +119,36 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) {
return cgroups.ReadProcsFile(dir)
}
func EnterPid(c *cgroups.Cgroup, pid int) error {
d, err := getCgroupData(c, 0)
if err != nil {
return err
}
for sysname, sys := range subsystems {
active, err := sys.Active(d)
if err != nil {
return err
}
if !active {
continue
}
path, err := d.path(sysname)
if err != nil {
// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
if err == cgroups.ErrNotFound {
continue
}
return err
}
if err := sys.Enter(path, strconv.FormatInt(int64(pid), 10)); err != nil {
return err
}
}
return nil
}
func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) {
// we can pick any subsystem to find the root
cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")

View File

@ -139,3 +139,12 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *BlkioGroup) Active(d *data) (bool, error) {
return true, nil
}
func (s *BlkioGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -70,3 +70,18 @@ func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error {
}
return nil
}
func (s *CpuGroup) Active(d *data) (bool, error) {
dir, err := d.path("cpu")
if err != nil {
return false, err
}
if FileExists(dir) {
return true, nil
}
return false, nil
}
func (s *CpuGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -161,3 +161,11 @@ func getPercpuUsage(path string) ([]uint64, error) {
}
return percpuUsage, nil
}
func (s *CpuacctGroup) Active(d *data) (bool, error) {
return true, nil
}
func (s *CpuacctGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -108,3 +108,20 @@ func (s *CpusetGroup) copyIfNeeded(current, parent string) error {
func (s *CpusetGroup) isEmpty(b []byte) bool {
return len(bytes.Trim(b, "\n")) == 0
}
func (s *CpusetGroup) Active(d *data) (bool, error) {
if d.c.CpusetCpus != "" {
dir, err := d.path("cpuset")
if err != nil {
return false, err
}
if FileExists(dir) {
return true, nil
}
}
return false, nil
}
func (s *CpusetGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -32,3 +32,11 @@ func (s *DevicesGroup) Remove(d *data) error {
func (s *DevicesGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *DevicesGroup) Active(d *data) (bool, error) {
return true, nil
}
func (s *DevicesGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -48,3 +48,12 @@ func (s *FreezerGroup) Remove(d *data) error {
func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *FreezerGroup) Active(d *data) (bool, error) {
return true, nil
}
func (s *FreezerGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -14,7 +14,7 @@ type MemoryGroup struct {
func (s *MemoryGroup) Set(d *data) error {
dir, err := d.join("memory")
// only return an error for memory if it was not specified
// only return an error for memory if it was specified
if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
return err
}
@ -90,3 +90,19 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *MemoryGroup) Active(d *data) (bool, error) {
dir, err := d.path("memory")
if err != nil {
return false, err
}
if FileExists(dir) {
return true, nil
}
return false, nil
}
func (s *MemoryGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -22,3 +22,11 @@ func (s *PerfEventGroup) Remove(d *data) error {
func (s *PerfEventGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *PerfEventGroup) Active(d *data) (bool, error) {
return true, nil
}
func (s *PerfEventGroup) Enter(path, pid string) error {
return writeFile(path, cgroupProcesses, pid)
}

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
@ -38,3 +39,10 @@ func getCgroupParamInt(cgroupPath, cgroupFile string) (uint64, error) {
}
return strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64)
}
func FileExists(path string) bool {
if _, err := os.Stat(path); err == nil {
return true
}
return false
}

View File

@ -12,6 +12,7 @@ import (
"syscall"
"github.com/docker/libcontainer"
"github.com/docker/libcontainer/cgroups/fs"
"github.com/docker/libcontainer/label"
"github.com/docker/libcontainer/syncpipe"
"github.com/docker/libcontainer/system"
@ -21,6 +22,10 @@ import (
// setns code in a single threaded environment joining the existing containers' namespaces.
func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs []string, initPath, action string,
stdin io.Reader, stdout, stderr io.Writer, console string, startCallback func(*exec.Cmd)) (int, error) {
// Enter cgroups.
if err := EnterCgroups(container); err != nil {
return err
}
args := []string{fmt.Sprintf("nsenter-%s", action), "--nspid", strconv.Itoa(state.InitPid)}
@ -102,3 +107,7 @@ func FinalizeSetns(container *libcontainer.Config, args []string) error {
panic("unreachable")
}
func EnterCgroups(container *libcontainer.Config) error {
return fs.EnterPid(container.Cgroups, os.Getpid())
}