Skip to content

Commit

Permalink
Merge pull request #2951 from weaveworks/one-pass-unconnected
Browse files Browse the repository at this point in the history
filter out unconnected pseudo nodes just once, at the end
  • Loading branch information
rade authored Nov 28, 2017
2 parents 91fd411 + 9563036 commit e73ba58
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 111 deletions.
56 changes: 35 additions & 21 deletions app/api_topologies.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ func MakeRegistry() *Registry {
registry.Add(
APITopologyDesc{
id: processesID,
renderer: render.FilterUnconnected(render.ProcessWithContainerNameRenderer),
renderer: render.ProcessWithContainerNameRenderer,
filter: render.FilterUnconnected,
Name: "Processes",
Rank: 1,
Options: unconnectedFilter,
Expand All @@ -209,35 +210,40 @@ func MakeRegistry() *Registry {
APITopologyDesc{
id: processesByNameID,
parent: processesID,
renderer: render.FilterUnconnected(render.ProcessNameRenderer),
renderer: render.ProcessNameRenderer,
filter: render.FilterUnconnected,
Name: "by name",
Options: unconnectedFilter,
HideIfEmpty: true,
},
APITopologyDesc{
id: containersID,
renderer: render.FilterUnconnectedPseudo(render.ContainerWithImageNameRenderer),
renderer: render.ContainerWithImageNameRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "Containers",
Rank: 2,
Options: containerFilters,
},
APITopologyDesc{
id: containersByHostnameID,
parent: containersID,
renderer: render.FilterUnconnectedPseudo(render.ContainerHostnameRenderer),
renderer: render.ContainerHostnameRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "by DNS name",
Options: containerFilters,
},
APITopologyDesc{
id: containersByImageID,
parent: containersID,
renderer: render.FilterUnconnectedPseudo(render.ContainerImageRenderer),
renderer: render.ContainerImageRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "by image",
Options: containerFilters,
},
APITopologyDesc{
id: podsID,
renderer: render.FilterUnconnectedPseudo(render.PodRenderer),
renderer: render.PodRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "Pods",
Rank: 3,
Options: []APITopologyOptionGroup{unmanagedFilter},
Expand All @@ -246,22 +252,25 @@ func MakeRegistry() *Registry {
APITopologyDesc{
id: kubeControllersID,
parent: podsID,
renderer: render.FilterUnconnectedPseudo(render.KubeControllerRenderer),
renderer: render.KubeControllerRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "controllers",
Options: []APITopologyOptionGroup{unmanagedFilter},
HideIfEmpty: true,
},
APITopologyDesc{
id: servicesID,
parent: podsID,
renderer: render.FilterUnconnectedPseudo(render.PodServiceRenderer),
renderer: render.PodServiceRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "services",
Options: []APITopologyOptionGroup{unmanagedFilter},
HideIfEmpty: true,
},
APITopologyDesc{
id: ecsTasksID,
renderer: render.FilterUnconnectedPseudo(render.ECSTaskRenderer),
renderer: render.ECSTaskRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "Tasks",
Rank: 3,
Options: []APITopologyOptionGroup{unmanagedFilter},
Expand All @@ -270,29 +279,33 @@ func MakeRegistry() *Registry {
APITopologyDesc{
id: ecsServicesID,
parent: ecsTasksID,
renderer: render.FilterUnconnectedPseudo(render.ECSServiceRenderer),
renderer: render.ECSServiceRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "services",
Options: []APITopologyOptionGroup{unmanagedFilter},
HideIfEmpty: true,
},
APITopologyDesc{
id: swarmServicesID,
renderer: render.FilterUnconnectedPseudo(render.SwarmServiceRenderer),
renderer: render.SwarmServiceRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "services",
Rank: 3,
Options: []APITopologyOptionGroup{unmanagedFilter},
HideIfEmpty: true,
},
APITopologyDesc{
id: hostsID,
renderer: render.FilterUnconnectedPseudo(render.HostRenderer),
renderer: render.HostRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "Hosts",
Rank: 4,
},
APITopologyDesc{
id: weaveID,
parent: hostsID,
renderer: render.FilterUnconnectedPseudo(render.WeaveRenderer),
renderer: render.WeaveRenderer,
filter: render.FilterUnconnectedPseudo,
Name: "Weave Net",
},
)
Expand All @@ -305,6 +318,7 @@ type APITopologyDesc struct {
id string
parent string
renderer render.Renderer
filter render.Transformer

Name string `json:"name"`
Rank int `json:"rank"`
Expand Down Expand Up @@ -496,13 +510,13 @@ func (r *Registry) renderTopologies(rpt report.Report, req *http.Request) []APIT
return updateFilters(rpt, topologies)
}

func computeStats(rpt report.Report, renderer render.Renderer, filter render.FilterFunc) topologyStats {
func computeStats(rpt report.Report, renderer render.Renderer, transformer render.Transformer) topologyStats {
var (
nodes int
realNodes int
edges int
)
r := render.Render(rpt, renderer, filter)
r := render.Render(rpt, renderer, transformer)
for _, n := range r.Nodes {
nodes++
if n.Topology != render.Pseudo {
Expand All @@ -519,16 +533,16 @@ func computeStats(rpt report.Report, renderer render.Renderer, filter render.Fil
}

// RendererForTopology ..
func (r *Registry) RendererForTopology(topologyID string, values url.Values, rpt report.Report) (render.Renderer, render.FilterFunc, error) {
func (r *Registry) RendererForTopology(topologyID string, values url.Values, rpt report.Report) (render.Renderer, render.Transformer, error) {
topology, ok := r.get(topologyID)
if !ok {
return nil, nil, fmt.Errorf("topology not found: %s", topologyID)
}
topology = updateFilters(rpt, []APITopologyDesc{topology})[0]

if len(values) == 0 {
// Do not apply filtering if no options where provided
return topology.renderer, nil, nil
// if no options where provided, only apply base filter
return topology.renderer, topology.filter, nil
}

var filters []render.FilterFunc
Expand All @@ -539,9 +553,9 @@ func (r *Registry) RendererForTopology(topologyID string, values url.Values, rpt
}
}
if len(filters) > 0 {
return topology.renderer, render.ComposeFilterFuncs(filters...), nil
return topology.renderer, render.Transformers([]render.Transformer{render.ComposeFilterFuncs(filters...), topology.filter}), nil
}
return topology.renderer, nil, nil
return topology.renderer, topology.filter, nil
}

type reporterHandler func(context.Context, Reporter, http.ResponseWriter, *http.Request)
Expand All @@ -552,7 +566,7 @@ func captureReporter(rep Reporter, f reporterHandler) CtxHandlerFunc {
}
}

type rendererHandler func(context.Context, render.Renderer, render.FilterFunc, report.RenderContext, http.ResponseWriter, *http.Request)
type rendererHandler func(context.Context, render.Renderer, render.Transformer, report.RenderContext, http.ResponseWriter, *http.Request)

func (r *Registry) captureRenderer(rep Reporter, f rendererHandler) CtxHandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
Expand Down
8 changes: 4 additions & 4 deletions app/api_topologies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,14 @@ func getTestContainerLabelFilterTopologySummary(t *testing.T, exclude bool) (det

var (
topologyRegistry = app.MakeRegistry()
filter render.FilterFunc
filterFunc render.FilterFunc
)
if exclude == true {
filter = render.DoesNotHaveLabel(fixture.TestLabelKey2, fixture.ApplicationLabelValue2)
filterFunc = render.DoesNotHaveLabel(fixture.TestLabelKey2, fixture.ApplicationLabelValue2)
} else {
filter = render.HasLabel(fixture.TestLabelKey1, fixture.ApplicationLabelValue1)
filterFunc = render.HasLabel(fixture.TestLabelKey1, fixture.ApplicationLabelValue1)
}
option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", filter, false)
option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", filterFunc, false)
topologyRegistry.AddContainerFilters(option)

urlvalues := url.Values{}
Expand Down
20 changes: 9 additions & 11 deletions app/api_topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ type APINode struct {
}

// Full topology.
func handleTopology(ctx context.Context, renderer render.Renderer, filter render.FilterFunc, rc report.RenderContext, w http.ResponseWriter, r *http.Request) {
func handleTopology(ctx context.Context, renderer render.Renderer, transformer render.Transformer, rc report.RenderContext, w http.ResponseWriter, r *http.Request) {
respondWith(w, http.StatusOK, APITopology{
Nodes: detailed.Summaries(rc, render.Render(rc.Report, renderer, filter).Nodes),
Nodes: detailed.Summaries(rc, render.Render(rc.Report, renderer, transformer).Nodes),
})
}

// Individual nodes.
func handleNode(ctx context.Context, renderer render.Renderer, filter render.FilterFunc, rc report.RenderContext, w http.ResponseWriter, r *http.Request) {
func handleNode(ctx context.Context, renderer render.Renderer, transformer render.Transformer, rc report.RenderContext, w http.ResponseWriter, r *http.Request) {
var (
vars = mux.Vars(r)
topologyID = vars["topology"]
Expand All @@ -53,14 +53,12 @@ func handleNode(ctx context.Context, renderer render.Renderer, filter render.Fil
http.NotFound(w, r)
return
}
if filter != nil {
nodes = filter.Apply(nodes)
if filteredNode, ok := nodes.Nodes[nodeID]; ok {
node = filteredNode
} else { // we've lost the node during filtering; put it back
nodes.Nodes[nodeID] = node
nodes.Filtered--
}
nodes = transformer.Transform(nodes)
if filteredNode, ok := nodes.Nodes[nodeID]; ok {
node = filteredNode
} else { // we've lost the node during filtering; put it back
nodes.Nodes[nodeID] = node
nodes.Filtered--
}
respondWith(w, http.StatusOK, APINode{Node: detailed.MakeNode(topologyID, rc, nodes.Nodes, node)})
}
Expand Down
2 changes: 1 addition & 1 deletion render/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var ContainerRenderer = Memoise(MakeFilter(
MakeReduce(
MakeMap(
MapProcess2Container,
ColorConnectedProcessRenderer,
ProcessRenderer,
),
ConnectionJoin(MapContainer2IP, SelectContainer),
),
Expand Down
14 changes: 10 additions & 4 deletions render/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ import (
)

var (
filterApplication = render.AnyFilterFunc(render.IsPseudoTopology, render.IsApplication)
filterSystem = render.AnyFilterFunc(render.IsPseudoTopology, render.IsSystem)
filterApplication = render.Transformers([]render.Transformer{
render.AnyFilterFunc(render.IsPseudoTopology, render.IsApplication),
render.FilterUnconnectedPseudo,
})
filterSystem = render.Transformers([]render.Transformer{
render.AnyFilterFunc(render.IsPseudoTopology, render.IsSystem),
render.FilterUnconnectedPseudo,
})
)

func TestMapProcess2Container(t *testing.T) {
Expand Down Expand Up @@ -74,7 +80,7 @@ func TestContainerFilterRenderer(t *testing.T) {
}

func TestContainerHostnameRenderer(t *testing.T) {
have := utils.Prune(render.Render(fixture.Report, render.ContainerHostnameRenderer, nil).Nodes)
have := utils.Prune(render.Render(fixture.Report, render.ContainerHostnameRenderer, render.Transformers(nil)).Nodes)
want := utils.Prune(expected.RenderedContainerHostnames)
if !reflect.DeepEqual(want, have) {
t.Error(test.Diff(want, have))
Expand All @@ -93,7 +99,7 @@ func TestContainerHostnameFilterRenderer(t *testing.T) {
}

func TestContainerImageRenderer(t *testing.T) {
have := utils.Prune(render.Render(fixture.Report, render.ContainerImageRenderer, nil).Nodes)
have := utils.Prune(render.Render(fixture.Report, render.ContainerImageRenderer, render.Transformers(nil)).Nodes)
want := utils.Prune(expected.RenderedContainerImages)
if !reflect.DeepEqual(want, have) {
t.Error(test.Diff(want, have))
Expand Down
Loading

0 comments on commit e73ba58

Please sign in to comment.