Files
weave-scope/render/render.go
Paul Bellamy 2c6b6e6707 Refactoring rendering to remove RenderableNode
Squash of:
- use detailed.Summaries to render topology nodes
- ban merging nodes of different topologies (they should be mapped)
- need to prune parents when mapping node types
- render container images by id if they have no name
- remove separate render ids and prune parents in NewDerived*
- don't render metrics/metadata for groups of nodes
- fixing up tests
- removing pending unit tests (for mapping.go, for now)
- updating experimental dir for RenderableNode removal
2016-03-29 14:13:03 +01:00

112 lines
2.9 KiB
Go

package render
import (
"github.com/weaveworks/scope/report"
)
// Renderer is something that can render a report to a set of Nodes.
type Renderer interface {
Render(report.Report) report.Nodes
Stats(report.Report) Stats
}
// Stats is the type returned by Renderer.Stats
type Stats struct {
FilteredNodes int
}
func (s Stats) merge(other Stats) Stats {
return Stats{
FilteredNodes: s.FilteredNodes + other.FilteredNodes,
}
}
// Reduce renderer is a Renderer which merges together the output of several
// other renderers.
type Reduce []Renderer
// MakeReduce is the only sane way to produce a Reduce Renderer.
func MakeReduce(renderers ...Renderer) Renderer {
r := Reduce(renderers)
return Memoise(&r)
}
// Render produces a set of Nodes given a Report.
func (r *Reduce) Render(rpt report.Report) report.Nodes {
result := report.Nodes{}
for _, renderer := range *r {
result = result.Merge(renderer.Render(rpt))
}
return result
}
// Stats implements Renderer
func (r *Reduce) Stats(rpt report.Report) Stats {
var result Stats
for _, renderer := range *r {
result = result.merge(renderer.Stats(rpt))
}
return result
}
// Map is a Renderer which produces a set of Nodes from the set of
// Nodes produced by another Renderer.
type Map struct {
MapFunc
Renderer
}
// MakeMap makes a new Map
func MakeMap(f MapFunc, r Renderer) Renderer {
return Memoise(&Map{f, r})
}
// Render transforms a set of Nodes produces by another Renderer.
// using a map function
func (m *Map) Render(rpt report.Report) report.Nodes {
var (
input = m.Renderer.Render(rpt)
output = report.Nodes{}
mapped = map[string]report.IDList{} // input node ID -> output node IDs
adjacencies = map[string]report.IDList{} // output node ID -> input node Adjacencies
localNetworks = LocalNetworks(rpt)
)
// Rewrite all the nodes according to the map function
for _, inRenderable := range input {
for _, outRenderable := range m.MapFunc(inRenderable, localNetworks) {
existing, ok := output[outRenderable.ID]
if ok {
outRenderable = 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)
}
}
// Rewrite Adjacency for new node IDs.
for outNodeID, inAdjacency := range adjacencies {
outAdjacency := report.MakeIDList()
for _, inAdjacent := range inAdjacency {
for _, outAdjacent := range mapped[inAdjacent] {
outAdjacency = outAdjacency.Add(outAdjacent)
}
}
outNode := output[outNodeID]
outNode.Adjacency = outAdjacency
output[outNodeID] = outNode
}
return output
}
// Stats implements Renderer
func (m *Map) Stats(rpt report.Report) Stats {
// There doesn't seem to be an instance where we want stats to recurse
// through Maps - for instance we don't want to see the number of filtered
// processes in the container renderer.
return Stats{}
}