mirror of
https://github.com/weaveworks/scope.git
synced 2026-02-14 18:09:59 +00:00
These can be long-running operations, and if the client retries we get the cancelled one running in parallel with the retry, slowing both down and making it likely the next one will time out too.
110 lines
3.2 KiB
Go
110 lines
3.2 KiB
Go
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(ctx context.Context, 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(ctx, processes)
|
|
}
|