From eb8f941ba60b7b74a9ceca40f2a0f07f125cb89b Mon Sep 17 00:00:00 2001 From: Rohit Jnagal Date: Thu, 4 Jun 2015 08:24:50 +0000 Subject: [PATCH] Make process listing work when cadvisor is running in docker. Use /rootfs/proc to build the process listing. --- manager/container.go | 40 +++++++++++++++++++++------------------- manager/manager.go | 12 +++++++++++- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/manager/container.go b/manager/container.go index 70adbf17..e19e8b5c 100644 --- a/manager/container.go +++ b/manager/container.go @@ -132,26 +132,22 @@ func (c *containerData) getCgroupPath(cgroups string) (string, error) { return string(matches[1]), nil } -func (c *containerData) GetProcessList() ([]v2.ProcessInfo, error) { +func (c *containerData) GetProcessList(cadvisorContainer string, inHostNamespace bool) ([]v2.ProcessInfo, error) { // report all processes for root. isRoot := c.info.Name == "/" - pidMap := map[int]bool{} - if !isRoot { - pids, err := c.handler.ListProcesses(container.ListSelf) - if err != nil { - return nil, err - } - for _, pid := range pids { - pidMap[pid] = true - } - } // TODO(rjnagal): Take format as an option? format := "user,pid,ppid,stime,pcpu,pmem,rss,vsz,stat,time,comm,cgroup" - args := []string{"-e", "-o", format} + args := []string{} + command := "ps" + if !inHostNamespace { + command = "/usr/sbin/chroot" + args = append(args, "/rootfs", "ps") + } + args = append(args, "-e", "-o", format) expectedFields := 12 - out, err := exec.Command("ps", args...).Output() + out, err := exec.Command(command, args...).Output() if err != nil { - return nil, fmt.Errorf("failed to execute ps command: %v", err) + return nil, fmt.Errorf("failed to execute %q command: %v", command, err) } processes := []v2.ProcessInfo{} lines := strings.Split(string(out), "\n") @@ -187,15 +183,21 @@ func (c *containerData) GetProcessList() ([]v2.ProcessInfo, error) { if err != nil { return nil, fmt.Errorf("invalid virtual size %q: %v", fields[7], err) } + cgroup, err := c.getCgroupPath(fields[11]) + if err != nil { + return nil, fmt.Errorf("could not parse cgroup path from %q: %v", fields[10], err) + } + // Remove the ps command we just ran from cadvisor container. + // Not necessary, but makes the cadvisor page look cleaner. + if !inHostNamespace && cadvisorContainer == cgroup && fields[10] == "ps" { + continue + } var cgroupPath string if isRoot { - cgroupPath, err = c.getCgroupPath(fields[11]) - if err != nil { - return nil, fmt.Errorf("could not parse cgroup path from %q: %v", fields[10], err) - } + cgroupPath = cgroup } - if isRoot || pidMap[pid] == true { + if isRoot || c.info.Name == cgroup { processes = append(processes, v2.ProcessInfo{ User: fields[0], Pid: pid, diff --git a/manager/manager.go b/manager/manager.go index 2c055d03..7f2688d9 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -18,6 +18,7 @@ package manager import ( "flag" "fmt" + "os" "path" "regexp" "strconv" @@ -130,12 +131,20 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs) (Manager, error) if err != nil { return nil, err } + + // If cAdvisor was started with host's rootfs mounted, assume that its running + // in its own namespaces. + inHostNamespace := false + if _, err := os.Stat("/rootfs/proc"); os.IsNotExist(err) { + inHostNamespace = true + } newManager := &manager{ containers: make(map[namespacedContainerName]*containerData), quitChannels: make([]chan error, 0, 2), memoryCache: memoryCache, fsInfo: fsInfo, cadvisorContainer: selfContainer, + inHostNamespace: inHostNamespace, startupTime: time.Now(), } @@ -175,6 +184,7 @@ type manager struct { versionInfo info.VersionInfo quitChannels []chan error cadvisorContainer string + inHostNamespace bool dockerContainersRegexp *regexp.Regexp loadReader cpuload.CpuLoadReader eventHandler events.EventManager @@ -671,7 +681,7 @@ func (m *manager) GetProcessList(containerName string, options v2.RequestOptions // TODO(rjnagal): handle count? Only if we can do count by type (eg. top 5 cpu users) ps := []v2.ProcessInfo{} for _, cont := range conts { - ps, err = cont.GetProcessList() + ps, err = cont.GetProcessList(m.cadvisorContainer, m.inHostNamespace) if err != nil { return nil, err }