Skip to content

Commit

Permalink
backend changes for new option rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
paulbellamy authored and davkal committed Mar 29, 2016
1 parent 619c63a commit 430130c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 74 deletions.
110 changes: 74 additions & 36 deletions app/api_topologies.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,60 @@ var (
)

func init() {
containerFilters := map[string][]APITopologyOption{
"system": {
{"show", "System containers shown", false, render.FilterNoop},
{"hide", "System containers hidden", true, render.FilterSystem},
serviceFilters := []APITopologyOptionGroup{
{
ID: "system",
Default: "application",
Options: []APITopologyOption{
{"system", "System services", render.FilterApplication},
{"application", "Application services", render.FilterSystem},
{"both", "Both", render.FilterNoop},
},
},
"stopped": {
{"show", "Stopped containers shown", false, render.FilterNoop},
{"hide", "Stopped containers hidden", true, render.FilterStopped},
}

podFilters := []APITopologyOptionGroup{
{
ID: "system",
Default: "application",
Options: []APITopologyOption{
{"system", "System pods", render.FilterApplication},
{"application", "Application pods", render.FilterSystem},
{"both", "Both", render.FilterNoop},
},
},
}

containerFilters := []APITopologyOptionGroup{
{
ID: "system",
Default: "application",
Options: []APITopologyOption{
{"system", "System containers", render.FilterApplication},
{"application", "Application containers", render.FilterSystem},
{"both", "Both", render.FilterNoop},
},
},
{
ID: "stopped",
Default: "running",
Options: []APITopologyOption{
{"stopped", "Stopped containers", render.FilterRunning},
{"running", "Running containers", render.FilterStopped},
{"both", "Both", render.FilterNoop},
},
},
}

unconnectedFilter := []APITopologyOptionGroup{
{
ID: "unconnected",
Default: "hide",
Options: []APITopologyOption{
// Show the user why there are filtered nodes in this view.
// Don't give them the option to show those nodes.
{"hide", "Unconnected nodes hidden", render.FilterNoop},
},
},
}

Expand All @@ -40,21 +86,14 @@ func init() {
renderer: render.FilterUnconnected(render.ProcessWithContainerNameRenderer),
Name: "Processes",
Rank: 1,
Options: map[string][]APITopologyOption{"unconnected": {
// Show the user why there are filtered nodes in this view.
// Don't give them the option to show those nodes.
{"hide", "Unconnected nodes hidden", true, render.FilterNoop},
}},
Options: unconnectedFilter,
},
APITopologyDesc{
id: "processes-by-name",
parent: "processes",
renderer: render.FilterUnconnected(render.ProcessNameRenderer),
Name: "by name",
Options: map[string][]APITopologyOption{"unconnected": {
// Ditto above.
{"hide", "Unconnected nodes hidden", true, render.FilterNoop},
}},
Options: unconnectedFilter,
},
APITopologyDesc{
id: "containers",
Expand Down Expand Up @@ -82,29 +121,22 @@ func init() {
renderer: render.HostRenderer,
Name: "Hosts",
Rank: 4,
Options: map[string][]APITopologyOption{},
},
APITopologyDesc{
id: "pods",
renderer: render.PodRenderer,
Name: "Pods",
Rank: 3,
HideIfEmpty: true,
Options: map[string][]APITopologyOption{"system": {
{"show", "System pods shown", false, render.FilterNoop},
{"hide", "System pods hidden", true, render.FilterSystem},
}},
Options: podFilters,
},
APITopologyDesc{
id: "pods-by-service",
parent: "pods",
renderer: render.PodServiceRenderer,
Name: "by service",
HideIfEmpty: true,
Options: map[string][]APITopologyOption{"system": {
{"show", "System services shown", false, render.FilterNoop},
{"hide", "System services hidden", true, render.FilterSystem},
}},
Options: serviceFilters,
},
)
}
Expand All @@ -121,10 +153,10 @@ type APITopologyDesc struct {
parent string
renderer render.Renderer

Name string `json:"name"`
Rank int `json:"rank"`
HideIfEmpty bool `json:"hide_if_empty"`
Options map[string][]APITopologyOption `json:"options"`
Name string `json:"name"`
Rank int `json:"rank"`
HideIfEmpty bool `json:"hide_if_empty"`
Options []APITopologyOptionGroup `json:"options"`

URL string `json:"url"`
SubTopologies []APITopologyDesc `json:"sub_topologies,omitempty"`
Expand All @@ -137,11 +169,17 @@ func (a byName) Len() int { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }

// APITopologyOptionGroup describes a group of APITopologyOptions
type APITopologyOptionGroup struct {
ID string `json:"id"`
Default string `json:"defaultValue,omitempty"`
Options []APITopologyOption `json:"options,omitempty"`
}

// APITopologyOption describes a &param=value to a given topology.
type APITopologyOption struct {
Value string `json:"value"`
Display string `json:"display"`
Default bool `json:"default,omitempty"`
Value string `json:"value"`
Label string `json:"label"`

decorator func(render.Renderer) render.Renderer
}
Expand Down Expand Up @@ -244,10 +282,10 @@ func decorateWithStats(rpt report.Report, renderer render.Renderer) topologyStat

func renderedForRequest(r *http.Request, topology APITopologyDesc) render.Renderer {
renderer := topology.renderer
for param, opts := range topology.Options {
value := r.FormValue(param)
for _, opt := range opts {
if (value == "" && opt.Default) || (opt.Value != "" && opt.Value == value) {
for _, group := range topology.Options {
value := r.FormValue(group.ID)
for _, opt := range group.Options {
if (value == "" && group.Default == opt.Value) || (opt.Value != "" && opt.Value == value) {
renderer = opt.decorator(renderer)
}
}
Expand Down
56 changes: 18 additions & 38 deletions render/filters.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package render

import (
"strings"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/kubernetes"
"github.com/weaveworks/scope/report"
)

Expand Down Expand Up @@ -125,6 +121,12 @@ func (f Filter) Stats(rpt report.Report) Stats {
// to indicate a node has an edge pointing to it or from it
const IsConnected = "is_connected"

// Complement takes a FilterFunc f and returns a FilterFunc that has the same
// effects, if any, and returns the opposite truth value.
func Complement(f func(RenderableNode) bool) func(RenderableNode) bool {
return func(node RenderableNode) bool { return !f(node) }
}

// FilterPseudo produces a renderer that removes pseudo nodes from the given
// renderer
func FilterPseudo(r Renderer) Renderer {
Expand Down Expand Up @@ -155,44 +157,22 @@ func FilterNoop(in Renderer) Renderer {

// FilterStopped filters out stopped containers.
func FilterStopped(r Renderer) Renderer {
return MakeFilter(
func(node RenderableNode) bool {
containerState, ok := node.Latest.Lookup(docker.ContainerState)
return !ok || containerState != docker.StateStopped
},
r,
)
return MakeFilter(RenderableNode.IsStopped, r)
}

// FilterRunning filters out running containers.
func FilterRunning(r Renderer) Renderer {
return MakeFilter(Complement(RenderableNode.IsStopped), r)
}

// FilterSystem is a Renderer which filters out system nodes.
func FilterSystem(r Renderer) Renderer {
return MakeFilter(
func(node RenderableNode) bool {
containerName, _ := node.Latest.Lookup(docker.ContainerName)
if _, ok := systemContainerNames[containerName]; ok {
return false
}
imageName, _ := node.Latest.Lookup(docker.ImageName)
imagePrefix := strings.SplitN(imageName, ":", 2)[0] // :(
if _, ok := systemImagePrefixes[imagePrefix]; ok {
return false
}
roleLabel, _ := node.Latest.Lookup(docker.LabelPrefix + "works.weave.role")
if roleLabel == "system" {
return false
}
namespace, _ := node.Latest.Lookup(kubernetes.Namespace)
if namespace == "kube-system" {
return false
}
podName, _ := node.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.name")
if strings.HasPrefix(podName, "kube-system/") {
return false
}
return true
},
r,
)
return MakeFilter(RenderableNode.IsSystem, r)
}

// FilterApplication is a Renderer which filters out system nodes.
func FilterApplication(r Renderer) Renderer {
return MakeFilter(Complement(RenderableNode.IsSystem), r)
}

var systemContainerNames = map[string]struct{}{
Expand Down
36 changes: 36 additions & 0 deletions render/renderable_node.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package render

import (
"strings"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/kubernetes"
"github.com/weaveworks/scope/report"
)

Expand Down Expand Up @@ -153,6 +157,38 @@ func (rn RenderableNode) Copy() RenderableNode {
}
}

// IsStopped checks if the RenderableNode is a stopped docker container.
func (rn RenderableNode) IsStopped() bool {
containerState, ok := rn.Latest.Lookup(docker.ContainerState)
return !ok || containerState != docker.StateStopped
}

// IsSystem checks if the RenderableNode is a system container/pod/etc.
func (rn RenderableNode) IsSystem() bool {
containerName, _ := rn.Latest.Lookup(docker.ContainerName)
if _, ok := systemContainerNames[containerName]; ok {
return false
}
imageName, _ := rn.Latest.Lookup(docker.ImageName)
imagePrefix := strings.SplitN(imageName, ":", 2)[0] // :(
if _, ok := systemImagePrefixes[imagePrefix]; ok {
return false
}
roleLabel, _ := rn.Latest.Lookup(docker.LabelPrefix + "works.weave.role")
if roleLabel == "system" {
return false
}
namespace, _ := rn.Latest.Lookup(kubernetes.Namespace)
if namespace == "kube-system" {
return false
}
podName, _ := rn.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.name")
if strings.HasPrefix(podName, "kube-system/") {
return false
}
return true
}

// Prune returns a copy of the RenderableNode with all information not
// strictly necessary for rendering nodes and edges stripped away.
// Specifically, that means cutting out parts of the Node.
Expand Down

0 comments on commit 430130c

Please sign in to comment.