mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-02 17:50:39 +00:00
Introduce renderers; allow them to recurse.
This commit is contained in:
2
Makefile
2
Makefile
@@ -21,7 +21,7 @@ $(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) docker/*
|
||||
$(SUDO) docker build -t $(SCOPE_IMAGE) docker/
|
||||
$(SUDO) docker save $(SCOPE_IMAGE):latest | sudo $(DOCKER_SQUASH) -t $(SCOPE_IMAGE) | tee $@ | $(SUDO) docker load
|
||||
|
||||
$(APP_EXE): app/*.go report/*.go xfer/*.go
|
||||
$(APP_EXE): app/*.go render/*.go report/*.go xfer/*.go
|
||||
|
||||
$(PROBE_EXE): probe/*.go probe/tag/*.go report/*.go xfer/*.go
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ func makeTopologyList(rep Reporter) func(w http.ResponseWriter, r *http.Request)
|
||||
subTopologies = append(subTopologies, APITopologyDesc{
|
||||
Name: subDef.human,
|
||||
URL: "/api/topology/" + subName,
|
||||
Stats: stats(render(rpt, subDef.maps)),
|
||||
Stats: stats(subDef.renderer.Render(rpt)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func makeTopologyList(rep Reporter) func(w http.ResponseWriter, r *http.Request)
|
||||
Name: def.human,
|
||||
URL: "/api/topology/" + name,
|
||||
SubTopologies: subTopologies,
|
||||
Stats: stats(render(rpt, def.maps)),
|
||||
Stats: stats(def.renderer.Render(rpt)),
|
||||
})
|
||||
}
|
||||
respondWith(w, http.StatusOK, topologies)
|
||||
|
||||
@@ -30,19 +30,10 @@ type APIEdge struct {
|
||||
Metadata report.AggregateMetadata `json:"metadata"`
|
||||
}
|
||||
|
||||
func render(rpt report.Report, maps []topologyMapper) report.RenderableNodes {
|
||||
result := report.RenderableNodes{}
|
||||
for _, m := range maps {
|
||||
rns := m.selector(rpt).RenderBy(m.mapper, m.pseudo)
|
||||
result.Merge(rns)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Full topology.
|
||||
func handleTopology(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Request) {
|
||||
respondWith(w, http.StatusOK, APITopology{
|
||||
Nodes: render(rep.Report(), t.maps),
|
||||
Nodes: t.renderer.Render(rep.Report()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -69,7 +60,7 @@ func handleNode(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Req
|
||||
vars = mux.Vars(r)
|
||||
nodeID = vars["id"]
|
||||
rpt = rep.Report()
|
||||
node, ok = render(rpt, t.maps)[nodeID]
|
||||
node, ok = t.renderer.Render(rep.Report())[nodeID]
|
||||
)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
@@ -85,13 +76,9 @@ func handleEdge(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Req
|
||||
localID = vars["local"]
|
||||
remoteID = vars["remote"]
|
||||
rpt = rep.Report()
|
||||
metadata = report.AggregateMetadata{}
|
||||
metadata = t.renderer.AggregateMetadata(rpt, localID, remoteID)
|
||||
)
|
||||
|
||||
for _, m := range t.maps {
|
||||
metadata.Merge(m.selector(rpt).EdgeMetadata(m.mapper, localID, remoteID).Transform())
|
||||
}
|
||||
|
||||
respondWith(w, http.StatusOK, APIEdge{Metadata: metadata})
|
||||
}
|
||||
|
||||
@@ -128,7 +115,7 @@ func handleWebsocket(
|
||||
tick = time.Tick(loop)
|
||||
)
|
||||
for {
|
||||
newTopo := render(rep.Report(), t.maps)
|
||||
newTopo := t.renderer.Render(rep.Report())
|
||||
diff := report.TopoDiff(previousTopo, newTopo)
|
||||
previousTopo = newTopo
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -47,51 +48,37 @@ func apiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var topologyRegistry = map[string]topologyView{
|
||||
"applications": {
|
||||
human: "Applications",
|
||||
parent: "",
|
||||
maps: []topologyMapper{
|
||||
{report.SelectEndpoint, report.ProcessPID, report.GenericPseudoNode},
|
||||
},
|
||||
human: "Applications",
|
||||
parent: "",
|
||||
renderer: render.Map{Selector: report.SelectEndpoint, Mapper: report.ProcessPID, Pseudo: report.GenericPseudoNode},
|
||||
},
|
||||
"applications-by-name": {
|
||||
human: "by name",
|
||||
parent: "applications",
|
||||
maps: []topologyMapper{
|
||||
{report.SelectEndpoint, report.ProcessName, report.GenericGroupedPseudoNode},
|
||||
},
|
||||
human: "by name",
|
||||
parent: "applications",
|
||||
renderer: render.Map{Selector: report.SelectEndpoint, Mapper: report.ProcessName, Pseudo: report.GenericGroupedPseudoNode},
|
||||
},
|
||||
"containers": {
|
||||
human: "Containers",
|
||||
parent: "",
|
||||
maps: []topologyMapper{
|
||||
{report.SelectEndpoint, report.MapEndpoint2Container, report.InternetOnlyPseudoNode},
|
||||
{report.SelectContainer, report.MapContainerIdentity, report.InternetOnlyPseudoNode},
|
||||
},
|
||||
renderer: render.Reduce([]render.Renderer{
|
||||
render.Map{Selector: report.SelectEndpoint, Mapper: report.MapEndpoint2Container, Pseudo: report.InternetOnlyPseudoNode},
|
||||
render.Map{Selector: report.SelectContainer, Mapper: report.MapContainerIdentity, Pseudo: report.InternetOnlyPseudoNode},
|
||||
}),
|
||||
},
|
||||
"containers-by-image": {
|
||||
human: "by image",
|
||||
parent: "containers",
|
||||
maps: []topologyMapper{
|
||||
{report.SelectEndpoint, report.ProcessContainerImage, report.InternetOnlyPseudoNode},
|
||||
},
|
||||
human: "by image",
|
||||
parent: "containers",
|
||||
renderer: render.Map{Selector: report.SelectEndpoint, Mapper: report.ProcessContainerImage, Pseudo: report.InternetOnlyPseudoNode},
|
||||
},
|
||||
"hosts": {
|
||||
human: "Hosts",
|
||||
parent: "",
|
||||
maps: []topologyMapper{
|
||||
{report.SelectAddress, report.NetworkHostname, report.GenericPseudoNode},
|
||||
},
|
||||
human: "Hosts",
|
||||
parent: "",
|
||||
renderer: render.Map{Selector: report.SelectAddress, Mapper: report.NetworkHostname, Pseudo: report.GenericPseudoNode},
|
||||
},
|
||||
}
|
||||
|
||||
type topologyView struct {
|
||||
human string
|
||||
parent string
|
||||
maps []topologyMapper
|
||||
}
|
||||
|
||||
type topologyMapper struct {
|
||||
selector report.TopologySelector
|
||||
mapper report.MapFunc
|
||||
pseudo report.PseudoFunc
|
||||
human string
|
||||
parent string
|
||||
renderer render.Renderer
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ dependencies:
|
||||
mv scope_ui_build.tar $(dirname "$SCOPE_UI_BUILD");
|
||||
fi
|
||||
post:
|
||||
- go version
|
||||
- go clean -i net
|
||||
- go install -tags netgo std
|
||||
- make deps
|
||||
|
||||
51
render/render.go
Normal file
51
render/render.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// Renderer is something that can render a report to a set of RenderableNodes
|
||||
type Renderer interface {
|
||||
Render(report.Report) report.RenderableNodes
|
||||
AggregateMetadata(rpt report.Report, localID, remoteID string) report.AggregateMetadata
|
||||
}
|
||||
|
||||
// Reduce renderer is a Renderer which merges together the output of several
|
||||
// other renderers
|
||||
type Reduce []Renderer
|
||||
|
||||
// Render produces a set of RenderableNodes given a Report
|
||||
func (r Reduce) Render(rpt report.Report) report.RenderableNodes {
|
||||
result := report.RenderableNodes{}
|
||||
for _, renderer := range r {
|
||||
result.Merge(renderer.Render(rpt))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AggregateMetadata produces an AggregateMetadata for a given edge
|
||||
func (r Reduce) AggregateMetadata(rpt report.Report, localID, remoteID string) report.AggregateMetadata {
|
||||
metadata := report.AggregateMetadata{}
|
||||
for _, renderer := range r {
|
||||
metadata.Merge(renderer.AggregateMetadata(rpt, localID, remoteID))
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
// Map is a Renderer which produces a set of RendererNodes by using a
|
||||
// Mapper functions and topology selector.
|
||||
type Map struct {
|
||||
Selector report.TopologySelector
|
||||
Mapper report.MapFunc
|
||||
Pseudo report.PseudoFunc
|
||||
}
|
||||
|
||||
// Render produces a set of RenderableNodes given a Report
|
||||
func (m Map) Render(rpt report.Report) report.RenderableNodes {
|
||||
return m.Selector(rpt).RenderBy(m.Mapper, m.Pseudo)
|
||||
}
|
||||
|
||||
// AggregateMetadata produces an AggregateMetadata for a given edge
|
||||
func (m Map) AggregateMetadata(rpt report.Report, localID, remoteID string) report.AggregateMetadata {
|
||||
return m.Selector(rpt).EdgeMetadata(m.Mapper, localID, remoteID).Transform()
|
||||
}
|
||||
49
render/render_test.go
Normal file
49
render/render_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package render_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
type mockRenderer struct {
|
||||
report.RenderableNodes
|
||||
aggregateMetadata report.AggregateMetadata
|
||||
}
|
||||
|
||||
func (m mockRenderer) Render(rpt report.Report) report.RenderableNodes {
|
||||
return m.RenderableNodes
|
||||
}
|
||||
func (m mockRenderer) AggregateMetadata(rpt report.Report, localID, remoteID string) report.AggregateMetadata {
|
||||
return m.aggregateMetadata
|
||||
}
|
||||
|
||||
func TestReduceRender(t *testing.T) {
|
||||
renderer := render.Reduce([]render.Renderer{
|
||||
mockRenderer{RenderableNodes: report.RenderableNodes{"foo": {ID: "foo"}}},
|
||||
mockRenderer{RenderableNodes: report.RenderableNodes{"bar": {ID: "bar"}}},
|
||||
})
|
||||
|
||||
want := report.RenderableNodes{"foo": {ID: "foo"}, "bar": {ID: "bar"}}
|
||||
have := renderer.Render(report.MakeReport())
|
||||
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("want %+v, have %+v", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReduceEdge(t *testing.T) {
|
||||
renderer := render.Reduce([]render.Renderer{
|
||||
mockRenderer{aggregateMetadata: report.AggregateMetadata{"foo": 1}},
|
||||
mockRenderer{aggregateMetadata: report.AggregateMetadata{"bar": 2}},
|
||||
})
|
||||
|
||||
want := report.AggregateMetadata{"foo": 1, "bar": 2}
|
||||
have := renderer.AggregateMetadata(report.MakeReport(), "", "")
|
||||
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("want %+v, have %+v", want, have)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user