Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filter out unconnected pseudo nodes just once, at the end #2951

Merged
merged 7 commits into from
Nov 28, 2017
Merged
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

This comment was marked as abuse.

This comment was marked as abuse.

}
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

This comment was marked as abuse.

This comment was marked as abuse.

)
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)

This comment was marked as abuse.

This comment was marked as abuse.

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