mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-15 03:20:03 +00:00
refactor: extract common code in endpoint mapping
This isn't quite as neat as we'd want to make it, because two of the three call sites still require a closure, but it's still an improvement. Note that every instance of MapEndpoints only ever maps to one topology, which, furthermore, is a core report topology. Hence we can just parameterise MapEndpoints with that topology, and then the map functions can return just the node ids.
This commit is contained in:
@@ -35,32 +35,29 @@ var ContainerRenderer = Memoise(MakeFilter(
|
||||
MapProcess2Container,
|
||||
ProcessRenderer,
|
||||
),
|
||||
ConnectionJoin(MapContainer2IP, SelectContainer),
|
||||
ConnectionJoin(MapContainer2IP, report.Container),
|
||||
),
|
||||
))
|
||||
|
||||
const originalNodeID = "original_node_id"
|
||||
|
||||
// ConnectionJoin joins the given renderer with connections from the
|
||||
// ConnectionJoin joins the given topology with connections from the
|
||||
// endpoints topology, using the toIPs function to extract IPs from
|
||||
// the nodes.
|
||||
func ConnectionJoin(toIPs func(report.Node) []string, r Renderer) Renderer {
|
||||
return connectionJoin{toIPs: toIPs, r: r}
|
||||
func ConnectionJoin(toIPs func(report.Node) []string, topology string) Renderer {
|
||||
return connectionJoin{toIPs: toIPs, topology: topology}
|
||||
}
|
||||
|
||||
type connectionJoin struct {
|
||||
toIPs func(report.Node) []string
|
||||
r Renderer
|
||||
toIPs func(report.Node) []string
|
||||
topology string
|
||||
}
|
||||
|
||||
func (c connectionJoin) Render(rpt report.Report) Nodes {
|
||||
local := LocalNetworks(rpt)
|
||||
inputNodes := c.r.Render(rpt)
|
||||
endpoints := SelectEndpoint.Render(rpt)
|
||||
|
||||
inputNodes := TopologySelector(c.topology).Render(rpt).Nodes
|
||||
// Collect all the IPs we are trying to map to, and which ID they map from
|
||||
var ipNodes = map[string]string{}
|
||||
for _, n := range inputNodes.Nodes {
|
||||
for _, n := range inputNodes {
|
||||
for _, ip := range c.toIPs(n) {
|
||||
if _, exists := ipNodes[ip]; exists {
|
||||
// If an IP is shared between multiple nodes, we can't reliably
|
||||
@@ -71,35 +68,27 @@ func (c connectionJoin) Render(rpt report.Report) Nodes {
|
||||
}
|
||||
}
|
||||
}
|
||||
ret := newJoinResults(inputNodes.Nodes)
|
||||
|
||||
// Now look at all the endpoints and see which map to IP nodes
|
||||
for _, m := range endpoints.Nodes {
|
||||
scope, addr, port, ok := report.ParseEndpointNodeID(m.ID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// Nodes without a hostid may be pseudo nodes - if so, pass through to result
|
||||
if _, ok := m.Latest.Lookup(report.HostNodeID); !ok {
|
||||
if id, ok := externalNodeID(m, addr, local); ok {
|
||||
ret.addChild(m, id, Pseudo)
|
||||
continue
|
||||
return MapEndpoints(
|
||||
func(m report.Node) string {
|
||||
scope, addr, port, ok := report.ParseEndpointNodeID(m.ID)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
id, found := ipNodes[report.MakeScopedEndpointNodeID(scope, addr, "")]
|
||||
// We also allow for joining on ip:port pairs. This is useful for
|
||||
// connections to the host IPs which have been port mapped to a
|
||||
// container can only be unambiguously identified with the port.
|
||||
if !found {
|
||||
id, found = ipNodes[report.MakeScopedEndpointNodeID(scope, addr, port)]
|
||||
}
|
||||
if found && id != "" { // not one we blanked out earlier
|
||||
// We are guaranteed to find the id, so really this should
|
||||
// never end up creating a node.
|
||||
ret.addChild(m, id, report.Container)
|
||||
}
|
||||
}
|
||||
return ret.result(endpoints)
|
||||
id, found := ipNodes[report.MakeScopedEndpointNodeID(scope, addr, "")]
|
||||
// We also allow for joining on ip:port pairs. This is
|
||||
// useful for connections to the host IPs which have been
|
||||
// port mapped to a container can only be unambiguously
|
||||
// identified with the port.
|
||||
if !found {
|
||||
id, found = ipNodes[report.MakeScopedEndpointNodeID(scope, addr, port)]
|
||||
}
|
||||
if found && id != "" { // not one we blanked out earlier
|
||||
// We are guaranteed to find the id, so really this
|
||||
// should never end up creating a node.
|
||||
return id
|
||||
}
|
||||
return ""
|
||||
}, c.topology).Render(rpt)
|
||||
}
|
||||
|
||||
// FilterEmpty is a Renderer which filters out nodes which have no children
|
||||
|
||||
49
render/endpoint.go
Normal file
49
render/endpoint.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// Pseudo is the topology for nodes that aren't "real" nodes inside a
|
||||
// cluster, such as nodes representing the internet, external
|
||||
// services, and artificial grouping such as "uncontained processes"
|
||||
// and "unmanaged containers".
|
||||
const Pseudo = "pseudo"
|
||||
|
||||
// EndpointRenderer is a Renderer which produces a renderable endpoint graph.
|
||||
var EndpointRenderer = SelectEndpoint
|
||||
|
||||
type endpointMapFunc func(report.Node) string
|
||||
|
||||
type mapEndpoints struct {
|
||||
f endpointMapFunc
|
||||
topology string
|
||||
}
|
||||
|
||||
// MapEndpoints creates a renderer for the endpoint topology. Each
|
||||
// endpoint is either turned into a pseudo node, or mapped to a node
|
||||
// in the specified topology by the supplied function.
|
||||
func MapEndpoints(f endpointMapFunc, topology string) Renderer {
|
||||
return mapEndpoints{f: f, topology: topology}
|
||||
}
|
||||
|
||||
func (e mapEndpoints) Render(rpt report.Report) Nodes {
|
||||
local := LocalNetworks(rpt)
|
||||
endpoints := SelectEndpoint.Render(rpt)
|
||||
ret := newJoinResults(TopologySelector(e.topology).Render(rpt).Nodes)
|
||||
|
||||
for _, n := range endpoints.Nodes {
|
||||
// Nodes without a hostid are mapped to pseudo nodes, if
|
||||
// possible.
|
||||
if _, ok := n.Latest.Lookup(report.HostNodeID); !ok {
|
||||
if id, ok := pseudoNodeID(n, local); ok {
|
||||
ret.addChild(n, id, Pseudo)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if id := e.f(n); id != "" {
|
||||
ret.addChild(n, id, e.topology)
|
||||
}
|
||||
}
|
||||
return ret.result(endpoints)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ var HostRenderer = MakeReduce(
|
||||
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: ContainerRenderer},
|
||||
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: ContainerImageRenderer},
|
||||
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: PodRenderer},
|
||||
endpoints2Hosts{},
|
||||
MapEndpoints(endpoint2Host, report.Host),
|
||||
)
|
||||
|
||||
// nodes2Hosts maps any Nodes to host Nodes.
|
||||
@@ -50,26 +50,9 @@ func nodes2Hosts(nodes Nodes) Nodes {
|
||||
return ret.result(nodes)
|
||||
}
|
||||
|
||||
// endpoints2Hosts takes nodes from the endpoint topology and produces
|
||||
// host nodes or pseudo nodes.
|
||||
type endpoints2Hosts struct {
|
||||
}
|
||||
|
||||
func (e endpoints2Hosts) Render(rpt report.Report) Nodes {
|
||||
local := LocalNetworks(rpt)
|
||||
hosts := SelectHost.Render(rpt)
|
||||
endpoints := SelectEndpoint.Render(rpt)
|
||||
ret := newJoinResults(hosts.Nodes)
|
||||
|
||||
for _, n := range endpoints.Nodes {
|
||||
// Nodes without a hostid are treated as pseudo nodes
|
||||
if hostNodeID, ok := n.Latest.Lookup(report.HostNodeID); !ok {
|
||||
if id, ok := pseudoNodeID(n, local); ok {
|
||||
ret.addChild(n, id, Pseudo)
|
||||
}
|
||||
} else {
|
||||
ret.addChild(n, hostNodeID, report.Host)
|
||||
}
|
||||
func endpoint2Host(n report.Node) string {
|
||||
if hostNodeID, ok := n.Latest.Lookup(report.HostNodeID); ok {
|
||||
return hostNodeID
|
||||
}
|
||||
return ret.result(endpoints)
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ var PodRenderer = Memoise(ConditionalRenderer(renderKubernetesTopologies,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConnectionJoin(MapPod2IP, SelectPod),
|
||||
ConnectionJoin(MapPod2IP, report.Pod),
|
||||
),
|
||||
),
|
||||
))
|
||||
|
||||
@@ -13,18 +13,12 @@ const (
|
||||
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"
|
||||
)
|
||||
|
||||
func renderProcesses(rpt report.Report) bool {
|
||||
return len(rpt.Process.Nodes) >= 1
|
||||
}
|
||||
|
||||
// EndpointRenderer is a Renderer which produces a renderable endpoint graph.
|
||||
var EndpointRenderer = SelectEndpoint
|
||||
|
||||
// ProcessRenderer is a Renderer which produces a renderable process
|
||||
// graph by merging the endpoint graph and the process topology. It
|
||||
// also colors connected nodes, so we can apply a filter to show/hide
|
||||
@@ -79,32 +73,22 @@ func (e endpoints2Processes) Render(rpt report.Report) Nodes {
|
||||
if len(rpt.Process.Nodes) == 0 {
|
||||
return Nodes{}
|
||||
}
|
||||
local := LocalNetworks(rpt)
|
||||
processes := SelectProcess.Render(rpt)
|
||||
endpoints := SelectEndpoint.Render(rpt)
|
||||
ret := newJoinResults(processes.Nodes)
|
||||
|
||||
for _, n := range endpoints.Nodes {
|
||||
// Nodes without a hostid are treated as pseudo nodes
|
||||
if hostNodeID, ok := n.Latest.Lookup(report.HostNodeID); !ok {
|
||||
if id, ok := pseudoNodeID(n, local); ok {
|
||||
ret.addChild(n, id, Pseudo)
|
||||
}
|
||||
} else {
|
||||
endpoints := SelectEndpoint.Render(rpt).Nodes
|
||||
return MapEndpoints(
|
||||
func(n report.Node) string {
|
||||
pid, ok := n.Latest.Lookup(process.PID)
|
||||
if !ok {
|
||||
continue
|
||||
return ""
|
||||
}
|
||||
if hasMoreThanOneConnection(n, endpoints.Nodes) {
|
||||
continue
|
||||
if hasMoreThanOneConnection(n, endpoints) {
|
||||
return ""
|
||||
}
|
||||
|
||||
hostID, _ := report.ParseHostNodeID(hostNodeID)
|
||||
id := report.MakeProcessNodeID(hostID, pid)
|
||||
ret.addChild(n, id, report.Process)
|
||||
}
|
||||
}
|
||||
return ret.result(endpoints)
|
||||
hostID := report.ExtractHostID(n)
|
||||
if hostID == "" {
|
||||
return ""
|
||||
}
|
||||
return report.MakeProcessNodeID(hostID, pid)
|
||||
}, report.Process).Render(rpt)
|
||||
}
|
||||
|
||||
// When there is more than one connection originating from a source
|
||||
|
||||
Reference in New Issue
Block a user