diff --git a/render/container.go b/render/container.go index f8f0dbd84f..5ee885d2da 100644 --- a/render/container.go +++ b/render/container.go @@ -71,8 +71,7 @@ func (c connectionJoin) Render(rpt report.Report, dct Decorator) report.Nodes { } } } - var ret = make(report.Nodes) - var mapped = map[string]string{} // input node ID -> output node ID + ret := newJoinResults() // Now look at all the endpoints and see which map to IP nodes for _, m := range endpoints { @@ -83,7 +82,7 @@ func (c connectionJoin) Render(rpt report.Report, dct Decorator) report.Nodes { // 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 { - addToResults(m, id, ret, mapped, newPseudoNode) + ret.addToResults(m, id, newPseudoNode) continue } } @@ -95,20 +94,15 @@ func (c connectionJoin) Render(rpt report.Report, dct Decorator) report.Nodes { id, found = ipNodes[report.MakeScopedEndpointNodeID(scope, addr, port)] } if found && id != "" { // not one we blanked out earlier - addToResults(m, id, ret, mapped, func(id string) report.Node { + ret.addToResults(m, id, func(id string) report.Node { return inputNodes[id] }) } } - // Copy through any unmatched input nodes - for _, n := range inputNodes { - if _, found := ret[n.ID]; !found { - ret[n.ID] = n - } - } - fixupAdjancencies(inputNodes, ret, mapped) - fixupAdjancencies(endpoints, ret, mapped) - return ret + ret.copyUnmatched(inputNodes) + ret.fixupAdjacencies(inputNodes) + ret.fixupAdjacencies(endpoints) + return ret.nodes } func (c connectionJoin) Stats(rpt report.Report, _ Decorator) Stats { diff --git a/render/host.go b/render/host.go index 384c47f5ac..8ce144d0a1 100644 --- a/render/host.go +++ b/render/host.go @@ -69,9 +69,8 @@ type endpoints2Hosts struct { func (e endpoints2Hosts) Render(rpt report.Report, dct Decorator) report.Nodes { ns := SelectEndpoint.Render(rpt, dct) local := LocalNetworks(rpt) + ret := newJoinResults() - var ret = make(report.Nodes) - var mapped = map[string]string{} // input node ID -> output node ID for _, n := range ns { // Nodes without a hostid are treated as pseudo nodes hostNodeID, timestamp, ok := n.Latest.LookupEntry(report.HostNodeID) @@ -80,50 +79,17 @@ func (e endpoints2Hosts) Render(rpt report.Report, dct Decorator) report.Nodes { if !ok { continue } - addToResults(n, id, ret, mapped, newPseudoNode) + ret.addToResults(n, id, newPseudoNode) } else { id := report.MakeHostNodeID(report.ExtractHostID(n)) - addToResults(n, id, ret, mapped, func(id string) report.Node { + ret.addToResults(n, id, func(id string) report.Node { return report.MakeNode(id).WithTopology(report.Host). WithLatest(report.HostNodeID, timestamp, hostNodeID) }) } } - fixupAdjancencies(ns, ret, mapped) - return ret -} - -// Add Node M to the result set ret under id, creating a new result -// node if not already there, and updating the old-id to new-id mapping -// Note we do not update any counters for child topologies here -func addToResults(m report.Node, id string, ret report.Nodes, mapped map[string]string, create func(string) report.Node) { - result, exists := ret[id] - if !exists { - result = create(id) - } - result.Children = result.Children.Add(m) - result.Children = result.Children.Merge(m.Children) - ret[id] = result - mapped[m.ID] = id -} - -// Rewrite Adjacency for new nodes in ret, original nodes in input, and mapping old->new IDs in mapped -func fixupAdjancencies(input, ret report.Nodes, mapped map[string]string) { - for _, n := range input { - outID, ok := mapped[n.ID] - if !ok { - continue - } - out := ret[outID] - // for each adjacency in the original node, find out what it maps to (if any), - // and add that to the new node - for _, a := range n.Adjacency { - if mappedDest, found := mapped[a]; found { - out.Adjacency = out.Adjacency.Add(mappedDest) - } - } - ret[outID] = out - } + ret.fixupAdjacencies(ns) + return ret.nodes } func (e endpoints2Hosts) Stats(rpt report.Report, _ Decorator) Stats { diff --git a/render/process.go b/render/process.go index e4288d3b59..f42db7c0aa 100644 --- a/render/process.go +++ b/render/process.go @@ -93,14 +93,13 @@ func (e endpoints2Processes) Render(rpt report.Report, dct Decorator) report.Nod processes := SelectProcess.Render(rpt, dct) endpoints := SelectEndpoint.Render(rpt, dct) local := LocalNetworks(rpt) + ret := newJoinResults() - var ret = make(report.Nodes) - var mapped = map[string]string{} // input node ID -> output node ID for _, n := range endpoints { // 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 { - addToResults(n, id, ret, mapped, newPseudoNode) + ret.addToResults(n, id, newPseudoNode) } } else { pid, timestamp, ok := n.Latest.LookupEntry(process.PID) @@ -117,7 +116,7 @@ func (e endpoints2Processes) Render(rpt report.Report, dct Decorator) report.Nod hostID, _, _ := report.ParseNodeID(hostNodeID) id := report.MakeProcessNodeID(hostID, pid) - addToResults(n, id, ret, mapped, func(id string) report.Node { + ret.addToResults(n, id, func(id string) report.Node { if processNode, found := processes[id]; found { return processNode } @@ -127,15 +126,10 @@ func (e endpoints2Processes) Render(rpt report.Report, dct Decorator) report.Nod }) } } - // Copy through any unmatched process nodes - for _, n := range processes { - if _, found := ret[n.ID]; !found { - ret[n.ID] = n - } - } - fixupAdjancencies(processes, ret, mapped) - fixupAdjancencies(endpoints, ret, mapped) - return ret + ret.copyUnmatched(processes) + ret.fixupAdjacencies(processes) + ret.fixupAdjacencies(endpoints) + return ret.nodes } func (e endpoints2Processes) Stats(rpt report.Report, _ Decorator) Stats { diff --git a/render/render.go b/render/render.go index 2e43575887..32205eb8a3 100644 --- a/render/render.go +++ b/render/render.go @@ -207,3 +207,55 @@ func (c ConstantRenderer) Render(_ report.Report, _ Decorator) report.Nodes { func (c ConstantRenderer) Stats(_ report.Report, _ Decorator) Stats { return Stats{} } + +// joinResults is used by Renderers that join sets of nodes +type joinResults struct { + nodes report.Nodes + mapped map[string]string // input node ID -> output node ID +} + +func newJoinResults() joinResults { + return joinResults{nodes: make(report.Nodes), mapped: map[string]string{}} +} + +// Add Node M under id, creating a new result node if not already there +// and updating the mapping from old ID to new ID +// Note we do not update any counters for child topologies here, because addToResults +// is only ever called when m is an endpoint and we never look at endpoint counts +func (ret *joinResults) addToResults(m report.Node, id string, create func(string) report.Node) { + result, exists := ret.nodes[id] + if !exists { + result = create(id) + } + result.Children = result.Children.Add(m) + result.Children = result.Children.Merge(m.Children) + ret.nodes[id] = result + ret.mapped[m.ID] = id +} + +// Rewrite Adjacency for new nodes in ret for original nodes in input +func (ret *joinResults) fixupAdjacencies(input report.Nodes) { + for _, n := range input { + outID, ok := ret.mapped[n.ID] + if !ok { + continue + } + out := ret.nodes[outID] + // for each adjacency in the original node, find out what it maps to (if any), + // and add that to the new node + for _, a := range n.Adjacency { + if mappedDest, found := ret.mapped[a]; found { + out.Adjacency = out.Adjacency.Add(mappedDest) + } + } + ret.nodes[outID] = out + } +} + +func (ret *joinResults) copyUnmatched(input report.Nodes) { + for _, n := range input { + if _, found := ret.nodes[n.ID]; !found { + ret.nodes[n.ID] = n + } + } +}