From ae08910fde5024a19a4f892c357c422faf1c5672 Mon Sep 17 00:00:00 2001 From: Vishnu Kannan Date: Tue, 5 Aug 2014 22:34:59 +0000 Subject: [PATCH] Enter cgroups as part of nsenter while using systemd. Docker-DCO-1.1-Signed-off-by: Vishnu Kannan (github: vishh) --- cgroups/fs/apply_raw.go | 32 +++++++++++++++----------------- cgroups/fs/blkio.go | 9 --------- cgroups/fs/cpu.go | 15 --------------- cgroups/fs/cpuacct.go | 8 -------- cgroups/fs/cpuset.go | 17 ----------------- cgroups/fs/devices.go | 8 -------- cgroups/fs/freezer.go | 9 --------- cgroups/fs/memory.go | 16 ---------------- cgroups/fs/perf_event.go | 8 -------- cgroups/fs/utils.go | 8 ++++---- cgroups/systemd/apply_systemd.go | 23 +++++++++++++++++++++++ namespaces/execin.go | 17 +++++++++++------ namespaces/nsenter/nsenter.c | 20 ++++++++++---------- 13 files changed, 63 insertions(+), 127 deletions(-) diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index 046740775..bf01df5dc 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -21,14 +21,15 @@ var ( "perf_event": &PerfEventGroup{}, "freezer": &FreezerGroup{}, } - cgroupProcesses = "cgroup.procs" + CgroupProcesses = "cgroup.procs" ) type subsystem interface { - Active(d *data) (bool, error) - Enter(string, string) error - GetStats(string, *cgroups.Stats) error + // Returns the stats, as 'stats', corresponding to the cgroup under 'path'. + GetStats(path string, stats *cgroups.Stats) error + // Removes the cgroup represented by 'data'. Remove(*data) error + // Creates and joins the cgroup represented by data. Set(*data) error } @@ -120,32 +121,29 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) { } func EnterPid(c *cgroups.Cgroup, pid int) error { - d, err := getCgroupData(c, 0) + d, err := getCgroupData(c, pid) if err != nil { return err } - for sysname, sys := range subsystems { - active, err := sys.Active(d) - if err != nil { - return err - } - if !active { - continue - } + for sysname := range subsystems { 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 + + if PathExists(path) { + if _, err := d.join(sysname); err != nil { + return err + } } } - + return nil } @@ -202,7 +200,7 @@ func (raw *data) join(subsystem string) (string, error) { if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { return "", err } - if err := writeFile(path, "cgroup.procs", strconv.Itoa(raw.pid)); err != nil { + if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil { return "", err } return path, nil diff --git a/cgroups/fs/blkio.go b/cgroups/fs/blkio.go index 11337c0ba..38b875772 100644 --- a/cgroups/fs/blkio.go +++ b/cgroups/fs/blkio.go @@ -139,12 +139,3 @@ 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) -} - diff --git a/cgroups/fs/cpu.go b/cgroups/fs/cpu.go index b51a7e426..efac9ed16 100644 --- a/cgroups/fs/cpu.go +++ b/cgroups/fs/cpu.go @@ -70,18 +70,3 @@ 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) -} diff --git a/cgroups/fs/cpuacct.go b/cgroups/fs/cpuacct.go index 00a64bd4b..7761d4c28 100644 --- a/cgroups/fs/cpuacct.go +++ b/cgroups/fs/cpuacct.go @@ -161,11 +161,3 @@ 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) -} diff --git a/cgroups/fs/cpuset.go b/cgroups/fs/cpuset.go index 8a4d769ca..9570125fd 100644 --- a/cgroups/fs/cpuset.go +++ b/cgroups/fs/cpuset.go @@ -108,20 +108,3 @@ 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) -} diff --git a/cgroups/fs/devices.go b/cgroups/fs/devices.go index aadd9016a..98d5d2d7d 100644 --- a/cgroups/fs/devices.go +++ b/cgroups/fs/devices.go @@ -32,11 +32,3 @@ 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) -} diff --git a/cgroups/fs/freezer.go b/cgroups/fs/freezer.go index 675aca8f5..db2a41ca3 100644 --- a/cgroups/fs/freezer.go +++ b/cgroups/fs/freezer.go @@ -48,12 +48,3 @@ 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) -} - diff --git a/cgroups/fs/memory.go b/cgroups/fs/memory.go index 9368a1508..ea92934a0 100644 --- a/cgroups/fs/memory.go +++ b/cgroups/fs/memory.go @@ -90,19 +90,3 @@ 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) -} diff --git a/cgroups/fs/perf_event.go b/cgroups/fs/perf_event.go index ba19ce8e2..5f45678ff 100644 --- a/cgroups/fs/perf_event.go +++ b/cgroups/fs/perf_event.go @@ -22,11 +22,3 @@ 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) -} diff --git a/cgroups/fs/utils.go b/cgroups/fs/utils.go index a2b679bed..b54a8b992 100644 --- a/cgroups/fs/utils.go +++ b/cgroups/fs/utils.go @@ -40,9 +40,9 @@ 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 +func PathExists(path string) bool { + if _, err := os.Stat(path); err != nil { + return false } - return false + return true } diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index 01e5bf49b..1849a8def 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -437,3 +437,26 @@ func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) { return stats, nil } + +func EnterPid(c *cgroups.Cgroup, pid int) error { + for sysname := range subsystems { + subsystemPath, err := getSubsystemPath(c, 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 fs.PathExists(subsystemPath) { + if err := ioutil.WriteFile(filepath.Join(subsystemPath, fs.CgroupProcesses), + []byte(strconv.Itoa(pid)), 0700); err != nil { + return err + } + } + } + + return nil +} diff --git a/namespaces/execin.go b/namespaces/execin.go index 44ac15bc5..1d1ac09ab 100644 --- a/namespaces/execin.go +++ b/namespaces/execin.go @@ -13,6 +13,7 @@ import ( "github.com/docker/libcontainer" "github.com/docker/libcontainer/cgroups/fs" + "github.com/docker/libcontainer/cgroups/systemd" "github.com/docker/libcontainer/label" "github.com/docker/libcontainer/syncpipe" "github.com/docker/libcontainer/system" @@ -22,10 +23,6 @@ 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)} @@ -64,6 +61,11 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs } pipe.CloseChild() + // Enter cgroups. + if err := EnterCgroups(container, cmd.Process.Pid); err != nil { + return -1, err + } + if err := pipe.SendToChild(container); err != nil { cmd.Process.Kill() cmd.Wait() @@ -108,6 +110,9 @@ func FinalizeSetns(container *libcontainer.Config, args []string) error { panic("unreachable") } -func EnterCgroups(container *libcontainer.Config) error { - return fs.EnterPid(container.Cgroups, os.Getpid()) +func EnterCgroups(container *libcontainer.Config, pid int) error { + if systemd.UseSystemd() { + return systemd.EnterPid(container.Cgroups, pid) + } + return fs.EnterPid(container.Cgroups, pid) } diff --git a/namespaces/nsenter/nsenter.c b/namespaces/nsenter/nsenter.c index 3bc29e2bc..2869dd14d 100644 --- a/namespaces/nsenter/nsenter.c +++ b/namespaces/nsenter/nsenter.c @@ -31,8 +31,8 @@ void get_args(int *argc, char ***argv) contents_size += kBufSize; contents = (char *)realloc(contents, contents_size); bytes_read = - read(fd, contents + contents_offset, - contents_size - contents_offset); + read(fd, contents + contents_offset, + contents_size - contents_offset); contents_offset += bytes_read; } while (bytes_read > 0); @@ -80,20 +80,20 @@ void nsenter() char **argv; get_args(&argc, &argv); - // check argv 0 to ensure that we are supposed to setns - // we use strncmp to test for a value of "nsenter" but also allows alternate implmentations - // after the setns code path to continue to use the argv 0 to determine actions to be run - // resulting in the ability to specify "nsenter-mknod", "nsenter-exec", etc... - if (strncmp(argv[0], kNsEnter, strlen(kNsEnter)) != 0) { - return; - } + // check argv 0 to ensure that we are supposed to setns + // we use strncmp to test for a value of "nsenter" but also allows alternate implmentations + // after the setns code path to continue to use the argv 0 to determine actions to be run + // resulting in the ability to specify "nsenter-mknod", "nsenter-exec", etc... + if (strncmp(argv[0], kNsEnter, strlen(kNsEnter)) != 0) { + return; + } static const struct option longopts[] = { {"nspid", required_argument, NULL, 'n'}, {"console", required_argument, NULL, 't'}, {NULL, 0, NULL, 0} }; - + pid_t init_pid = -1; char *init_pid_str = NULL; char *console = NULL;