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:
parent
6940d0ea85
commit
ae64fd1e58
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue