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:
parent
ae64fd1e58
commit
ae08910fde
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue