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

Deployment and Replica Set views #1436

Merged
merged 4 commits into from
May 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions app/api_topologies.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ func init() {
Options: containerFilters,
},
APITopologyDesc{
id: "containers-by-image",
id: "containers-by-hostname",
parent: "containers",
renderer: render.ContainerImageRenderer,
Name: "by image",
renderer: render.ContainerHostnameRenderer,
Name: "by DNS name",
Options: containerFilters,
},
APITopologyDesc{
id: "containers-by-hostname",
id: "containers-by-image",
parent: "containers",
renderer: render.ContainerHostnameRenderer,
Name: "by DNS name",
renderer: render.ContainerImageRenderer,
Name: "by image",
Options: containerFilters,
},
APITopologyDesc{
Expand All @@ -103,10 +103,24 @@ func init() {
HideIfEmpty: true,
},
APITopologyDesc{
id: "pods-by-service",
id: "replica-sets",
parent: "pods",
renderer: render.ReplicaSetRenderer,
Name: "replica sets",
HideIfEmpty: true,
},
APITopologyDesc{
id: "deployments",
parent: "pods",
renderer: render.DeploymentRenderer,
Name: "deployments",
HideIfEmpty: true,
},
APITopologyDesc{
id: "services",
parent: "pods",
renderer: render.PodServiceRenderer,
Name: "by service",
Name: "services",
HideIfEmpty: true,
},
APITopologyDesc{
Expand Down Expand Up @@ -136,9 +150,9 @@ func kubernetesFilters(namespaces ...string) APITopologyOptionGroup {
// Currently only kubernetes changes.
func updateFilters(rpt report.Report, topologies []APITopologyDesc) []APITopologyDesc {
namespaces := map[string]struct{}{}
for _, t := range []report.Topology{rpt.Pod, rpt.Service} {
for _, t := range []report.Topology{rpt.Pod, rpt.Service, rpt.Deployment, rpt.ReplicaSet} {
for _, n := range t.Nodes {
if state, ok := n.Latest.Lookup(kubernetes.PodState); ok && state == kubernetes.StateDeleted {
if state, ok := n.Latest.Lookup(kubernetes.State); ok && state == kubernetes.StateDeleted {
continue
}
if namespace, ok := n.Latest.Lookup(kubernetes.Namespace); ok {
Expand All @@ -152,7 +166,7 @@ func updateFilters(rpt report.Report, topologies []APITopologyDesc) []APITopolog
}
sort.Strings(ns)
for i, t := range topologies {
if t.id == "pods" || t.id == "pods-by-service" {
if t.id == "pods" || t.id == "services" || t.id == "deployments" || t.id == "replica-sets" {
topologies[i] = updateTopologyFilters(t, []APITopologyOptionGroup{kubernetesFilters(ns...)})
}
}
Expand Down Expand Up @@ -227,7 +241,6 @@ func (r *registry) add(ts ...APITopologyDesc) {
if t.parent != "" {
parent := r.items[t.parent]
parent.SubTopologies = append(parent.SubTopologies, t)
sort.Sort(byName(parent.SubTopologies))
r.items[t.parent] = parent
}

Expand Down
4 changes: 4 additions & 0 deletions probe/appclient/app_client_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ func TestAppClientPublish(t *testing.T) {
rpt.ContainerImage = report.MakeTopology()
rpt.Pod = report.MakeTopology()
rpt.Service = report.MakeTopology()
rpt.Deployment = report.MakeTopology()
rpt.ReplicaSet = report.MakeTopology()
rpt.Host = report.MakeTopology()
rpt.Overlay = report.MakeTopology()
rpt.Endpoint.Controls = nil
Expand All @@ -82,6 +84,8 @@ func TestAppClientPublish(t *testing.T) {
rpt.ContainerImage.Controls = nil
rpt.Pod.Controls = nil
rpt.Service.Controls = nil
rpt.Deployment.Controls = nil
rpt.ReplicaSet.Controls = nil
rpt.Host.Controls = nil
rpt.Overlay.Controls = nil

Expand Down
107 changes: 74 additions & 33 deletions probe/kubernetes/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

log "github.com/Sirupsen/logrus"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/unversioned"
Expand All @@ -16,16 +17,13 @@ import (
"k8s.io/kubernetes/pkg/util/wait"
)

// These constants are keys used in node metadata
const (
Namespace = "kubernetes_namespace"
)

// Client keeps track of running kubernetes pods and services
type Client interface {
Stop()
WalkPods(f func(Pod) error) error
WalkServices(f func(Service) error) error
WalkDeployments(f func(Deployment) error) error
WalkReplicaSets(f func(ReplicaSet) error) error
WalkNodes(f func(*api.Node) error) error

WatchPods(f func(Event, Pod))
Expand All @@ -35,14 +33,15 @@ type Client interface {
}

type client struct {
quit chan struct{}
client *unversioned.Client
podReflector *cache.Reflector
serviceReflector *cache.Reflector
nodeReflector *cache.Reflector
podStore *cache.StoreToPodLister
serviceStore *cache.StoreToServiceLister
nodeStore *cache.StoreToNodeLister
quit chan struct{}
resyncPeriod time.Duration
client *unversioned.Client
podStore *cache.StoreToPodLister
serviceStore *cache.StoreToServiceLister
deploymentStore *cache.StoreToDeploymentLister
replicaSetStore *cache.StoreToReplicaSetLister
replicationControllerStore *cache.StoreToReplicationControllerLister
nodeStore *cache.StoreToNodeLister

podWatchesMutex sync.Mutex
podWatches []func(Event, Pod)
Expand Down Expand Up @@ -80,32 +79,33 @@ func NewClient(addr string, resyncPeriod time.Duration) (Client, error) {
return nil, err
}

result := &client{
quit: make(chan struct{}),
client: c,
ec, err := unversioned.NewExtensions(config)
if err != nil {
return nil, err
}

podListWatch := cache.NewListWatchFromClient(c, "pods", api.NamespaceAll, fields.Everything())
podStore := NewEventStore(result.triggerPodWatches, cache.MetaNamespaceKeyFunc)
result.podStore = &cache.StoreToPodLister{Store: podStore}
result.podReflector = cache.NewReflector(podListWatch, &api.Pod{}, podStore, resyncPeriod)

serviceListWatch := cache.NewListWatchFromClient(c, "services", api.NamespaceAll, fields.Everything())
serviceStore := cache.NewStore(cache.MetaNamespaceKeyFunc)
result.serviceStore = &cache.StoreToServiceLister{Store: serviceStore}
result.serviceReflector = cache.NewReflector(serviceListWatch, &api.Service{}, serviceStore, resyncPeriod)

nodeListWatch := cache.NewListWatchFromClient(c, "nodes", api.NamespaceAll, fields.Everything())
nodeStore := cache.NewStore(cache.MetaNamespaceKeyFunc)
result.nodeStore = &cache.StoreToNodeLister{Store: nodeStore}
result.nodeReflector = cache.NewReflector(nodeListWatch, &api.Node{}, nodeStore, resyncPeriod)
result := &client{
quit: make(chan struct{}),
resyncPeriod: resyncPeriod,
client: c,
}

runReflectorUntil(result.podReflector, resyncPeriod, result.quit)
runReflectorUntil(result.serviceReflector, resyncPeriod, result.quit)
runReflectorUntil(result.nodeReflector, resyncPeriod, result.quit)
result.podStore = &cache.StoreToPodLister{Store: result.setupStore(c, "pods", &api.Pod{})}
result.serviceStore = &cache.StoreToServiceLister{Store: result.setupStore(c, "services", &api.Service{})}
result.deploymentStore = &cache.StoreToDeploymentLister{Store: result.setupStore(ec, "deployments", &extensions.Deployment{})}
result.replicaSetStore = &cache.StoreToReplicaSetLister{Store: result.setupStore(ec, "replicasets", &extensions.ReplicaSet{})}
result.replicationControllerStore = &cache.StoreToReplicationControllerLister{Store: result.setupStore(c, "replicationcontrollers", &api.ReplicationController{})}
result.nodeStore = &cache.StoreToNodeLister{Store: result.setupStore(c, "nodes", &api.Node{})}
return result, nil
}

func (c *client) setupStore(kclient cache.Getter, resource string, itemType interface{}) cache.Store {
lw := cache.NewListWatchFromClient(kclient, resource, api.NamespaceAll, fields.Everything())
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
runReflectorUntil(cache.NewReflector(lw, itemType, store, c.resyncPeriod), c.resyncPeriod, c.quit)
return store
}

func (c *client) WatchPods(f func(Event, Pod)) {
c.podWatchesMutex.Lock()
defer c.podWatchesMutex.Unlock()
Expand Down Expand Up @@ -146,6 +146,47 @@ func (c *client) WalkServices(f func(Service) error) error {
return nil
}

func (c *client) WalkDeployments(f func(Deployment) error) error {
list, err := c.deploymentStore.List()
if err != nil {
return err
}
for i := range list {
if err := f(NewDeployment(&(list[i]))); err != nil {
return err
}
}
return nil
}

// WalkReplicaSets calls f for each replica set (and replication controller)
func (c *client) WalkReplicaSets(f func(ReplicaSet) error) error {
{
list, err := c.replicaSetStore.List()
if err != nil {
return err
}
for i := range list {
if err := f(NewReplicaSet(&(list[i]))); err != nil {
return err
}
}
}

{
list, err := c.replicationControllerStore.List()
if err != nil {
return err
}
for i := range list {
if err := f(NewReplicationController(&(list[i]))); err != nil {
return err
}
}
}
return nil
}

func (c *client) WalkNodes(f func(*api.Node) error) error {
list, err := c.nodeStore.List()
if err != nil {
Expand Down
59 changes: 59 additions & 0 deletions probe/kubernetes/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package kubernetes

import (
"fmt"

"github.com/weaveworks/scope/report"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels"
)

// These constants are keys used in node metadata
const (
UpdatedReplicas = "kubernetes_updated_replicas"
AvailableReplicas = "kubernetes_available_replicas"
UnavailableReplicas = "kubernetes_unavailable_replicas"
Strategy = "kubernetes_strategy"
)

// Deployment represents a Kubernetes deployment
type Deployment interface {
Meta
Selector() labels.Selector
GetNode(probeID string) report.Node
}

type deployment struct {
*extensions.Deployment
Meta
Node *api.Node
}

// NewDeployment creates a new Deployment
func NewDeployment(d *extensions.Deployment) Deployment {
return &deployment{Deployment: d, Meta: meta{d.ObjectMeta}}
}

func (d *deployment) Selector() labels.Selector {
selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector)
if err != nil {
// TODO(paulbellamy): Remove the panic!
panic(err)
}
return selector
}

func (d *deployment) GetNode(probeID string) report.Node {
return d.MetaNode(report.MakeDeploymentNodeID(d.UID())).WithLatests(map[string]string{
ObservedGeneration: fmt.Sprint(d.Status.ObservedGeneration),
DesiredReplicas: fmt.Sprint(d.Spec.Replicas),
Replicas: fmt.Sprint(d.Status.Replicas),
UpdatedReplicas: fmt.Sprint(d.Status.UpdatedReplicas),
AvailableReplicas: fmt.Sprint(d.Status.AvailableReplicas),
UnavailableReplicas: fmt.Sprint(d.Status.UnavailableReplicas),
Strategy: string(d.Spec.Strategy.Type),
report.ControlProbeID: probeID,
})
}
67 changes: 67 additions & 0 deletions probe/kubernetes/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package kubernetes

import (
"time"

"k8s.io/kubernetes/pkg/api"

"github.com/weaveworks/scope/report"
)

// These constants are keys used in node metadata
const (
ID = "kubernetes_id"
Name = "kubernetes_name"
Namespace = "kubernetes_namespace"
Created = "kubernetes_created"
LabelPrefix = "kubernetes_labels_"
)

// Meta represents a metadata information about a Kubernetes object
type Meta interface {

This comment was marked as abuse.

UID() string
ID() string
Name() string
Namespace() string
Created() string
Labels() map[string]string
MetaNode(id string) report.Node
}

type meta struct {
ObjectMeta api.ObjectMeta
}

func (m meta) UID() string {
return string(m.ObjectMeta.UID)
}

func (m meta) ID() string {
return m.ObjectMeta.Namespace + "/" + m.ObjectMeta.Name
}

func (m meta) Name() string {
return m.ObjectMeta.Name
}

func (m meta) Namespace() string {
return m.ObjectMeta.Namespace
}

func (m meta) Created() string {
return m.ObjectMeta.CreationTimestamp.Format(time.RFC822)
}

func (m meta) Labels() map[string]string {
return m.ObjectMeta.Labels
}

// MetaNode gets the node metadata
func (m meta) MetaNode(id string) report.Node {
return report.MakeNodeWith(id, map[string]string{
ID: m.ID(),
Name: m.Name(),
Namespace: m.Namespace(),
Created: m.Created(),
}).AddTable(LabelPrefix, m.Labels())
}
Loading