Decouple PIDTree from DockerTagger

PIDTree is created in each spy tick, regardless if Docker Tagger is
used.
This commit is contained in:
Peter Bourgon
2015-06-10 17:49:50 +02:00
parent d435e36834
commit 7df63d1bc4
4 changed files with 40 additions and 39 deletions

View File

@@ -99,8 +99,10 @@ func main() {
case <-spyTick:
r.Merge(spy(hostID, hostName, *spyProcs))
if dockerTagger != nil {
r.Process.Merge(dockerTagger.ProcessTopology(hostID))
if pidTree, err := tag.NewPIDTree(*procRoot); err == nil {
r.Process.Merge(pidTree.ProcessTopology(hostID))
} else {
log.Print(err)
}
r = tag.Apply(r, taggers)

View File

@@ -18,7 +18,7 @@ const (
var (
newDockerClientStub = newDockerClient
newPIDTreeStub = newPIDTree
newPIDTreeStub = NewPIDTree
)
// DockerTagger is a tagger that tags Docker container information to process
@@ -33,7 +33,7 @@ type DockerTagger struct {
images map[string]*docker.APIImages
procRoot string
pidTree *pidTree
pidTree *PIDTree
}
// NewDockerTagger returns a usable DockerTagger. Don't forget to Stop it.
@@ -64,11 +64,6 @@ func (t *DockerTagger) Stop() {
close(t.quit)
}
// ProcessTopology returns a process topology from the pidtree.
func (t *DockerTagger) ProcessTopology(hostID string) report.Topology {
return t.pidTree.processTopology(hostID)
}
func (t *DockerTagger) loop() {
if !t.update() {
return

View File

@@ -40,12 +40,12 @@ func TestDockerTagger(t *testing.T) {
oldPIDTree, oldDockerClient := newPIDTreeStub, newDockerClientStub
defer func() { newPIDTreeStub, newDockerClientStub = oldPIDTree, oldDockerClient }()
newPIDTreeStub = func(procRoot string) (*pidTree, error) {
pid1 := &process{pid: 1}
pid2 := &process{pid: 2, ppid: 1, parent: pid1}
pid1.children = []*process{pid2}
return &pidTree{
processes: map[int]*process{
newPIDTreeStub = func(procRoot string) (*PIDTree, error) {
pid1 := &Process{PID: 1}
pid2 := &Process{PID: 2, PPID: 1, parent: pid1}
pid1.children = []*Process{pid2}
return &PIDTree{
processes: map[int]*Process{
1: pid1, 2: pid2,
},
}, nil

View File

@@ -10,15 +10,17 @@ import (
"github.com/weaveworks/scope/report"
)
type pidTree struct {
processes map[int]*process
// PIDTree represents all processes on the machine.
type PIDTree struct {
processes map[int]*Process
}
type process struct {
pid, ppid int
parent *process
children []*process
comm string
// Process represents a single process.
type Process struct {
PID, PPID int
Comm string
parent *Process
children []*Process
}
// Hooks for mocking
@@ -27,13 +29,14 @@ var (
readFile = ioutil.ReadFile
)
func newPIDTree(procRoot string) (*pidTree, error) {
// NewPIDTree returns a new PIDTree that can be polled.
func NewPIDTree(procRoot string) (*PIDTree, error) {
dirEntries, err := readDir(procRoot)
if err != nil {
return nil, err
}
pt := pidTree{processes: map[int]*process{}}
pt := PIDTree{processes: map[int]*Process{}}
for _, dirEntry := range dirEntries {
filename := dirEntry.Name()
pid, err := strconv.Atoi(filename)
@@ -56,15 +59,15 @@ func newPIDTree(procRoot string) (*pidTree, error) {
comm = string(commBuf)
}
pt.processes[pid] = &process{
pid: pid,
ppid: ppid,
comm: comm,
pt.processes[pid] = &Process{
PID: pid,
PPID: ppid,
Comm: comm,
}
}
for _, child := range pt.processes {
parent, ok := pt.processes[child.ppid]
parent, ok := pt.processes[child.PPID]
if !ok {
// This can happen as listing proc is not a consistent snapshot
continue
@@ -76,17 +79,17 @@ func newPIDTree(procRoot string) (*pidTree, error) {
return &pt, nil
}
func (pt *pidTree) getParent(pid int) (int, error) {
func (pt *PIDTree) getParent(pid int) (int, error) {
proc, ok := pt.processes[pid]
if !ok {
return -1, fmt.Errorf("PID %d not found", pid)
}
return proc.ppid, nil
return proc.PPID, nil
}
// allChildren returns a flattened list of child pids including the given pid
func (pt *pidTree) allChildren(pid int) ([]int, error) {
func (pt *PIDTree) allChildren(pid int) ([]int, error) {
proc, ok := pt.processes[pid]
if !ok {
return []int{}, fmt.Errorf("PID %d not found", pid)
@@ -94,9 +97,9 @@ func (pt *pidTree) allChildren(pid int) ([]int, error) {
var result []int
var f func(*process)
f = func(p *process) {
result = append(result, p.pid)
var f func(*Process)
f = func(p *Process) {
result = append(result, p.PID)
for _, child := range p.children {
f(child)
}
@@ -106,17 +109,18 @@ func (pt *pidTree) allChildren(pid int) ([]int, error) {
return result, nil
}
func (pt *pidTree) processTopology(hostID string) report.Topology {
// ProcessTopology returns a process topology based on the current state of the PIDTree.
func (pt *PIDTree) ProcessTopology(hostID string) report.Topology {
t := report.NewTopology()
for pid, proc := range pt.processes {
pidstr := strconv.Itoa(pid)
nodeID := report.MakeProcessNodeID(hostID, pidstr)
t.NodeMetadatas[nodeID] = report.NodeMetadata{
"pid": pidstr,
"comm": proc.comm,
"comm": proc.Comm,
}
if proc.ppid > 0 {
t.NodeMetadatas[nodeID]["ppid"] = strconv.Itoa(proc.ppid)
if proc.PPID > 0 {
t.NodeMetadatas[nodeID]["ppid"] = strconv.Itoa(proc.PPID)
}
}
return t