Skip to content

Commit

Permalink
Merge pull request #2452 from weaveworks/mike/docker-swarm/service-ns…
Browse files Browse the repository at this point in the history
…-selector

Add docker swarm Stack selector ala k8s namespace selector
  • Loading branch information
Alfonso Acosta authored Apr 25, 2017
2 parents 8ad2d0e + 5199952 commit 876bb97
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 15 deletions.
47 changes: 40 additions & 7 deletions app/api_topologies.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/gorilla/mux"
"golang.org/x/net/context"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/kubernetes"
"github.com/weaveworks/scope/render"
"github.com/weaveworks/scope/report"
Expand Down Expand Up @@ -48,12 +49,12 @@ var (
}
)

// kubernetesFilters generates the current kubernetes filters based on the
// available k8s topologies.
func kubernetesFilters(namespaces ...string) APITopologyOptionGroup {
options := APITopologyOptionGroup{ID: "namespace", Default: "", SelectType: "union", NoneLabel: "All Namespaces"}
// namespaceFilters generates a namespace selector option group based on the given namespaces
func namespaceFilters(namespaces []string, defaultNamespace, noneLabel string) APITopologyOptionGroup {
options := APITopologyOptionGroup{ID: "namespace", Default: "", SelectType: "union", NoneLabel: noneLabel}
for _, namespace := range namespaces {
if namespace == "default" {
if defaultNamespace != "" && namespace == defaultNamespace {
// We only set the default namespace as options.Default if it is present, otherwise default to All
options.Default = namespace
}
options.Options = append(options.Options, APITopologyOption{
Expand All @@ -64,8 +65,40 @@ func kubernetesFilters(namespaces ...string) APITopologyOptionGroup {
}

// updateFilters updates the available filters based on the current report.
// Currently only kubernetes changes.
func updateFilters(rpt report.Report, topologies []APITopologyDesc) []APITopologyDesc {
topologies = updateKubeFilters(rpt, topologies)
topologies = updateSwarmFilters(rpt, topologies)
return topologies
}

func updateSwarmFilters(rpt report.Report, topologies []APITopologyDesc) []APITopologyDesc {
namespaces := map[string]struct{}{}
for _, n := range rpt.SwarmService.Nodes {
if namespace, ok := n.Latest.Lookup(docker.StackNamespace); ok {
namespaces[namespace] = struct{}{}
}
}
if len(namespaces) == 0 {
// We only want to apply filters when we have swarm-related nodes,
// so if we don't then return early
return topologies
}
ns := []string{}
for namespace := range namespaces {
ns = append(ns, namespace)
}
topologies = append([]APITopologyDesc{}, topologies...) // Make a copy so we can make changes safely
for i, t := range topologies {
if t.id == containersID || t.id == containersByImageID || t.id == containersByHostnameID || t.id == swarmServicesID {
topologies[i] = mergeTopologyFilters(t, []APITopologyOptionGroup{
namespaceFilters(ns, docker.DefaultNamespace, "All Stacks"),
})
}
}
return topologies
}

func updateKubeFilters(rpt report.Report, topologies []APITopologyDesc) []APITopologyDesc {
namespaces := map[string]struct{}{}
for _, t := range []report.Topology{rpt.Pod, rpt.Service, rpt.Deployment, rpt.ReplicaSet} {
for _, n := range t.Nodes {
Expand All @@ -91,7 +124,7 @@ func updateFilters(rpt report.Report, topologies []APITopologyDesc) []APITopolog
for i, t := range topologies {
if t.id == containersID || t.id == containersByImageID || t.id == containersByHostnameID || t.id == podsID || t.id == servicesID || t.id == deploymentsID || t.id == replicaSetsID {
topologies[i] = mergeTopologyFilters(t, []APITopologyOptionGroup{
kubernetesFilters(ns...),
namespaceFilters(ns, "default", "All Namespaces"),
})
}
}
Expand Down
1 change: 1 addition & 0 deletions probe/docker/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
ImageTableID = "image_table"
ServiceName = "service_name"
StackNamespace = "stack_namespace"
DefaultNamespace = "No Stack"
)

// Exposed for testing
Expand Down
12 changes: 6 additions & 6 deletions probe/docker/tagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ func (t *Tagger) Tag(r report.Report) (report.Report, error) {
}
stackNamespace, ok := container.Latest.Lookup(LabelPrefix + "com.docker.stack.namespace")
if !ok {
continue
}

prefix := stackNamespace + "_"
if strings.HasPrefix(serviceName, prefix) {
serviceName = serviceName[len(prefix):]
stackNamespace = DefaultNamespace
} else {
prefix := stackNamespace + "_"
if strings.HasPrefix(serviceName, prefix) {
serviceName = serviceName[len(prefix):]
}
}

nodeID := report.MakeSwarmServiceNodeID(serviceID)
Expand Down
9 changes: 7 additions & 2 deletions render/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
)

const (
k8sNamespaceLabel = "io.kubernetes.pod.namespace"
k8sNamespaceLabel = "io.kubernetes.pod.namespace"
swarmNamespaceLabel = "com.docker.stack.namespace"
)

// PreciousNodeRenderer ensures a node is never filtered out by decorators
Expand Down Expand Up @@ -330,14 +331,18 @@ func IsPseudoTopology(n report.Node) bool {
// IsNamespace checks if the node is a pod/service in the specified namespace
func IsNamespace(namespace string) FilterFunc {
return func(n report.Node) bool {
tryKeys := []string{kubernetes.Namespace, docker.LabelPrefix + k8sNamespaceLabel}
tryKeys := []string{kubernetes.Namespace, docker.LabelPrefix + k8sNamespaceLabel, docker.StackNamespace, docker.LabelPrefix + swarmNamespaceLabel}
gotNamespace := ""
for _, key := range tryKeys {
if value, ok := n.Latest.Lookup(key); ok {
gotNamespace = value
break
}
}
// Special case for docker
if namespace == docker.DefaultNamespace && gotNamespace == "" {
return true
}
return namespace == gotNamespace
}
}
Expand Down

0 comments on commit 876bb97

Please sign in to comment.