Make process listing work when cadvisor is running in docker.

Use /rootfs/proc to build the process listing.
This commit is contained in:
Rohit Jnagal 2015-06-04 08:24:50 +00:00
parent 387f7b3a7f
commit eb8f941ba6
2 changed files with 32 additions and 20 deletions

View File

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

View File

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