diff --git a/client/app/scripts/utils/__tests__/topology-utils-test.js b/client/app/scripts/utils/__tests__/topology-utils-test.js index 7010bb4147..7d2e5bc144 100644 --- a/client/app/scripts/utils/__tests__/topology-utils-test.js +++ b/client/app/scripts/utils/__tests__/topology-utils-test.js @@ -108,12 +108,12 @@ describe('TopologyUtils', () => { }); describe('filterHiddenTopologies', () => { - it('should filter out empty topos that set hidden_if_empty=true', () => { + it('should filter out empty topos that set hide_if_empty=true', () => { const topos = [ - {id: 'a', hidden_if_empty: true, stats: {node_count: 0, filtered_nodes:0}}, - {id: 'b', hidden_if_empty: true, stats: {node_count: 1, filtered_nodes:0}}, - {id: 'c', hidden_if_empty: true, stats: {node_count: 0, filtered_nodes:1}}, - {id: 'd', hidden_if_empty: false, stats: {node_count: 0, filtered_nodes:0}} + {id: 'a', hide_if_empty: true, stats: {node_count: 0, filtered_nodes:0}}, + {id: 'b', hide_if_empty: true, stats: {node_count: 1, filtered_nodes:0}}, + {id: 'c', hide_if_empty: true, stats: {node_count: 0, filtered_nodes:1}}, + {id: 'd', hide_if_empty: false, stats: {node_count: 0, filtered_nodes:0}} ]; const res = TopologyUtils.filterHiddenTopologies(topos); diff --git a/client/app/scripts/utils/topology-utils.js b/client/app/scripts/utils/topology-utils.js index 5987af9bc1..0d4036feb0 100644 --- a/client/app/scripts/utils/topology-utils.js +++ b/client/app/scripts/utils/topology-utils.js @@ -55,6 +55,6 @@ export function setTopologyUrlsById(topologyUrlsById, topologies) { } export function filterHiddenTopologies(topologies) { - return topologies.filter(t => (!t.hidden_if_empty || t.stats.node_count > 0 || + return topologies.filter(t => (!t.hide_if_empty || t.stats.node_count > 0 || t.stats.filtered_nodes > 0)); } diff --git a/render/filters.go b/render/filters.go index 07745abe47..24de14aa2c 100644 --- a/render/filters.go +++ b/render/filters.go @@ -59,11 +59,24 @@ func ColorConnected(r Renderer) Renderer { type Filter struct { Renderer FilterFunc func(report.Node) bool + Silent bool // true means we don't report stats for how many are filtered } // MakeFilter makes a new Filter. func MakeFilter(f func(report.Node) bool, r Renderer) Renderer { - return Memoise(&Filter{r, f}) + return Memoise(&Filter{ + Renderer: r, + FilterFunc: f, + }) +} + +// MakeSilentFilter makes a new Filter which does not report how many nodes it filters in Stats. +func MakeSilentFilter(f func(report.Node) bool, r Renderer) Renderer { + return Memoise(&Filter{ + Renderer: r, + FilterFunc: f, + Silent: true, + }) } // Render implements Renderer @@ -115,9 +128,11 @@ func (f *Filter) render(rpt report.Report) (report.Nodes, int) { // Stats implements Renderer func (f Filter) Stats(rpt report.Report) Stats { - _, filtered := f.render(rpt) var upstream = f.Renderer.Stats(rpt) - upstream.FilteredNodes += filtered + if !f.Silent { + _, filtered := f.render(rpt) + upstream.FilteredNodes += filtered + } return upstream } @@ -154,6 +169,18 @@ func FilterUnconnected(r Renderer) Renderer { ) } +// SilentFilterUnconnected produces a renderer that filters unconnected nodes +// from the given renderer; nodes filtered by this are not reported in stats. +func SilentFilterUnconnected(r Renderer) Renderer { + return MakeSilentFilter( + func(node report.Node) bool { + _, ok := node.Latest.Lookup(IsConnected) + return ok + }, + ColorConnected(r), + ) +} + // FilterNoop does nothing. func FilterNoop(in Renderer) Renderer { return in @@ -177,7 +204,7 @@ func FilterRunning(r Renderer) Renderer { // FilterNonProcspied removes endpoints which were not found in procspy. func FilterNonProcspied(r Renderer) Renderer { - return MakeFilter( + return MakeSilentFilter( func(node report.Node) bool { _, ok := node.Latest.Lookup(endpoint.Procspied) return ok diff --git a/render/topologies.go b/render/topologies.go index b7656bda41..3752dcac12 100644 --- a/render/topologies.go +++ b/render/topologies.go @@ -69,11 +69,10 @@ var ProcessNameRenderer = MakeMap( // but we need to be careful to ensure we only include each edge once, by only // including the ProcessRenderer once. var ContainerRenderer = MakeReduce( - MakeFilter( + MakeSilentFilter( func(n report.Node) bool { - _, inContainer := n.Latest.Lookup(docker.ContainerID) _, isConnected := n.Latest.Lookup(IsConnected) - return inContainer || isConnected + return n.Topology != Pseudo || isConnected }, MakeMap( MapProcess2Container, @@ -85,7 +84,7 @@ var ContainerRenderer = MakeReduce( // We need to be careful to ensure we only include each edge once. Edges brought in // by the above renders will have a pid, so its enough to filter out any nodes with // pids. - FilterUnconnected(MakeMap( + SilentFilterUnconnected(MakeMap( MapIP2Container, MakeReduce( MakeMap( @@ -224,9 +223,15 @@ var HostRenderer = MakeReduce( // PodRenderer is a Renderer which produces a renderable kubernetes // graph by merging the container graph and the pods topology. var PodRenderer = MakeReduce( - MakeMap( - MapContainer2Pod, - ContainerRenderer, + MakeSilentFilter( + func(n report.Node) bool { + _, isConnected := n.Latest.Lookup(IsConnected) + return n.Topology != Pseudo || isConnected + }, + ColorConnected(MakeMap( + MapContainer2Pod, + ContainerRenderer, + )), ), SelectPod, )