Enter cgroups as part of nsenter while using systemd.

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:34:59 +00:00
parent ae64fd1e58
commit ae08910fde
13 changed files with 63 additions and 127 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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;