mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-05 16:59:36 +00:00
Give mapping functions the ability to return multiple nodes.
This commit is contained in:
@@ -31,10 +31,7 @@ const (
|
||||
//
|
||||
// A single NodeMetadata can yield arbitrary many representations, including
|
||||
// representations that reduce the cardinality of the set of nodes.
|
||||
//
|
||||
// If the final output parameter is false, the node shall be omitted from the
|
||||
// rendered topology.
|
||||
type LeafMapFunc func(report.NodeMetadata) (RenderableNode, bool)
|
||||
type LeafMapFunc func(report.NodeMetadata) RenderableNodes
|
||||
|
||||
// PseudoFunc creates RenderableNode representing pseudo nodes given the
|
||||
// srcNodeID. dstNodeID is the node id of one of the nodes this node has an
|
||||
@@ -48,20 +45,20 @@ type PseudoFunc func(srcNodeID, dstNodeID string, srcIsClient bool, local report
|
||||
//
|
||||
// As with LeafMapFunc, if the final output parameter is false, the node
|
||||
// shall be omitted from the rendered topology.
|
||||
type MapFunc func(RenderableNode) (RenderableNode, bool)
|
||||
type MapFunc func(RenderableNode) RenderableNodes
|
||||
|
||||
// MapEndpointIdentity maps an endpoint topology node to an endpoint
|
||||
// renderable node. As it is only ever run on endpoint topology nodes, we
|
||||
// expect that certain keys are present.
|
||||
func MapEndpointIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
func MapEndpointIdentity(m report.NodeMetadata) RenderableNodes {
|
||||
addr, ok := m.Metadata[endpoint.Addr]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
port, ok := m.Metadata[endpoint.Port]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -75,16 +72,16 @@ func MapEndpointIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
minor = fmt.Sprintf("%s (%s)", minor, pid)
|
||||
}
|
||||
|
||||
return NewRenderableNode(id, major, minor, rank, m), true
|
||||
return RenderableNodes{id: NewRenderableNode(id, major, minor, rank, m)}
|
||||
}
|
||||
|
||||
// MapProcessIdentity maps a process topology node to a process renderable
|
||||
// node. As it is only ever run on process topology nodes, we expect that
|
||||
// certain keys are present.
|
||||
func MapProcessIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
func MapProcessIdentity(m report.NodeMetadata) RenderableNodes {
|
||||
pid, ok := m.Metadata[process.PID]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -94,16 +91,16 @@ func MapProcessIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
rank = m.Metadata["comm"]
|
||||
)
|
||||
|
||||
return NewRenderableNode(id, major, minor, rank, m), true
|
||||
return RenderableNodes{id: NewRenderableNode(id, major, minor, rank, m)}
|
||||
}
|
||||
|
||||
// MapContainerIdentity maps a container topology node to a container
|
||||
// renderable node. As it is only ever run on container topology nodes, we
|
||||
// expect that certain keys are present.
|
||||
func MapContainerIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
func MapContainerIdentity(m report.NodeMetadata) RenderableNodes {
|
||||
id, ok := m.Metadata[docker.ContainerID]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -112,16 +109,16 @@ func MapContainerIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
rank = m.Metadata[docker.ImageID]
|
||||
)
|
||||
|
||||
return NewRenderableNode(id, major, minor, rank, m), true
|
||||
return RenderableNodes{id: NewRenderableNode(id, major, minor, rank, m)}
|
||||
}
|
||||
|
||||
// MapContainerImageIdentity maps a container image topology node to container
|
||||
// image renderable node. As it is only ever run on container image topology
|
||||
// nodes, we expect that certain keys are present.
|
||||
func MapContainerImageIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
func MapContainerImageIdentity(m report.NodeMetadata) RenderableNodes {
|
||||
id, ok := m.Metadata[docker.ImageID]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -129,16 +126,16 @@ func MapContainerImageIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
rank = m.Metadata[docker.ImageID]
|
||||
)
|
||||
|
||||
return NewRenderableNode(id, major, "", rank, m), true
|
||||
return RenderableNodes{id: NewRenderableNode(id, major, "", rank, m)}
|
||||
}
|
||||
|
||||
// MapAddressIdentity maps an address topology node to an address renderable
|
||||
// node. As it is only ever run on address topology nodes, we expect that
|
||||
// certain keys are present.
|
||||
func MapAddressIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
func MapAddressIdentity(m report.NodeMetadata) RenderableNodes {
|
||||
addr, ok := m.Metadata[endpoint.Addr]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -148,13 +145,13 @@ func MapAddressIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
rank = major
|
||||
)
|
||||
|
||||
return NewRenderableNode(id, major, minor, rank, m), true
|
||||
return RenderableNodes{id: NewRenderableNode(id, major, minor, rank, m)}
|
||||
}
|
||||
|
||||
// MapHostIdentity maps a host topology node to a host renderable node. As it
|
||||
// is only ever run on host topology nodes, we expect that certain keys are
|
||||
// present.
|
||||
func MapHostIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
func MapHostIdentity(m report.NodeMetadata) RenderableNodes {
|
||||
var (
|
||||
id = MakeHostID(report.ExtractHostID(m))
|
||||
hostname = m.Metadata[host.HostName]
|
||||
@@ -168,7 +165,7 @@ func MapHostIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
major = hostname
|
||||
}
|
||||
|
||||
return NewRenderableNode(id, major, minor, rank, m), true
|
||||
return RenderableNodes{id: NewRenderableNode(id, major, minor, rank, m)}
|
||||
}
|
||||
|
||||
// MapEndpoint2Process maps endpoint RenderableNodes to process
|
||||
@@ -182,18 +179,18 @@ func MapHostIdentity(m report.NodeMetadata) (RenderableNode, bool) {
|
||||
// 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 RenderableNode) (RenderableNode, bool) {
|
||||
func MapEndpoint2Process(n RenderableNode) RenderableNodes {
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
pid, ok := n.NodeMetadata.Metadata[process.PID]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
id := MakeProcessID(report.ExtractHostID(n.NodeMetadata), pid)
|
||||
return newDerivedNode(id, n), true
|
||||
return RenderableNodes{id: newDerivedNode(id, n)}
|
||||
}
|
||||
|
||||
// MapProcess2Container maps process RenderableNodes to container
|
||||
@@ -207,15 +204,15 @@ func MapEndpoint2Process(n RenderableNode) (RenderableNode, bool) {
|
||||
// format for a container, 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 container graph to get that info.
|
||||
func MapProcess2Container(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapProcess2Container(n RenderableNode) RenderableNodes {
|
||||
// Propogate the internet pseudo node
|
||||
if n.ID == TheInternetID {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
// Don't propogate non-internet pseudo nodes
|
||||
if n.Pseudo {
|
||||
return n, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
// Otherwise, if the process is not in a container, group it
|
||||
@@ -228,10 +225,10 @@ func MapProcess2Container(n RenderableNode) (RenderableNode, bool) {
|
||||
id = MakePseudoNodeID(UncontainedID, hostID)
|
||||
node := newDerivedPseudoNode(id, UncontainedMajor, n)
|
||||
node.LabelMinor = hostID
|
||||
return node, true
|
||||
return RenderableNodes{id: node}
|
||||
}
|
||||
|
||||
return newDerivedNode(id, n), true
|
||||
return RenderableNodes{id: newDerivedNode(id, n)}
|
||||
}
|
||||
|
||||
// MapProcess2Name maps process RenderableNodes to RenderableNodes
|
||||
@@ -240,29 +237,29 @@ func MapProcess2Container(n RenderableNode) (RenderableNode, bool) {
|
||||
// This mapper is unlike the other foo2bar mappers as the intention
|
||||
// is not to join the information with another topology. Therefore
|
||||
// it outputs a properly-formed node with labels etc.
|
||||
func MapProcess2Name(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapProcess2Name(n RenderableNode) RenderableNodes {
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
name, ok := n.NodeMetadata.Metadata["comm"]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
node := newDerivedNode(name, n)
|
||||
node.LabelMajor = name
|
||||
node.Rank = name
|
||||
node.NodeMetadata.Counters[processesKey] = 1
|
||||
return node, true
|
||||
return RenderableNodes{name: node}
|
||||
}
|
||||
|
||||
// MapCountProcessName maps 1:1 process name nodes, counting
|
||||
// the number of processes grouped together and putting
|
||||
// that info in the minor label.
|
||||
func MapCountProcessName(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapCountProcessName(n RenderableNode) RenderableNodes {
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
processes := n.NodeMetadata.Counters[processesKey]
|
||||
@@ -271,7 +268,7 @@ func MapCountProcessName(n RenderableNode) (RenderableNode, bool) {
|
||||
} else {
|
||||
n.LabelMinor = fmt.Sprintf("%d processes", processes)
|
||||
}
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
// MapContainer2ContainerImage maps container RenderableNodes to container
|
||||
@@ -285,23 +282,23 @@ func MapCountProcessName(n RenderableNode) (RenderableNode, bool) {
|
||||
// format for a container, 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 container graph to get that info.
|
||||
func MapContainer2ContainerImage(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapContainer2ContainerImage(n RenderableNode) RenderableNodes {
|
||||
// Propogate all pseudo nodes
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
// Otherwise, if some some reason the container doesn't have a image_id
|
||||
// (maybe slightly out of sync reports), just drop it
|
||||
id, ok := n.NodeMetadata.Metadata[docker.ImageID]
|
||||
if !ok {
|
||||
return n, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
// Add container-<id> key to NMD, which will later be counted to produce the minor label
|
||||
result := newDerivedNode(id, n)
|
||||
result.NodeMetadata.Counters[containersKey] = 1
|
||||
return result, true
|
||||
return RenderableNodes{id: result}
|
||||
}
|
||||
|
||||
// MapContainerImage2Name maps container images RenderableNodes to
|
||||
@@ -310,14 +307,14 @@ func MapContainer2ContainerImage(n RenderableNode) (RenderableNode, bool) {
|
||||
// This mapper is unlike the other foo2bar mappers as the intention
|
||||
// is not to join the information with another topology. Therefore
|
||||
// it outputs a properly-formed node with labels etc.
|
||||
func MapContainerImage2Name(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapContainerImage2Name(n RenderableNode) RenderableNodes {
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
name, ok := n.NodeMetadata.Metadata[docker.ImageName]
|
||||
if !ok {
|
||||
return RenderableNode{}, false
|
||||
return RenderableNodes{}
|
||||
}
|
||||
|
||||
parts := strings.SplitN(name, ":", 2)
|
||||
@@ -329,15 +326,15 @@ func MapContainerImage2Name(n RenderableNode) (RenderableNode, bool) {
|
||||
node.LabelMajor = name
|
||||
node.Rank = name
|
||||
node.NodeMetadata = n.NodeMetadata.Copy() // Propagate NMD for container counting.
|
||||
return node, true
|
||||
return RenderableNodes{name: node}
|
||||
}
|
||||
|
||||
// MapCountContainers maps 1:1 container image nodes, counting
|
||||
// the number of containers grouped together and putting
|
||||
// that info in the minor label.
|
||||
func MapCountContainers(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapCountContainers(n RenderableNode) RenderableNodes {
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
containers := n.NodeMetadata.Counters[containersKey]
|
||||
@@ -346,19 +343,19 @@ func MapCountContainers(n RenderableNode) (RenderableNode, bool) {
|
||||
} else {
|
||||
n.LabelMinor = fmt.Sprintf("%d containers", containers)
|
||||
}
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
// MapAddress2Host maps address RenderableNodes to host RenderableNodes.
|
||||
//
|
||||
// Otherthan pseudo nodes, we can assume all nodes have a HostID
|
||||
func MapAddress2Host(n RenderableNode) (RenderableNode, bool) {
|
||||
func MapAddress2Host(n RenderableNode) RenderableNodes {
|
||||
if n.Pseudo {
|
||||
return n, true
|
||||
return RenderableNodes{n.ID: n}
|
||||
}
|
||||
|
||||
id := MakeHostID(report.ExtractHostID(n.NodeMetadata))
|
||||
return newDerivedNode(id, n), true
|
||||
return RenderableNodes{id: newDerivedNode(id, n)}
|
||||
}
|
||||
|
||||
// GenericPseudoNode makes a PseudoFunc given an addresser. The returned
|
||||
|
||||
@@ -72,7 +72,7 @@ type testcase struct {
|
||||
}
|
||||
|
||||
func testMap(t *testing.T, f render.LeafMapFunc, input testcase) {
|
||||
if _, have := f(input.md); input.ok != have {
|
||||
if have := f(input.md); input.ok != (len(have) > 0) {
|
||||
t.Errorf("%v: want %v, have %v", input.md, input.ok, have)
|
||||
}
|
||||
}
|
||||
|
||||
148
render/render.go
148
render/render.go
@@ -53,26 +53,24 @@ func (m Map) Render(rpt report.Report) RenderableNodes {
|
||||
return output
|
||||
}
|
||||
|
||||
func (m Map) render(rpt report.Report) (RenderableNodes, map[string]string) {
|
||||
func (m Map) render(rpt report.Report) (RenderableNodes, map[string]report.IDList) {
|
||||
input := m.Renderer.Render(rpt)
|
||||
output := RenderableNodes{}
|
||||
mapped := map[string]string{} // input node ID -> output node ID
|
||||
mapped := map[string]report.IDList{} // input node ID -> output node IDs
|
||||
adjacencies := map[string]report.IDList{} // output node ID -> input node Adjacencies
|
||||
|
||||
for _, inRenderable := range input {
|
||||
outRenderable, ok := m.MapFunc(inRenderable)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
outRenderables := m.MapFunc(inRenderable)
|
||||
for _, outRenderable := range outRenderables {
|
||||
existing, ok := output[outRenderable.ID]
|
||||
if ok {
|
||||
outRenderable.Merge(existing)
|
||||
}
|
||||
|
||||
existing, ok := output[outRenderable.ID]
|
||||
if ok {
|
||||
outRenderable.Merge(existing)
|
||||
output[outRenderable.ID] = outRenderable
|
||||
mapped[inRenderable.ID] = mapped[inRenderable.ID].Add(outRenderable.ID)
|
||||
adjacencies[outRenderable.ID] = adjacencies[outRenderable.ID].Merge(inRenderable.Adjacency)
|
||||
}
|
||||
|
||||
output[outRenderable.ID] = outRenderable
|
||||
mapped[inRenderable.ID] = outRenderable.ID
|
||||
adjacencies[outRenderable.ID] = adjacencies[outRenderable.ID].Merge(inRenderable.Adjacency)
|
||||
}
|
||||
|
||||
// Rewrite Adjacency for new node IDs.
|
||||
@@ -82,7 +80,7 @@ func (m Map) render(rpt report.Report) (RenderableNodes, map[string]string) {
|
||||
for outNodeID, inAdjacency := range adjacencies {
|
||||
outAdjacency := report.MakeIDList()
|
||||
for _, inAdjacent := range inAdjacency {
|
||||
if outAdjacent, ok := mapped[inAdjacent]; ok {
|
||||
for _, outAdjacent := range mapped[inAdjacent] {
|
||||
outAdjacency = outAdjacency.Add(outAdjacent)
|
||||
}
|
||||
}
|
||||
@@ -102,10 +100,12 @@ func (m Map) EdgeMetadata(rpt report.Report, srcRenderableID, dstRenderableID st
|
||||
// First we need to map the ids in this layer into the ids in the underlying layer
|
||||
_, mapped := m.render(rpt) // this maps from old -> new
|
||||
inverted := map[string][]string{} // this maps from new -> old(s)
|
||||
for k, v := range mapped {
|
||||
existing := inverted[v]
|
||||
existing = append(existing, k)
|
||||
inverted[v] = existing
|
||||
for k, vs := range mapped {
|
||||
for _, v := range vs {
|
||||
existing := inverted[v]
|
||||
existing = append(existing, k)
|
||||
inverted[v] = existing
|
||||
}
|
||||
}
|
||||
|
||||
// Now work out a slice of edges this edge is constructed from
|
||||
@@ -148,34 +148,31 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
|
||||
// Build a set of RenderableNodes for all non-pseudo probes, and an
|
||||
// addressID to nodeID lookup map. Multiple addressIDs can map to the same
|
||||
// RenderableNodes.
|
||||
source2mapped := map[string]string{} // source node ID -> mapped node ID
|
||||
source2mapped := map[string]report.IDList{} // source node ID -> mapped node IDs
|
||||
for nodeID, metadata := range t.NodeMetadatas {
|
||||
mapped, ok := m.Mapper(metadata)
|
||||
if !ok {
|
||||
continue
|
||||
for _, mapped := range m.Mapper(metadata) {
|
||||
// mapped.ID needs not be unique over all addressIDs. If not, we merge with
|
||||
// the existing data, on the assumption that the MapFunc returns the same
|
||||
// data.
|
||||
existing, ok := nodes[mapped.ID]
|
||||
if ok {
|
||||
mapped.Merge(existing)
|
||||
}
|
||||
|
||||
origins := mapped.Origins
|
||||
origins = origins.Add(nodeID)
|
||||
origins = origins.Add(metadata.Metadata[report.HostNodeID])
|
||||
mapped.Origins = origins
|
||||
|
||||
nodes[mapped.ID] = mapped
|
||||
source2mapped[nodeID] = source2mapped[nodeID].Add(mapped.ID)
|
||||
}
|
||||
|
||||
// mapped.ID needs not be unique over all addressIDs. If not, we merge with
|
||||
// the existing data, on the assumption that the MapFunc returns the same
|
||||
// data.
|
||||
existing, ok := nodes[mapped.ID]
|
||||
if ok {
|
||||
mapped.Merge(existing)
|
||||
}
|
||||
|
||||
origins := mapped.Origins
|
||||
origins = origins.Add(nodeID)
|
||||
origins = origins.Add(metadata.Metadata[report.HostNodeID])
|
||||
mapped.Origins = origins
|
||||
|
||||
nodes[mapped.ID] = mapped
|
||||
source2mapped[nodeID] = mapped.ID
|
||||
}
|
||||
|
||||
mkPseudoNode := func(srcNodeID, dstNodeID string, srcIsClient bool) (string, bool) {
|
||||
mkPseudoNode := func(srcNodeID, dstNodeID string, srcIsClient bool) report.IDList {
|
||||
pseudoNode, ok := m.Pseudo(srcNodeID, dstNodeID, srcIsClient, localNetworks)
|
||||
if !ok {
|
||||
return "", false
|
||||
return report.MakeIDList()
|
||||
}
|
||||
pseudoNode.Origins = pseudoNode.Origins.Add(srcNodeID)
|
||||
existing, ok := nodes[pseudoNode.ID]
|
||||
@@ -184,8 +181,8 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
|
||||
}
|
||||
|
||||
nodes[pseudoNode.ID] = pseudoNode
|
||||
source2mapped[pseudoNode.ID] = srcNodeID
|
||||
return pseudoNode.ID, true
|
||||
source2mapped[pseudoNode.ID] = source2mapped[pseudoNode.ID].Add(srcNodeID)
|
||||
return report.MakeIDList(pseudoNode.ID)
|
||||
}
|
||||
|
||||
// Walk the graph and make connections.
|
||||
@@ -196,7 +193,7 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
|
||||
continue
|
||||
}
|
||||
|
||||
srcRenderableID, ok := source2mapped[srcNodeID]
|
||||
srcRenderableIDs, ok := source2mapped[srcNodeID]
|
||||
if !ok {
|
||||
// One of the entries in dsts must be a non-pseudo node
|
||||
var existingDstNodeID string
|
||||
@@ -207,40 +204,52 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
|
||||
}
|
||||
}
|
||||
|
||||
srcRenderableID, ok = mkPseudoNode(srcNodeID, existingDstNodeID, true)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
srcRenderableIDs = mkPseudoNode(srcNodeID, existingDstNodeID, true)
|
||||
}
|
||||
if len(srcRenderableIDs) == 0 {
|
||||
continue
|
||||
}
|
||||
srcRenderableNode := nodes[srcRenderableID]
|
||||
|
||||
for _, dstNodeID := range dsts {
|
||||
dstRenderableID, ok := source2mapped[dstNodeID]
|
||||
if !ok {
|
||||
dstRenderableID, ok = mkPseudoNode(dstNodeID, srcNodeID, false)
|
||||
for _, srcRenderableID := range srcRenderableIDs {
|
||||
srcRenderableNode := nodes[srcRenderableID]
|
||||
|
||||
for _, dstNodeID := range dsts {
|
||||
dstRenderableIDs, ok := source2mapped[dstNodeID]
|
||||
if !ok {
|
||||
dstRenderableIDs = mkPseudoNode(dstNodeID, srcNodeID, false)
|
||||
}
|
||||
if len(dstRenderableIDs) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
dstRenderableNode := nodes[dstRenderableID]
|
||||
for _, dstRenderableID := range dstRenderableIDs {
|
||||
dstRenderableNode := nodes[dstRenderableID]
|
||||
srcRenderableNode.Adjacency = srcRenderableNode.Adjacency.Add(dstRenderableID)
|
||||
|
||||
srcRenderableNode.Adjacency = srcRenderableNode.Adjacency.Add(dstRenderableID)
|
||||
|
||||
// We propagate edge metadata to nodes on both ends of the edges.
|
||||
// TODO we should 'reverse' one end of the edge meta data - ingress -> egress etc.
|
||||
if md, ok := t.EdgeMetadatas[report.MakeEdgeID(srcNodeID, dstNodeID)]; ok {
|
||||
srcRenderableNode.EdgeMetadata = srcRenderableNode.EdgeMetadata.Merge(md)
|
||||
dstRenderableNode.EdgeMetadata = dstRenderableNode.EdgeMetadata.Merge(md)
|
||||
nodes[dstRenderableID] = dstRenderableNode
|
||||
// We propagate edge metadata to nodes on both ends of the edges.
|
||||
// TODO we should 'reverse' one end of the edge meta data - ingress -> egress etc.
|
||||
if md, ok := t.EdgeMetadatas[report.MakeEdgeID(srcNodeID, dstNodeID)]; ok {
|
||||
srcRenderableNode.EdgeMetadata = srcRenderableNode.EdgeMetadata.Merge(md)
|
||||
dstRenderableNode.EdgeMetadata = dstRenderableNode.EdgeMetadata.Merge(md)
|
||||
nodes[dstRenderableID] = dstRenderableNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodes[srcRenderableID] = srcRenderableNode
|
||||
}
|
||||
|
||||
nodes[srcRenderableID] = srcRenderableNode
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
func ids(nodes RenderableNodes) report.IDList {
|
||||
result := report.MakeIDList()
|
||||
for id := range nodes {
|
||||
result = result.Add(id)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EdgeMetadata gives the metadata of an edge from the perspective of the
|
||||
// srcRenderableID. Since an edgeID can have multiple edges on the address
|
||||
// level, it uses the supplied mapping function to translate address IDs to
|
||||
@@ -254,15 +263,16 @@ func (m LeafMap) EdgeMetadata(rpt report.Report, srcRenderableID, dstRenderableI
|
||||
log.Printf("bad edge ID %q", edgeID)
|
||||
continue
|
||||
}
|
||||
srcs, dsts := report.MakeIDList(src), report.MakeIDList(dst)
|
||||
if src != report.TheInternet {
|
||||
mapped, _ := m.Mapper(t.NodeMetadatas[src])
|
||||
src = mapped.ID
|
||||
mapped := m.Mapper(t.NodeMetadatas[src])
|
||||
srcs = ids(mapped)
|
||||
}
|
||||
if dst != report.TheInternet {
|
||||
mapped, _ := m.Mapper(t.NodeMetadatas[dst])
|
||||
dst = mapped.ID
|
||||
mapped := m.Mapper(t.NodeMetadatas[dst])
|
||||
dsts = ids(mapped)
|
||||
}
|
||||
if src == srcRenderableID && dst == dstRenderableID {
|
||||
if srcs.Contains(srcRenderableID) && dsts.Contains(dstRenderableID) {
|
||||
metadata = metadata.Flatten(edgeMeta)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ func TestReduceEdge(t *testing.T) {
|
||||
func TestMapRender1(t *testing.T) {
|
||||
// 1. Check when we return false, the node gets filtered out
|
||||
mapper := render.Map{
|
||||
MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) {
|
||||
return render.RenderableNode{}, false
|
||||
MapFunc: func(nodes render.RenderableNode) render.RenderableNodes {
|
||||
return render.RenderableNodes{}
|
||||
},
|
||||
Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{
|
||||
"foo": {ID: "foo"},
|
||||
@@ -69,8 +69,8 @@ func TestMapRender1(t *testing.T) {
|
||||
func TestMapRender2(t *testing.T) {
|
||||
// 2. Check we can remap two nodes into one
|
||||
mapper := render.Map{
|
||||
MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) {
|
||||
return render.RenderableNode{ID: "bar"}, true
|
||||
MapFunc: func(nodes render.RenderableNode) render.RenderableNodes {
|
||||
return render.RenderableNodes{"bar": render.RenderableNode{ID: "bar"}}
|
||||
},
|
||||
Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{
|
||||
"foo": {ID: "foo"},
|
||||
@@ -89,8 +89,9 @@ func TestMapRender2(t *testing.T) {
|
||||
func TestMapRender3(t *testing.T) {
|
||||
// 3. Check we can remap adjacencies
|
||||
mapper := render.Map{
|
||||
MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) {
|
||||
return render.RenderableNode{ID: "_" + nodes.ID}, true
|
||||
MapFunc: func(nodes render.RenderableNode) render.RenderableNodes {
|
||||
id := "_" + nodes.ID
|
||||
return render.RenderableNodes{id: render.RenderableNode{ID: id}}
|
||||
},
|
||||
Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{
|
||||
"foo": {ID: "foo", Adjacency: report.MakeIDList("baz")},
|
||||
@@ -125,13 +126,14 @@ func TestMapEdge(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
identity := func(nmd report.NodeMetadata) (render.RenderableNode, bool) {
|
||||
return render.NewRenderableNode(nmd.Metadata["id"], "", "", "", nmd), true
|
||||
identity := func(nmd report.NodeMetadata) render.RenderableNodes {
|
||||
return render.RenderableNodes{nmd.Metadata["id"]: render.NewRenderableNode(nmd.Metadata["id"], "", "", "", nmd)}
|
||||
}
|
||||
|
||||
mapper := render.Map{
|
||||
MapFunc: func(n render.RenderableNode) (render.RenderableNode, bool) {
|
||||
return render.RenderableNode{ID: "_" + n.ID}, true
|
||||
MapFunc: func(nodes render.RenderableNode) render.RenderableNodes {
|
||||
id := "_" + nodes.ID
|
||||
return render.RenderableNodes{id: render.RenderableNode{ID: id}}
|
||||
},
|
||||
Renderer: render.LeafMap{
|
||||
Selector: selector,
|
||||
|
||||
Reference in New Issue
Block a user