From 87a2655e6702d5fd35c6b2c2ff9c1b8586a948df Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Tue, 23 May 2017 04:01:04 -0700 Subject: [PATCH] Add new Renderer type to include full node data without changing node set The nodes returned from Map2Parent are mostly empty, and need joining with their full topologies before being useful. But we want to filter out any nodes that weren't already in the graph. We make a new Renderer type to implement this. We also add the missing types to the type option group --- app/api_topologies.go | 2 ++ render/pod.go | 23 ++++++++++++++++------- render/render.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/app/api_topologies.go b/app/api_topologies.go index 21dee103d..5d9cb6dc5 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -204,6 +204,8 @@ func MakeRegistry() *Registry { Options: []APITopologyOption{ {Value: report.Deployment, Label: "Deployments", filter: render.IsTopology(report.Deployment), filterPseudo: false}, {Value: report.DaemonSet, Label: "Daemonsets", filter: render.IsTopology(report.DaemonSet), filterPseudo: false}, + {Value: report.ReplicaSet, Label: "Replica sets", filter: render.IsTopology(report.ReplicaSet), filterPseudo: false}, + {Value: report.Pod, Label: "Pods", filter: render.IsTopology(report.Pod), filterPseudo: false}, }, } diff --git a/render/pod.go b/render/pod.go index 6caf168b5..4707c0882 100644 --- a/render/pod.go +++ b/render/pod.go @@ -127,16 +127,25 @@ var DaemonSetRenderer = ConditionalRenderer(renderKubernetesTopologies, // unchanged). // We can't simply combine the rendered graphs of the high level objects as they would never // have connections to each other. +// We combine with all the full topologies using ReduceFirstOnly, which keeps the same +// set of nodes but merges in the full data from the other renderers. var KubeCombinedRenderer = ConditionalRenderer(renderKubernetesTopologies, - MakeMap( - Map2Parent([]string{report.Deployment}, NoParentsKeep, "", nil), + MakeReduceFirstOnly( MakeMap( - Map2Parent([]string{ - report.ReplicaSet, - report.DaemonSet, - }, NoParentsKeep, "", nil), - PodRenderer, + Map2Parent([]string{report.Deployment}, NoParentsKeep, "", nil), + MakeReduceFirstOnly( + MakeMap( + Map2Parent([]string{ + report.ReplicaSet, + report.DaemonSet, + }, NoParentsKeep, "", nil), + PodRenderer, + ), + SelectReplicaSet, + SelectDaemonSet, + ), ), + SelectDeployment, ), ) diff --git a/render/render.go b/render/render.go index 415bc3ffb..7b2582fa6 100644 --- a/render/render.go +++ b/render/render.go @@ -55,6 +55,40 @@ func (r *Reduce) Stats(rpt report.Report, dct Decorator) Stats { return result } +// ReduceFirstOnly renderer is a Renderer which merges together the output of several other renderers, +// including only the nodes present in the first render, but merging in info from the same nodes +// if present in the other renders. +type ReduceFirstOnly struct { + first Renderer + others []Renderer +} + +// MakeReduceFirstOnly is the only sane way to produce a ReduceFirstOnly Renderer. +func MakeReduceFirstOnly(first Renderer, others ...Renderer) Renderer { + r := ReduceFirstOnly{first, others} + return Memoise(&r) +} + +// Render produces a set of Nodes given a Report. +func (r *ReduceFirstOnly) Render(rpt report.Report, dct Decorator) report.Nodes { + result := r.first.Render(rpt, dct).Copy() + for _, other := range r.others { + for id, node := range other.Render(rpt, dct) { + if n, ok := result[id]; ok { + result[id] = n.Merge(node) + } + } + } + return result +} + +// Stats implements Renderer +func (r *ReduceFirstOnly) Stats(rpt report.Report, dct Decorator) Stats { + // Since we're just taking more detailed data from the other renderers, + // we probably only care about the filter stats for the 'main' renderer. + return r.first.Stats(rpt, dct) +} + // Map is a Renderer which produces a set of Nodes from the set of // Nodes produced by another Renderer. type Map struct {