Make process listing work when cadvisor is running in docker.
Use /rootfs/proc to build the process listing.
This commit is contained in:
parent
387f7b3a7f
commit
eb8f941ba6
@ -132,26 +132,22 @@ func (c *containerData) getCgroupPath(cgroups string) (string, error) {
|
|||||||
return string(matches[1]), nil
|
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.
|
// report all processes for root.
|
||||||
isRoot := c.info.Name == "/"
|
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?
|
// TODO(rjnagal): Take format as an option?
|
||||||
format := "user,pid,ppid,stime,pcpu,pmem,rss,vsz,stat,time,comm,cgroup"
|
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
|
expectedFields := 12
|
||||||
out, err := exec.Command("ps", args...).Output()
|
out, err := exec.Command(command, args...).Output()
|
||||||
if err != nil {
|
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{}
|
processes := []v2.ProcessInfo{}
|
||||||
lines := strings.Split(string(out), "\n")
|
lines := strings.Split(string(out), "\n")
|
||||||
@ -187,15 +183,21 @@ func (c *containerData) GetProcessList() ([]v2.ProcessInfo, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid virtual size %q: %v", fields[7], err)
|
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
|
var cgroupPath string
|
||||||
if isRoot {
|
if isRoot {
|
||||||
cgroupPath, err = c.getCgroupPath(fields[11])
|
cgroupPath = cgroup
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not parse cgroup path from %q: %v", fields[10], err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if isRoot || pidMap[pid] == true {
|
if isRoot || c.info.Name == cgroup {
|
||||||
processes = append(processes, v2.ProcessInfo{
|
processes = append(processes, v2.ProcessInfo{
|
||||||
User: fields[0],
|
User: fields[0],
|
||||||
Pid: pid,
|
Pid: pid,
|
||||||
|
@ -18,6 +18,7 @@ package manager
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -130,12 +131,20 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs) (Manager, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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{
|
newManager := &manager{
|
||||||
containers: make(map[namespacedContainerName]*containerData),
|
containers: make(map[namespacedContainerName]*containerData),
|
||||||
quitChannels: make([]chan error, 0, 2),
|
quitChannels: make([]chan error, 0, 2),
|
||||||
memoryCache: memoryCache,
|
memoryCache: memoryCache,
|
||||||
fsInfo: fsInfo,
|
fsInfo: fsInfo,
|
||||||
cadvisorContainer: selfContainer,
|
cadvisorContainer: selfContainer,
|
||||||
|
inHostNamespace: inHostNamespace,
|
||||||
startupTime: time.Now(),
|
startupTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,6 +184,7 @@ type manager struct {
|
|||||||
versionInfo info.VersionInfo
|
versionInfo info.VersionInfo
|
||||||
quitChannels []chan error
|
quitChannels []chan error
|
||||||
cadvisorContainer string
|
cadvisorContainer string
|
||||||
|
inHostNamespace bool
|
||||||
dockerContainersRegexp *regexp.Regexp
|
dockerContainersRegexp *regexp.Regexp
|
||||||
loadReader cpuload.CpuLoadReader
|
loadReader cpuload.CpuLoadReader
|
||||||
eventHandler events.EventManager
|
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)
|
// TODO(rjnagal): handle count? Only if we can do count by type (eg. top 5 cpu users)
|
||||||
ps := []v2.ProcessInfo{}
|
ps := []v2.ProcessInfo{}
|
||||||
for _, cont := range conts {
|
for _, cont := range conts {
|
||||||
ps, err = cont.GetProcessList()
|
ps, err = cont.GetProcessList(m.cadvisorContainer, m.inHostNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user