forked from weaveworks/scope
-
Notifications
You must be signed in to change notification settings - Fork 0
/
process.go
109 lines (96 loc) · 3.17 KB
/
process.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package render
import (
"context"
"github.com/weaveworks/scope/report"
)
// Constants are used in the tests.
const (
InboundMajor = "The Internet"
OutboundMajor = "The Internet"
InboundMinor = "Inbound connections"
OutboundMinor = "Outbound connections"
)
func renderProcesses(rpt report.Report) bool {
return len(rpt.Process.Nodes) >= 1
}
// ProcessRenderer is a Renderer which produces a renderable process
// graph by merging the endpoint graph and the process topology.
var ProcessRenderer = Memoise(endpoints2Processes{})
// ConnectedProcessRenderer is a Renderer which colors
// connected nodes, so we can apply a filter to show/hide unconnected
// nodes depending on user choice.
//
// not memoised
var ConnectedProcessRenderer = ColorConnected(ProcessRenderer)
// ProcessNameRenderer is a Renderer which produces a renderable
// process name graph by munging the progess graph.
//
// It also colors connected nodes, so we can apply a filter to
// show/hide unconnected nodes depending on user choice.
//
// not memoised
var ProcessNameRenderer = ColorConnected(CustomRenderer{RenderFunc: processes2Names, Renderer: ProcessRenderer})
// endpoints2Processes joins the endpoint topology to the process
// topology, matching on hostID and pid.
type endpoints2Processes struct {
}
func (e endpoints2Processes) Render(ctx context.Context, rpt report.Report) Nodes {
if len(rpt.Process.Nodes) == 0 {
return Nodes{}
}
endpoints := SelectEndpoint.Render(ctx, rpt).Nodes
return MapEndpoints(
func(n report.Node) string {
pid, ok := n.Latest.Lookup(report.PID)
if !ok {
return ""
}
if hasMoreThanOneConnection(n, endpoints) {
return ""
}
hostID := report.ExtractHostID(n)
if hostID == "" {
return ""
}
return report.MakeProcessNodeID(hostID, pid)
}, report.Process).Render(ctx, rpt)
}
// When there is more than one connection originating from a source
// endpoint, we cannot be sure that its pid is associated with all of
// them, since the source endpoint may have been re-used by a
// different process. See #2665. It is better to drop such an endpoint
// than risk rendering bogus connections. Aliased connections - when
// all the remote endpoints represent the same logical endpoint, due
// to NATing - are fine though.
func hasMoreThanOneConnection(n report.Node, endpoints report.Nodes) bool {
if len(n.Adjacency) < 2 {
return false
}
firstRealEndpointID := ""
for _, endpointID := range n.Adjacency {
if ep, ok := endpoints[endpointID]; ok {
if copyID, _, ok := ep.Latest.LookupEntry(report.CopyOf); ok {
endpointID = copyID
}
}
if firstRealEndpointID == "" {
firstRealEndpointID = endpointID
} else if firstRealEndpointID != endpointID {
return true
}
}
return false
}
var processNameTopology = MakeGroupNodeTopology(report.Process, report.Name)
// processes2Names maps process Nodes to Nodes for each process name.
func processes2Names(processes Nodes) Nodes {
ret := newJoinResults(nil)
for _, n := range processes.Nodes {
if n.Topology == Pseudo {
ret.passThrough(n)
} else if name, ok := n.Latest.Lookup(report.Name); ok {
ret.addChildAndChildren(n, name, processNameTopology)
}
}
return ret.result(processes)
}