diff --git a/app/api_topology.go b/app/api_topology.go index fedf7bddd..43c0f3668 100644 --- a/app/api_topology.go +++ b/app/api_topology.go @@ -38,11 +38,12 @@ func handleTopology(ctx context.Context, renderer render.Renderer, decorator ren // Individual nodes. func handleNode(ctx context.Context, renderer render.Renderer, decorator render.Decorator, report report.Report, w http.ResponseWriter, r *http.Request) { var ( - vars = mux.Vars(r) - topologyID = vars["topology"] - nodeID = vars["id"] - rendered = renderer.Render(report, decorator) - node, ok = rendered[nodeID] + vars = mux.Vars(r) + topologyID = vars["topology"] + nodeID = vars["id"] + preciousRenderer = render.PreciousNodeRenderer{nodeID, renderer} + rendered = preciousRenderer.Render(report, decorator) + node, ok = rendered[nodeID] ) if !ok { http.NotFound(w, r) diff --git a/render/filters.go b/render/filters.go index 347ca36f3..c1d2ea9e4 100644 --- a/render/filters.go +++ b/render/filters.go @@ -10,6 +10,28 @@ import ( "github.com/weaveworks/scope/report" ) +// PreciousNodeRenderer ensures a node is never filtered out by decorators +type PreciousNodeRenderer struct { + PreciousNodeID string + Renderer +} + +func (p PreciousNodeRenderer) Render(rpt report.Report, dct Decorator) report.Nodes { + undecoratedNodes := p.Renderer.Render(rpt, nil) + preciousNode, foundBeforeDecoration := undecoratedNodes[p.PreciousNodeID] + finalNodes := applyDecorator{ConstantRenderer(undecoratedNodes)}.Render(rpt, dct) + if _, ok := finalNodes[p.PreciousNodeID]; !ok && foundBeforeDecoration { + finalNodes[p.PreciousNodeID] = preciousNode + } + return finalNodes +} + +func (p PreciousNodeRenderer) Stats(rpt report.Report, dct Decorator) Stats { + // default to the underlying renderer + // TODO: we don't take into account the precious node, so we may be off by one + return p.Renderer.Stats(rpt, dct) +} + // CustomRenderer allow for mapping functions that received the entire topology // in one call - useful for functions that need to consider the entire graph. // We should minimise the use of this renderer type, as it is very inflexible. diff --git a/render/render.go b/render/render.go index 9a9078a3e..2a11bdeff 100644 --- a/render/render.go +++ b/render/render.go @@ -185,3 +185,14 @@ func (cr conditionalRenderer) Stats(rpt report.Report, dct Decorator) Stats { } return Stats{} } + +// ConstantRenderer renders a fixed set of nodes +type ConstantRenderer report.Nodes + +func (c ConstantRenderer) Render(_ report.Report, _ Decorator) report.Nodes { + return report.Nodes(c) +} + +func (c ConstantRenderer) Stats(_ report.Report, _ Decorator) Stats { + return Stats{} +}