mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
160 lines
5.0 KiB
Go
160 lines
5.0 KiB
Go
package render
|
|
|
|
import (
|
|
"net"
|
|
|
|
"github.com/weaveworks/scope/probe/docker"
|
|
"github.com/weaveworks/scope/probe/endpoint"
|
|
"github.com/weaveworks/scope/probe/process"
|
|
"github.com/weaveworks/scope/report"
|
|
)
|
|
|
|
// Constants are used in the tests.
|
|
const (
|
|
TheInternetID = "theinternet"
|
|
IncomingInternetID = "in-" + TheInternetID
|
|
OutgoingInternetID = "out-" + TheInternetID
|
|
InboundMajor = "The Internet"
|
|
OutboundMajor = "The Internet"
|
|
InboundMinor = "Inbound connections"
|
|
OutboundMinor = "Outbound connections"
|
|
|
|
// Topology for pseudo-nodes and IPs so we can differentiate them at the end
|
|
Pseudo = "pseudo"
|
|
)
|
|
|
|
// EndpointRenderer is a Renderer which produces a renderable endpoint graph.
|
|
var EndpointRenderer = FilterNonProcspied(SelectEndpoint)
|
|
|
|
// ProcessRenderer is a Renderer which produces a renderable process
|
|
// graph by merging the endpoint graph and the process topology.
|
|
var ProcessRenderer = ColorConnected(MakeReduce(
|
|
MakeMap(
|
|
MapEndpoint2Process,
|
|
EndpointRenderer,
|
|
),
|
|
SelectProcess,
|
|
))
|
|
|
|
// processWithContainerNameRenderer is a Renderer which produces a process
|
|
// graph enriched with container names where appropriate
|
|
type processWithContainerNameRenderer struct {
|
|
Renderer
|
|
}
|
|
|
|
func (r processWithContainerNameRenderer) Render(rpt report.Report, dct Decorator) report.Nodes {
|
|
processes := r.Renderer.Render(rpt, dct)
|
|
containers := SelectContainer.Render(rpt, dct)
|
|
|
|
outputs := report.Nodes{}
|
|
for id, p := range processes {
|
|
outputs[id] = p
|
|
containerID, timestamp, ok := p.Latest.LookupEntry(docker.ContainerID)
|
|
if !ok {
|
|
continue
|
|
}
|
|
container, ok := containers[report.MakeContainerNodeID(containerID)]
|
|
if !ok {
|
|
continue
|
|
}
|
|
output := p.Copy()
|
|
output.Latest = output.Latest.Set(docker.ContainerID, timestamp, containerID)
|
|
if containerName, timestamp, ok := container.Latest.LookupEntry(docker.ContainerName); ok {
|
|
output.Latest = output.Latest.Set(docker.ContainerName, timestamp, containerName)
|
|
}
|
|
outputs[id] = output
|
|
}
|
|
return outputs
|
|
}
|
|
|
|
// ProcessWithContainerNameRenderer is a Renderer which produces a process
|
|
// graph enriched with container names where appropriate
|
|
var ProcessWithContainerNameRenderer = processWithContainerNameRenderer{ProcessRenderer}
|
|
|
|
// ProcessNameRenderer is a Renderer which produces a renderable process
|
|
// name graph by munging the progess graph.
|
|
var ProcessNameRenderer = MakeMap(
|
|
MapProcess2Name,
|
|
ProcessRenderer,
|
|
)
|
|
|
|
// MapEndpoint2Pseudo makes internet of host pesudo nodes from a endpoint node.
|
|
func MapEndpoint2Pseudo(n report.Node, local report.Networks) report.Nodes {
|
|
var node report.Node
|
|
|
|
addr, ok := n.Latest.Lookup(endpoint.Addr)
|
|
if !ok {
|
|
return report.Nodes{}
|
|
}
|
|
|
|
if ip := net.ParseIP(addr); ip != nil && !local.Contains(ip) {
|
|
// If the dstNodeAddr is not in a network local to this report, we emit an
|
|
// internet node
|
|
node = theInternetNode(n)
|
|
} else {
|
|
// due to https://github.com/weaveworks/scope/issues/1323 we are dropping
|
|
// all non-internet pseudo nodes for now.
|
|
// node = NewDerivedPseudoNode(MakePseudoNodeID(addr), n)
|
|
return report.Nodes{}
|
|
}
|
|
return report.Nodes{node.ID: node}
|
|
}
|
|
|
|
// MapEndpoint2Process maps endpoint Nodes to process
|
|
// Nodes.
|
|
//
|
|
// If this function is given a pseudo node, then it will just return it;
|
|
// Pseudo nodes will never have pids in them, and therefore will never
|
|
// be able to be turned into a Process node.
|
|
//
|
|
// Otherwise, this function will produce a node with the correct ID
|
|
// format for a process, but without any Major or Minor labels.
|
|
// It does not have enough info to do that, and the resulting graph
|
|
// must be merged with a process graph to get that info.
|
|
func MapEndpoint2Process(n report.Node, local report.Networks) report.Nodes {
|
|
// Nodes without a hostid are treated as pseudo nodes
|
|
if _, ok := n.Latest.Lookup(report.HostNodeID); !ok {
|
|
return MapEndpoint2Pseudo(n, local)
|
|
}
|
|
|
|
pid, timestamp, ok := n.Latest.LookupEntry(process.PID)
|
|
if !ok {
|
|
return report.Nodes{}
|
|
}
|
|
|
|
id := report.MakeProcessNodeID(report.ExtractHostID(n), pid)
|
|
node := NewDerivedNode(id, n).WithTopology(report.Process)
|
|
node.Latest = node.Latest.Set(process.PID, timestamp, pid)
|
|
node.Counters = node.Counters.Add(n.Topology, 1)
|
|
return report.Nodes{id: node}
|
|
}
|
|
|
|
// MapProcess2Name maps process Nodes to Nodes
|
|
// for each process name.
|
|
//
|
|
// This mapper is unlike the other foo2bar mappers as the intention
|
|
// is not to join the information with another topology.
|
|
func MapProcess2Name(n report.Node, _ report.Networks) report.Nodes {
|
|
if n.Topology == Pseudo {
|
|
return report.Nodes{n.ID: n}
|
|
}
|
|
|
|
name, timestamp, ok := n.Latest.LookupEntry(process.Name)
|
|
if !ok {
|
|
return report.Nodes{}
|
|
}
|
|
|
|
node := NewDerivedNode(name, n).WithTopology(MakeGroupNodeTopology(n.Topology, process.Name))
|
|
node.Latest = node.Latest.Set(process.Name, timestamp, name)
|
|
node.Counters = node.Counters.Add(n.Topology, 1)
|
|
return report.Nodes{name: node}
|
|
}
|
|
|
|
func theInternetNode(m report.Node) report.Node {
|
|
// emit one internet node for incoming, one for outgoing
|
|
if len(m.Adjacency) > 0 {
|
|
return NewDerivedPseudoNode(IncomingInternetID, m)
|
|
}
|
|
return NewDerivedPseudoNode(OutgoingInternetID, m)
|
|
}
|