mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 18:51:17 +00:00
Merge pull request #1436 from weaveworks/1372-deployment-view
Deployment and Replica Set views
This commit is contained in:
@@ -81,13 +81,6 @@ func init() {
|
||||
Rank: 2,
|
||||
Options: containerFilters,
|
||||
},
|
||||
APITopologyDesc{
|
||||
id: "containers-by-image",
|
||||
parent: "containers",
|
||||
renderer: render.ContainerImageRenderer,
|
||||
Name: "by image",
|
||||
Options: containerFilters,
|
||||
},
|
||||
APITopologyDesc{
|
||||
id: "containers-by-hostname",
|
||||
parent: "containers",
|
||||
@@ -95,6 +88,13 @@ func init() {
|
||||
Name: "by DNS name",
|
||||
Options: containerFilters,
|
||||
},
|
||||
APITopologyDesc{
|
||||
id: "containers-by-image",
|
||||
parent: "containers",
|
||||
renderer: render.ContainerImageRenderer,
|
||||
Name: "by image",
|
||||
Options: containerFilters,
|
||||
},
|
||||
APITopologyDesc{
|
||||
id: "pods",
|
||||
renderer: render.PodRenderer,
|
||||
@@ -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{
|
||||
@@ -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 {
|
||||
@@ -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...)})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
result := &client{
|
||||
quit: make(chan struct{}),
|
||||
resyncPeriod: resyncPeriod,
|
||||
client: c,
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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()
|
||||
@@ -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 {
|
||||
|
||||
59
probe/kubernetes/deployment.go
Normal file
59
probe/kubernetes/deployment.go
Normal file
@@ -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
probe/kubernetes/meta.go
Normal file
67
probe/kubernetes/meta.go
Normal file
@@ -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 {
|
||||
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())
|
||||
}
|
||||
@@ -1,49 +1,39 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
)
|
||||
|
||||
// These constants are keys used in node metadata
|
||||
const (
|
||||
PodID = "kubernetes_pod_id"
|
||||
PodName = "kubernetes_pod_name"
|
||||
PodCreated = "kubernetes_pod_created"
|
||||
PodState = "kubernetes_pod_state"
|
||||
PodLabelPrefix = "kubernetes_pod_labels_"
|
||||
PodIP = "kubernetes_pod_ip"
|
||||
ServiceIDs = "kubernetes_service_ids"
|
||||
State = "kubernetes_state"
|
||||
|
||||
StateDeleted = "deleted"
|
||||
)
|
||||
|
||||
// Pod represents a Kubernetes pod
|
||||
type Pod interface {
|
||||
UID() string
|
||||
ID() string
|
||||
Name() string
|
||||
Namespace() string
|
||||
Created() string
|
||||
AddServiceID(id string)
|
||||
Labels() labels.Labels
|
||||
Meta
|
||||
AddParent(topology, id string)
|
||||
NodeName() string
|
||||
GetNode(probeID string) report.Node
|
||||
}
|
||||
|
||||
type pod struct {
|
||||
*api.Pod
|
||||
serviceIDs report.StringSet
|
||||
Node *api.Node
|
||||
Meta
|
||||
parents report.Sets
|
||||
Node *api.Node
|
||||
}
|
||||
|
||||
// NewPod creates a new Pod
|
||||
func NewPod(p *api.Pod) Pod {
|
||||
return &pod{Pod: p, serviceIDs: report.MakeStringSet()}
|
||||
return &pod{
|
||||
Pod: p,
|
||||
Meta: meta{p.ObjectMeta},
|
||||
parents: report.MakeSets(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pod) UID() string {
|
||||
@@ -51,31 +41,11 @@ func (p *pod) UID() string {
|
||||
if hash, ok := p.ObjectMeta.Annotations["kubernetes.io/config.hash"]; ok {
|
||||
return hash
|
||||
}
|
||||
return string(p.ObjectMeta.UID)
|
||||
return p.Meta.UID()
|
||||
}
|
||||
|
||||
func (p *pod) ID() string {
|
||||
return p.ObjectMeta.Namespace + "/" + p.ObjectMeta.Name
|
||||
}
|
||||
|
||||
func (p *pod) Name() string {
|
||||
return p.ObjectMeta.Name
|
||||
}
|
||||
|
||||
func (p *pod) Namespace() string {
|
||||
return p.ObjectMeta.Namespace
|
||||
}
|
||||
|
||||
func (p *pod) Created() string {
|
||||
return p.ObjectMeta.CreationTimestamp.Format(time.RFC822)
|
||||
}
|
||||
|
||||
func (p *pod) Labels() labels.Labels {
|
||||
return labels.Set(p.ObjectMeta.Labels)
|
||||
}
|
||||
|
||||
func (p *pod) AddServiceID(id string) {
|
||||
p.serviceIDs = p.serviceIDs.Add(id)
|
||||
func (p *pod) AddParent(topology, id string) {
|
||||
p.parents = p.parents.Add(topology, report.MakeStringSet(id))
|
||||
}
|
||||
|
||||
func (p *pod) State() string {
|
||||
@@ -87,25 +57,11 @@ func (p *pod) NodeName() string {
|
||||
}
|
||||
|
||||
func (p *pod) GetNode(probeID string) report.Node {
|
||||
n := report.MakeNodeWith(report.MakePodNodeID(p.UID()), map[string]string{
|
||||
PodID: p.ID(),
|
||||
PodName: p.Name(),
|
||||
Namespace: p.Namespace(),
|
||||
PodCreated: p.Created(),
|
||||
PodState: p.State(),
|
||||
PodIP: p.Status.PodIP,
|
||||
return p.MetaNode(report.MakePodNodeID(p.UID())).WithLatests(map[string]string{
|
||||
State: p.State(),
|
||||
IP: p.Status.PodIP,
|
||||
report.ControlProbeID: probeID,
|
||||
}).WithSets(report.EmptySets.Add(ServiceIDs, p.serviceIDs))
|
||||
for _, serviceID := range p.serviceIDs {
|
||||
segments := strings.SplitN(serviceID, "/", 2)
|
||||
if len(segments) != 2 {
|
||||
continue
|
||||
}
|
||||
n = n.WithParents(report.EmptySets.
|
||||
Add(report.Service, report.MakeStringSet(report.MakeServiceNodeID(p.Namespace(), segments[1]))),
|
||||
)
|
||||
}
|
||||
n = n.AddTable(PodLabelPrefix, p.ObjectMeta.Labels)
|
||||
n = n.WithControls(GetLogs, DeletePod)
|
||||
return n
|
||||
}).
|
||||
WithParents(p.parents).
|
||||
WithControls(GetLogs, DeletePod)
|
||||
}
|
||||
|
||||
63
probe/kubernetes/replica_set.go
Normal file
63
probe/kubernetes/replica_set.go
Normal file
@@ -0,0 +1,63 @@
|
||||
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 (
|
||||
FullyLabeledReplicas = "kubernetes_fully_labeled_replicas"
|
||||
)
|
||||
|
||||
// ReplicaSet represents a Kubernetes replica set
|
||||
type ReplicaSet interface {
|
||||
Meta
|
||||
Selector() labels.Selector
|
||||
AddParent(topology, id string)
|
||||
GetNode(probeID string) report.Node
|
||||
}
|
||||
|
||||
type replicaSet struct {
|
||||
*extensions.ReplicaSet
|
||||
Meta
|
||||
parents report.Sets
|
||||
Node *api.Node
|
||||
}
|
||||
|
||||
// NewReplicaSet creates a new ReplicaSet
|
||||
func NewReplicaSet(r *extensions.ReplicaSet) ReplicaSet {
|
||||
return &replicaSet{
|
||||
ReplicaSet: r,
|
||||
Meta: meta{r.ObjectMeta},
|
||||
parents: report.MakeSets(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *replicaSet) Selector() labels.Selector {
|
||||
selector, err := unversioned.LabelSelectorAsSelector(r.Spec.Selector)
|
||||
if err != nil {
|
||||
// TODO(paulbellamy): Remove the panic!
|
||||
panic(err)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
func (r *replicaSet) AddParent(topology, id string) {
|
||||
r.parents = r.parents.Add(topology, report.MakeStringSet(id))
|
||||
}
|
||||
|
||||
func (r *replicaSet) GetNode(probeID string) report.Node {
|
||||
return r.MetaNode(report.MakeReplicaSetNodeID(r.UID())).WithLatests(map[string]string{
|
||||
ObservedGeneration: fmt.Sprint(r.Status.ObservedGeneration),
|
||||
Replicas: fmt.Sprint(r.Status.Replicas),
|
||||
DesiredReplicas: fmt.Sprint(r.Spec.Replicas),
|
||||
FullyLabeledReplicas: fmt.Sprint(r.Status.FullyLabeledReplicas),
|
||||
report.ControlProbeID: probeID,
|
||||
}).WithParents(r.parents)
|
||||
}
|
||||
46
probe/kubernetes/replication_controller.go
Normal file
46
probe/kubernetes/replication_controller.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
)
|
||||
|
||||
type replicationController struct {
|
||||
*api.ReplicationController
|
||||
Meta
|
||||
parents report.Sets
|
||||
Node *api.Node
|
||||
}
|
||||
|
||||
// NewReplicationController creates a new ReplicationController
|
||||
func NewReplicationController(r *api.ReplicationController) ReplicaSet {
|
||||
return &replicationController{
|
||||
ReplicationController: r,
|
||||
Meta: meta{r.ObjectMeta},
|
||||
parents: report.MakeSets(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *replicationController) Selector() labels.Selector {
|
||||
if r.Spec.Selector == nil {
|
||||
return labels.Nothing()
|
||||
}
|
||||
return labels.SelectorFromSet(labels.Set(r.Spec.Selector))
|
||||
}
|
||||
|
||||
func (r *replicationController) AddParent(topology, id string) {
|
||||
r.parents = r.parents.Add(topology, report.MakeStringSet(id))
|
||||
}
|
||||
|
||||
func (r *replicationController) GetNode(probeID string) report.Node {
|
||||
return r.MetaNode(report.MakeReplicaSetNodeID(r.UID())).WithLatests(map[string]string{
|
||||
ObservedGeneration: fmt.Sprint(r.Status.ObservedGeneration),
|
||||
Replicas: fmt.Sprint(r.Status.Replicas),
|
||||
DesiredReplicas: fmt.Sprint(r.Spec.Replicas),
|
||||
FullyLabeledReplicas: fmt.Sprint(r.Status.FullyLabeledReplicas),
|
||||
report.ControlProbeID: probeID,
|
||||
}).WithParents(r.parents)
|
||||
}
|
||||
@@ -15,32 +15,55 @@ import (
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// These constants are keys used in node metadata
|
||||
const (
|
||||
IP = "kubernetes_ip"
|
||||
ObservedGeneration = "kubernetes_observed_generation"
|
||||
Replicas = "kubernetes_replicas"
|
||||
DesiredReplicas = "kubernetes_desired_replicas"
|
||||
)
|
||||
|
||||
// Exposed for testing
|
||||
var (
|
||||
PodMetadataTemplates = report.MetadataTemplates{
|
||||
PodID: {ID: PodID, Label: "ID", From: report.FromLatest, Priority: 1},
|
||||
PodState: {ID: PodState, Label: "State", From: report.FromLatest, Priority: 2},
|
||||
PodIP: {ID: PodIP, Label: "IP", From: report.FromLatest, Priority: 3},
|
||||
ID: {ID: ID, Label: "ID", From: report.FromLatest, Priority: 1},
|
||||
State: {ID: State, Label: "State", From: report.FromLatest, Priority: 2},
|
||||
IP: {ID: IP, Label: "IP", From: report.FromLatest, Priority: 3},
|
||||
report.Container: {ID: report.Container, Label: "# Containers", From: report.FromCounters, Datatype: "number", Priority: 4},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 5},
|
||||
PodCreated: {ID: PodCreated, Label: "Created", From: report.FromLatest, Priority: 6},
|
||||
Created: {ID: Created, Label: "Created", From: report.FromLatest, Priority: 6},
|
||||
}
|
||||
|
||||
ServiceMetadataTemplates = report.MetadataTemplates{
|
||||
ServiceID: {ID: ServiceID, Label: "ID", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
|
||||
ServiceCreated: {ID: ServiceCreated, Label: "Created", From: report.FromLatest, Priority: 3},
|
||||
ServicePublicIP: {ID: ServicePublicIP, Label: "Public IP", From: report.FromLatest, Priority: 4},
|
||||
ServiceIP: {ID: ServiceIP, Label: "Internal IP", From: report.FromLatest, Priority: 5},
|
||||
report.Pod: {ID: report.Pod, Label: "# Pods", From: report.FromCounters, Datatype: "number", Priority: 6},
|
||||
ID: {ID: ID, Label: "ID", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
|
||||
Created: {ID: Created, Label: "Created", From: report.FromLatest, Priority: 3},
|
||||
PublicIP: {ID: PublicIP, Label: "Public IP", From: report.FromLatest, Priority: 4},
|
||||
IP: {ID: IP, Label: "Internal IP", From: report.FromLatest, Priority: 5},
|
||||
report.Pod: {ID: report.Pod, Label: "# Pods", From: report.FromCounters, Datatype: "number", Priority: 6},
|
||||
}
|
||||
|
||||
PodTableTemplates = report.TableTemplates{
|
||||
PodLabelPrefix: {ID: PodLabelPrefix, Label: "Kubernetes Labels", Prefix: PodLabelPrefix},
|
||||
DeploymentMetadataTemplates = report.MetadataTemplates{
|
||||
ID: {ID: ID, Label: "ID", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
|
||||
Created: {ID: Created, Label: "Created", From: report.FromLatest, Priority: 3},
|
||||
ObservedGeneration: {ID: ObservedGeneration, Label: "Observed Gen.", From: report.FromLatest, Priority: 4},
|
||||
DesiredReplicas: {ID: DesiredReplicas, Label: "Desired Replicas", From: report.FromLatest, Datatype: "number", Priority: 5},
|
||||
report.Pod: {ID: report.Pod, Label: "# Pods", From: report.FromCounters, Datatype: "number", Priority: 6},
|
||||
Strategy: {ID: Strategy, Label: "Strategy", From: report.FromLatest, Priority: 7},
|
||||
}
|
||||
|
||||
ServiceTableTemplates = report.TableTemplates{
|
||||
ServiceLabelPrefix: {ID: ServiceLabelPrefix, Label: "Kubernetes Labels", Prefix: ServiceLabelPrefix},
|
||||
ReplicaSetMetadataTemplates = report.MetadataTemplates{
|
||||
ID: {ID: ID, Label: "ID", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
|
||||
Created: {ID: Created, Label: "Created", From: report.FromLatest, Priority: 3},
|
||||
ObservedGeneration: {ID: ObservedGeneration, Label: "Observed Gen.", From: report.FromLatest, Priority: 4},
|
||||
DesiredReplicas: {ID: DesiredReplicas, Label: "Desired Replicas", From: report.FromLatest, Datatype: "number", Priority: 5},
|
||||
report.Pod: {ID: report.Pod, Label: "# Pods", From: report.FromCounters, Datatype: "number", Priority: 6},
|
||||
}
|
||||
|
||||
TableTemplates = report.TableTemplates{
|
||||
LabelPrefix: {ID: LabelPrefix, Label: "Kubernetes Labels", Prefix: LabelPrefix},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -86,7 +109,7 @@ func (r *Reporter) podEvent(e Event, pod Pod) {
|
||||
rpt.Pod.AddNode(
|
||||
report.MakeNodeWith(
|
||||
report.MakePodNodeID(pod.UID()),
|
||||
map[string]string{PodState: StateDeleted},
|
||||
map[string]string{State: StateDeleted},
|
||||
),
|
||||
)
|
||||
r.probe.Publish(rpt)
|
||||
@@ -142,12 +165,22 @@ func (r *Reporter) Report() (report.Report, error) {
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
podTopology, err := r.podTopology(services)
|
||||
deploymentTopology, deployments, err := r.deploymentTopology(r.probeID)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
replicaSetTopology, replicaSets, err := r.replicaSetTopology(r.probeID, deployments)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
podTopology, err := r.podTopology(services, replicaSets)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Service = result.Service.Merge(serviceTopology)
|
||||
result.Pod = result.Pod.Merge(podTopology)
|
||||
result.Service = result.Service.Merge(serviceTopology)
|
||||
result.Deployment = result.Deployment.Merge(deploymentTopology)
|
||||
result.ReplicaSet = result.ReplicaSet.Merge(replicaSetTopology)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -155,7 +188,7 @@ func (r *Reporter) serviceTopology() (report.Topology, []Service, error) {
|
||||
var (
|
||||
result = report.MakeTopology().
|
||||
WithMetadataTemplates(ServiceMetadataTemplates).
|
||||
WithTableTemplates(ServiceTableTemplates)
|
||||
WithTableTemplates(TableTemplates)
|
||||
services = []Service{}
|
||||
)
|
||||
err := r.client.WalkServices(func(s Service) error {
|
||||
@@ -166,6 +199,48 @@ func (r *Reporter) serviceTopology() (report.Topology, []Service, error) {
|
||||
return result, services, err
|
||||
}
|
||||
|
||||
func (r *Reporter) deploymentTopology(probeID string) (report.Topology, []Deployment, error) {
|
||||
var (
|
||||
result = report.MakeTopology().
|
||||
WithMetadataTemplates(DeploymentMetadataTemplates).
|
||||
WithTableTemplates(TableTemplates)
|
||||
deployments = []Deployment{}
|
||||
)
|
||||
err := r.client.WalkDeployments(func(d Deployment) error {
|
||||
result = result.AddNode(d.GetNode(probeID))
|
||||
deployments = append(deployments, d)
|
||||
return nil
|
||||
})
|
||||
return result, deployments, err
|
||||
}
|
||||
|
||||
func (r *Reporter) replicaSetTopology(probeID string, deployments []Deployment) (report.Topology, []ReplicaSet, error) {
|
||||
var (
|
||||
result = report.MakeTopology().
|
||||
WithMetadataTemplates(ReplicaSetMetadataTemplates).
|
||||
WithTableTemplates(TableTemplates)
|
||||
replicaSets = []ReplicaSet{}
|
||||
selectors = []func(labelledChild){}
|
||||
)
|
||||
for _, deployment := range deployments {
|
||||
selectors = append(selectors, match(
|
||||
deployment.Selector(),
|
||||
report.Deployment,
|
||||
report.MakeDeploymentNodeID(deployment.UID()),
|
||||
))
|
||||
}
|
||||
|
||||
err := r.client.WalkReplicaSets(func(r ReplicaSet) error {
|
||||
for _, selector := range selectors {
|
||||
selector(r)
|
||||
}
|
||||
result = result.AddNode(r.GetNode(probeID))
|
||||
replicaSets = append(replicaSets, r)
|
||||
return nil
|
||||
})
|
||||
return result, replicaSets, err
|
||||
}
|
||||
|
||||
// GetNodeName return the k8s node name for the current machine.
|
||||
// It is exported for testing.
|
||||
var GetNodeName = func(r *Reporter) (string, error) {
|
||||
@@ -187,12 +262,26 @@ var GetNodeName = func(r *Reporter) (string, error) {
|
||||
return nodeName, err
|
||||
}
|
||||
|
||||
func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
|
||||
type labelledChild interface {
|
||||
Labels() map[string]string
|
||||
AddParent(string, string)
|
||||
}
|
||||
|
||||
// Match parses the selectors and adds the target as a parent if the selector matches.
|
||||
func match(selector labels.Selector, topology, id string) func(labelledChild) {
|
||||
return func(c labelledChild) {
|
||||
if selector.Matches(labels.Set(c.Labels())) {
|
||||
c.AddParent(topology, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reporter) podTopology(services []Service, replicaSets []ReplicaSet) (report.Topology, error) {
|
||||
var (
|
||||
pods = report.MakeTopology().
|
||||
WithMetadataTemplates(PodMetadataTemplates).
|
||||
WithTableTemplates(PodTableTemplates)
|
||||
selectors = map[string]labels.Selector{}
|
||||
WithTableTemplates(TableTemplates)
|
||||
selectors = []func(labelledChild){}
|
||||
)
|
||||
pods.Controls.AddControl(report.Control{
|
||||
ID: GetLogs,
|
||||
@@ -207,7 +296,18 @@ func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
|
||||
Rank: 1,
|
||||
})
|
||||
for _, service := range services {
|
||||
selectors[service.ID()] = service.Selector()
|
||||
selectors = append(selectors, match(
|
||||
service.Selector(),
|
||||
report.Service,
|
||||
report.MakeServiceNodeID(service.UID()),
|
||||
))
|
||||
}
|
||||
for _, replicaSet := range replicaSets {
|
||||
selectors = append(selectors, match(
|
||||
replicaSet.Selector(),
|
||||
report.ReplicaSet,
|
||||
report.MakeReplicaSetNodeID(replicaSet.UID()),
|
||||
))
|
||||
}
|
||||
|
||||
thisNodeName, err := GetNodeName(r)
|
||||
@@ -218,10 +318,8 @@ func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
|
||||
if p.NodeName() != thisNodeName {
|
||||
return nil
|
||||
}
|
||||
for serviceID, selector := range selectors {
|
||||
if selector.Matches(p.Labels()) {
|
||||
p.AddServiceID(serviceID)
|
||||
}
|
||||
for _, selector := range selectors {
|
||||
selector(p)
|
||||
}
|
||||
pods = pods.AddNode(p.GetNode(r.probeID))
|
||||
return nil
|
||||
|
||||
@@ -22,6 +22,7 @@ var (
|
||||
nodeName = "nodename"
|
||||
pod1UID = "a1b2c3d4e5"
|
||||
pod2UID = "f6g7h8i9j0"
|
||||
serviceUID = "service1234"
|
||||
podTypeMeta = unversioned.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
@@ -73,6 +74,7 @@ var (
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "pongservice",
|
||||
UID: types.UID(serviceUID),
|
||||
Namespace: "ping",
|
||||
CreationTimestamp: unversioned.Now(),
|
||||
},
|
||||
@@ -129,6 +131,12 @@ func (c *mockClient) WalkServices(f func(kubernetes.Service) error) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *mockClient) WalkDeployments(f func(kubernetes.Deployment) error) error {
|
||||
return nil
|
||||
}
|
||||
func (c *mockClient) WalkReplicaSets(f func(kubernetes.ReplicaSet) error) error {
|
||||
return nil
|
||||
}
|
||||
func (*mockClient) WalkNodes(f func(*api.Node) error) error {
|
||||
return nil
|
||||
}
|
||||
@@ -166,7 +174,7 @@ func TestReporter(t *testing.T) {
|
||||
|
||||
pod1ID := report.MakePodNodeID(pod1UID)
|
||||
pod2ID := report.MakePodNodeID(pod2UID)
|
||||
serviceID := report.MakeServiceNodeID("ping", "pongservice")
|
||||
serviceID := report.MakeServiceNodeID(serviceUID)
|
||||
rpt, _ := kubernetes.NewReporter(newMockClient(), nil, "", nil).Report()
|
||||
|
||||
// Reporter should have added the following pods
|
||||
@@ -174,23 +182,18 @@ func TestReporter(t *testing.T) {
|
||||
id string
|
||||
parentService string
|
||||
latest map[string]string
|
||||
sets map[string]report.StringSet
|
||||
}{
|
||||
{pod1ID, serviceID, map[string]string{
|
||||
kubernetes.PodID: "ping/pong-a",
|
||||
kubernetes.PodName: "pong-a",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.PodCreated: pod1.Created(),
|
||||
}, map[string]report.StringSet{
|
||||
kubernetes.ServiceIDs: report.MakeStringSet("ping/pongservice"),
|
||||
kubernetes.ID: "ping/pong-a",
|
||||
kubernetes.Name: "pong-a",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.Created: pod1.Created(),
|
||||
}},
|
||||
{pod2ID, serviceID, map[string]string{
|
||||
kubernetes.PodID: "ping/pong-b",
|
||||
kubernetes.PodName: "pong-b",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.PodCreated: pod1.Created(),
|
||||
}, map[string]report.StringSet{
|
||||
kubernetes.ServiceIDs: report.MakeStringSet("ping/pongservice"),
|
||||
kubernetes.ID: "ping/pong-b",
|
||||
kubernetes.Name: "pong-b",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.Created: pod1.Created(),
|
||||
}},
|
||||
} {
|
||||
node, ok := rpt.Pod.Nodes[pod.id]
|
||||
@@ -207,12 +210,6 @@ func TestReporter(t *testing.T) {
|
||||
t.Errorf("Expected pod %s latest %q: %q, got %q", pod.id, k, want, have)
|
||||
}
|
||||
}
|
||||
|
||||
for k, want := range pod.sets {
|
||||
if have, ok := node.Sets.Lookup(k); !ok || !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("Expected pod %s sets %q: %q, got %q", pod.id, k, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reporter should have added a service
|
||||
@@ -223,10 +220,10 @@ func TestReporter(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, want := range map[string]string{
|
||||
kubernetes.ServiceID: "ping/pongservice",
|
||||
kubernetes.ServiceName: "pongservice",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.ServiceCreated: pod1.Created(),
|
||||
kubernetes.ID: "ping/pongservice",
|
||||
kubernetes.Name: "pongservice",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.Created: pod1.Created(),
|
||||
} {
|
||||
if have, ok := node.Latest.Lookup(k); !ok || have != want {
|
||||
t.Errorf("Expected service %s latest %q: %q, got %q", serviceID, k, want, have)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
@@ -10,47 +8,24 @@ import (
|
||||
|
||||
// These constants are keys used in node metadata
|
||||
const (
|
||||
ServiceID = "kubernetes_service_id"
|
||||
ServiceName = "kubernetes_service_name"
|
||||
ServiceCreated = "kubernetes_service_created"
|
||||
ServiceIP = "kubernetes_service_ip"
|
||||
ServicePublicIP = "kubernetes_service_public_ip"
|
||||
ServiceLabelPrefix = "kubernetes_service_label_"
|
||||
PublicIP = "kubernetes_public_ip"
|
||||
)
|
||||
|
||||
// Service represents a Kubernetes service
|
||||
type Service interface {
|
||||
UID() string
|
||||
ID() string
|
||||
Name() string
|
||||
Namespace() string
|
||||
Meta
|
||||
GetNode() report.Node
|
||||
Selector() labels.Selector
|
||||
}
|
||||
|
||||
type service struct {
|
||||
*api.Service
|
||||
Meta
|
||||
}
|
||||
|
||||
// NewService creates a new Service
|
||||
func NewService(s *api.Service) Service {
|
||||
return &service{Service: s}
|
||||
}
|
||||
|
||||
func (s *service) UID() string {
|
||||
return string(s.ObjectMeta.UID)
|
||||
}
|
||||
|
||||
func (s *service) ID() string {
|
||||
return s.ObjectMeta.Namespace + "/" + s.ObjectMeta.Name
|
||||
}
|
||||
|
||||
func (s *service) Name() string {
|
||||
return s.ObjectMeta.Name
|
||||
}
|
||||
|
||||
func (s *service) Namespace() string {
|
||||
return s.ObjectMeta.Namespace
|
||||
return &service{Service: s, Meta: meta{s.ObjectMeta}}
|
||||
}
|
||||
|
||||
func (s *service) Selector() labels.Selector {
|
||||
@@ -61,19 +36,9 @@ func (s *service) Selector() labels.Selector {
|
||||
}
|
||||
|
||||
func (s *service) GetNode() report.Node {
|
||||
latest := map[string]string{
|
||||
ServiceID: s.ID(),
|
||||
ServiceName: s.Name(),
|
||||
ServiceCreated: s.ObjectMeta.CreationTimestamp.Format(time.RFC822),
|
||||
Namespace: s.Namespace(),
|
||||
ServiceIP: s.Spec.ClusterIP,
|
||||
}
|
||||
latest := map[string]string{IP: s.Spec.ClusterIP}
|
||||
if s.Spec.LoadBalancerIP != "" {
|
||||
latest[ServicePublicIP] = s.Spec.LoadBalancerIP
|
||||
latest[PublicIP] = s.Spec.LoadBalancerIP
|
||||
}
|
||||
return report.MakeNodeWith(
|
||||
report.MakeServiceNodeID(s.Namespace(), s.Name()),
|
||||
latest,
|
||||
).
|
||||
AddTable(ServiceLabelPrefix, s.Labels)
|
||||
return s.MetaNode(report.MakeServiceNodeID(s.UID())).WithLatests(latest)
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ func TestProbe(t *testing.T) {
|
||||
want.ContainerImage.Controls = nil
|
||||
want.Pod.Controls = nil
|
||||
want.Service.Controls = nil
|
||||
want.Deployment.Controls = nil
|
||||
want.ReplicaSet.Controls = nil
|
||||
want.Host.Controls = nil
|
||||
want.Overlay.Controls = nil
|
||||
want.Endpoint.AddNode(node)
|
||||
|
||||
@@ -140,6 +140,28 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
topologyID: report.Service,
|
||||
NodeSummaryGroup: NodeSummaryGroup{
|
||||
TopologyID: "services",
|
||||
Label: "Services",
|
||||
Columns: []Column{
|
||||
{ID: report.Pod, Label: "# Pods"},
|
||||
{ID: kubernetes.IP, Label: "IP"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
topologyID: report.ReplicaSet,
|
||||
NodeSummaryGroup: NodeSummaryGroup{
|
||||
TopologyID: "replica-sets",
|
||||
Label: "Replica Sets",
|
||||
Columns: []Column{
|
||||
{ID: report.Pod, Label: "# Pods"},
|
||||
{ID: kubernetes.ObservedGeneration, Label: "Observed Gen."},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
topologyID: report.Pod,
|
||||
NodeSummaryGroup: NodeSummaryGroup{
|
||||
@@ -148,18 +170,7 @@ var (
|
||||
|
||||
Columns: []Column{
|
||||
{ID: report.Container, Label: "# Containers"},
|
||||
{ID: kubernetes.PodIP, Label: "IP"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
topologyID: report.Service,
|
||||
NodeSummaryGroup: NodeSummaryGroup{
|
||||
TopologyID: "pods-by-service",
|
||||
Label: "Services",
|
||||
Columns: []Column{
|
||||
{ID: report.Pod, Label: "# Pods"},
|
||||
{ID: kubernetes.ServiceIP, Label: "IP"},
|
||||
{ID: kubernetes.IP, Label: "IP"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestMakeDetailedHostNode(t *testing.T) {
|
||||
TopologyID: "pods",
|
||||
Columns: []detailed.Column{
|
||||
{ID: report.Container, Label: "# Containers"},
|
||||
{ID: kubernetes.PodIP, Label: "IP"},
|
||||
{ID: kubernetes.IP, Label: "IP"},
|
||||
},
|
||||
Nodes: []detailed.NodeSummary{podNodeSummary},
|
||||
},
|
||||
@@ -327,8 +327,8 @@ func TestMakeDetailedPodNode(t *testing.T) {
|
||||
Linkable: true,
|
||||
Pseudo: false,
|
||||
Metadata: []report.MetadataRow{
|
||||
{ID: "kubernetes_pod_id", Label: "ID", Value: "ping/pong-b", Priority: 1},
|
||||
{ID: "kubernetes_pod_state", Label: "State", Value: "running", Priority: 2},
|
||||
{ID: "kubernetes_id", Label: "ID", Value: "ping/pong-b", Priority: 1},
|
||||
{ID: "kubernetes_state", Label: "State", Value: "running", Priority: 2},
|
||||
{ID: "container", Label: "# Containers", Value: "1", Priority: 4, Datatype: "number"},
|
||||
{ID: "kubernetes_namespace", Label: "Namespace", Value: "ping", Priority: 5},
|
||||
},
|
||||
@@ -361,6 +361,11 @@ func TestMakeDetailedPodNode(t *testing.T) {
|
||||
Label: fixture.ServerHostName,
|
||||
TopologyID: "hosts",
|
||||
},
|
||||
{
|
||||
ID: fixture.ServiceNodeID,
|
||||
Label: fixture.ServiceName,
|
||||
TopologyID: "services",
|
||||
},
|
||||
},
|
||||
Connections: []detailed.ConnectionsSummary{
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@ func Parents(r report.Report, n report.Node) (result []Parent) {
|
||||
}{
|
||||
report.Container: {r.Container, containerParent},
|
||||
report.Pod: {r.Pod, podParent},
|
||||
report.ReplicaSet: {r.ReplicaSet, replicaSetParent},
|
||||
report.Deployment: {r.Deployment, deploymentParent},
|
||||
report.Service: {r.Service, serviceParent},
|
||||
report.ContainerImage: {r.ContainerImage, containerImageParent},
|
||||
report.Host: {r.Host, hostParent},
|
||||
@@ -62,21 +64,21 @@ func containerParent(n report.Node) Parent {
|
||||
}
|
||||
}
|
||||
|
||||
func podParent(n report.Node) Parent {
|
||||
podName, _ := n.Latest.Lookup(kubernetes.PodName)
|
||||
return Parent{
|
||||
ID: n.ID,
|
||||
Label: podName,
|
||||
TopologyID: "pods",
|
||||
}
|
||||
}
|
||||
var (
|
||||
podParent = kubernetesParent("pods")
|
||||
replicaSetParent = kubernetesParent("replica-sets")
|
||||
deploymentParent = kubernetesParent("deployments")
|
||||
serviceParent = kubernetesParent("services")
|
||||
)
|
||||
|
||||
func serviceParent(n report.Node) Parent {
|
||||
serviceName, _ := n.Latest.Lookup(kubernetes.ServiceName)
|
||||
return Parent{
|
||||
ID: n.ID,
|
||||
Label: serviceName,
|
||||
TopologyID: "pods-by-service",
|
||||
func kubernetesParent(topology string) func(report.Node) Parent {
|
||||
return func(n report.Node) Parent {
|
||||
name, _ := n.Latest.Lookup(kubernetes.Name)
|
||||
return Parent{
|
||||
ID: n.ID,
|
||||
Label: name,
|
||||
TopologyID: topology,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,8 @@ func MakeNodeSummary(r report.Report, n report.Node) (NodeSummary, bool) {
|
||||
report.ContainerImage: containerImageNodeSummary,
|
||||
report.Pod: podNodeSummary,
|
||||
report.Service: serviceNodeSummary,
|
||||
report.Deployment: deploymentNodeSummary,
|
||||
report.ReplicaSet: replicaSetNodeSummary,
|
||||
report.Host: hostNodeSummary,
|
||||
}
|
||||
if renderer, ok := renderers[n.Topology]; ok {
|
||||
@@ -238,8 +240,8 @@ func containerImageNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bo
|
||||
}
|
||||
|
||||
func podNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base.Label, _ = n.Latest.Lookup(kubernetes.PodName)
|
||||
base.Rank, _ = n.Latest.Lookup(kubernetes.PodID)
|
||||
base.Label, _ = n.Latest.Lookup(kubernetes.Name)
|
||||
base.Rank, _ = n.Latest.Lookup(kubernetes.ID)
|
||||
|
||||
if c, ok := n.Counters.Lookup(report.Container); ok {
|
||||
if c == 1 {
|
||||
@@ -253,8 +255,8 @@ func podNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
}
|
||||
|
||||
func serviceNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base.Label, _ = n.Latest.Lookup(kubernetes.ServiceName)
|
||||
base.Rank, _ = n.Latest.Lookup(kubernetes.ServiceID)
|
||||
base.Label, _ = n.Latest.Lookup(kubernetes.Name)
|
||||
base.Rank, _ = n.Latest.Lookup(kubernetes.ID)
|
||||
base.Stack = true
|
||||
|
||||
// Services are always just a group of pods, so there's no counting multiple
|
||||
@@ -270,6 +272,38 @@ func serviceNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
return base, true
|
||||
}
|
||||
|
||||
func deploymentNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base.Label, _ = n.Latest.Lookup(kubernetes.Name)
|
||||
base.Rank, _ = n.Latest.Lookup(kubernetes.ID)
|
||||
base.Stack = true
|
||||
|
||||
if p, ok := n.Counters.Lookup(report.Pod); ok {
|
||||
if p == 1 {
|
||||
base.LabelMinor = fmt.Sprintf("%d pod", p)
|
||||
} else {
|
||||
base.LabelMinor = fmt.Sprintf("%d pods", p)
|
||||
}
|
||||
}
|
||||
|
||||
return base, true
|
||||
}
|
||||
|
||||
func replicaSetNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base.Label, _ = n.Latest.Lookup(kubernetes.Name)
|
||||
base.Rank, _ = n.Latest.Lookup(kubernetes.ID)
|
||||
base.Stack = true
|
||||
|
||||
if p, ok := n.Counters.Lookup(report.Pod); ok {
|
||||
if p == 1 {
|
||||
base.LabelMinor = fmt.Sprintf("%d pod", p)
|
||||
} else {
|
||||
base.LabelMinor = fmt.Sprintf("%d pods", p)
|
||||
}
|
||||
}
|
||||
|
||||
return base, true
|
||||
}
|
||||
|
||||
func hostNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
var (
|
||||
hostname, _ = n.Latest.Lookup(host.HostName)
|
||||
|
||||
@@ -23,7 +23,7 @@ func renderKubernetesTopologies(rpt report.Report) bool {
|
||||
var PodRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
||||
ApplyDecorators(MakeFilter(
|
||||
func(n report.Node) bool {
|
||||
state, ok := n.Latest.Lookup(kubernetes.PodState)
|
||||
state, ok := n.Latest.Lookup(kubernetes.State)
|
||||
return (!ok || state != kubernetes.StateDeleted)
|
||||
},
|
||||
MakeReduce(
|
||||
@@ -42,7 +42,7 @@ var PodServiceRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
||||
ApplyDecorators(FilterEmpty(report.Pod,
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
MapPod2Service,
|
||||
Map2Service,
|
||||
PodRenderer,
|
||||
),
|
||||
SelectService,
|
||||
@@ -50,6 +50,34 @@ var PodServiceRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
||||
)),
|
||||
)
|
||||
|
||||
// DeploymentRenderer is a Renderer which produces a renderable kubernetes deployments
|
||||
// graph by merging the pods graph and the deployments topology.
|
||||
var DeploymentRenderer = ApplyDecorators(
|
||||
FilterEmpty(report.Pod,
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
Map2Deployment,
|
||||
ReplicaSetRenderer,
|
||||
),
|
||||
SelectDeployment,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// ReplicaSetRenderer is a Renderer which produces a renderable kubernetes replica sets
|
||||
// graph by merging the pods graph and the replica sets topology.
|
||||
var ReplicaSetRenderer = ApplyDecorators(
|
||||
FilterEmpty(report.Pod,
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
Map2ReplicaSet,
|
||||
PodRenderer,
|
||||
),
|
||||
SelectReplicaSet,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// MapContainer2Pod maps container Nodes to pod
|
||||
// Nodes.
|
||||
//
|
||||
@@ -95,40 +123,35 @@ func MapContainer2Pod(n report.Node, _ report.Networks) report.Nodes {
|
||||
return report.Nodes{id: node}
|
||||
}
|
||||
|
||||
// MapPod2Service maps pod Nodes to service Nodes.
|
||||
//
|
||||
// If this function is given a node without a kubernetes_pod_id
|
||||
// (including other pseudo nodes), it will produce an "Uncontained"
|
||||
// pseudo node.
|
||||
//
|
||||
// Otherwise, this function will produce a node with the correct ID
|
||||
// format for a container, but without any Major or Minor labels.
|
||||
// It does not have enough info to do that, and the resulting graph
|
||||
// must be merged with a pod graph to get that info.
|
||||
func MapPod2Service(pod report.Node, _ report.Networks) report.Nodes {
|
||||
// Propagate all pseudo nodes
|
||||
if pod.Topology == Pseudo {
|
||||
return report.Nodes{pod.ID: pod}
|
||||
}
|
||||
// The various ways of grouping pods
|
||||
var (
|
||||
Map2Service = Map2Parent(report.Service)
|
||||
Map2Deployment = Map2Parent(report.Deployment)
|
||||
Map2ReplicaSet = Map2Parent(report.ReplicaSet)
|
||||
)
|
||||
|
||||
// Otherwise, if some some reason the pod doesn't have a service_ids (maybe
|
||||
// slightly out of sync reports, or its not in a service), just drop it
|
||||
namespace, ok := pod.Latest.Lookup(kubernetes.Namespace)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
serviceIDs, ok := pod.Sets.Lookup(kubernetes.ServiceIDs)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
// Map2Parent maps Nodes to some parent grouping.
|
||||
func Map2Parent(topology string) func(n report.Node, _ report.Networks) report.Nodes {
|
||||
return func(n report.Node, _ report.Networks) report.Nodes {
|
||||
// Propagate all pseudo nodes
|
||||
if n.Topology == Pseudo {
|
||||
return report.Nodes{n.ID: n}
|
||||
}
|
||||
|
||||
result := report.Nodes{}
|
||||
for _, serviceID := range serviceIDs {
|
||||
serviceName := strings.TrimPrefix(serviceID, namespace+"/")
|
||||
id := report.MakeServiceNodeID(namespace, serviceName)
|
||||
node := NewDerivedNode(id, pod).WithTopology(report.Service)
|
||||
node.Counters = node.Counters.Add(pod.Topology, 1)
|
||||
result[id] = node
|
||||
// Otherwise, if some some reason the node doesn't have any of these ids
|
||||
// (maybe slightly out of sync reports, or its not in this group), just
|
||||
// drop it
|
||||
groupIDs, ok := n.Parents.Lookup(topology)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
result := report.Nodes{}
|
||||
for _, id := range groupIDs {
|
||||
node := NewDerivedNode(id, n).WithTopology(topology)
|
||||
node.Counters = node.Counters.Add(n.Topology, 1)
|
||||
result[id] = node
|
||||
}
|
||||
return result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -29,4 +29,6 @@ var (
|
||||
SelectHost = TopologySelector(report.Host)
|
||||
SelectPod = TopologySelector(report.Pod)
|
||||
SelectService = TopologySelector(report.Service)
|
||||
SelectDeployment = TopologySelector(report.Deployment)
|
||||
SelectReplicaSet = TopologySelector(report.ReplicaSet)
|
||||
)
|
||||
|
||||
46
report/id.go
46
report/id.go
@@ -96,32 +96,34 @@ func MakeProcessNodeID(hostID, pid string) string {
|
||||
return hostID + ScopeDelim + pid
|
||||
}
|
||||
|
||||
// MakeHostNodeID produces a host node ID from its composite parts.
|
||||
func MakeHostNodeID(hostID string) string {
|
||||
// hostIDs come from the probe and are presumed to be globally-unique.
|
||||
// But, suffix something to elicit failures if we try to use probe host
|
||||
// IDs directly as node IDs in the host topology.
|
||||
return hostID + ScopeDelim + "<host>"
|
||||
}
|
||||
var (
|
||||
// MakeHostNodeID produces a host node ID from its composite parts.
|
||||
MakeHostNodeID = singleComponentID("host")
|
||||
|
||||
// MakeContainerNodeID produces a container node ID from its composite parts.
|
||||
func MakeContainerNodeID(containerID string) string {
|
||||
return containerID + ScopeDelim + "<container>"
|
||||
}
|
||||
// MakeContainerNodeID produces a container node ID from its composite parts.
|
||||
MakeContainerNodeID = singleComponentID("container")
|
||||
|
||||
// MakeContainerImageNodeID produces a container image node ID from its composite parts.
|
||||
func MakeContainerImageNodeID(containerImageID string) string {
|
||||
return containerImageID + ScopeDelim + "<container_image>"
|
||||
}
|
||||
// MakeContainerImageNodeID produces a container image node ID from its composite parts.
|
||||
MakeContainerImageNodeID = singleComponentID("container_image")
|
||||
|
||||
// MakePodNodeID produces a pod node ID from its composite parts.
|
||||
func MakePodNodeID(uid string) string {
|
||||
return uid + ScopeDelim + "<pod>"
|
||||
}
|
||||
// MakePodNodeID produces a pod node ID from its composite parts.
|
||||
MakePodNodeID = singleComponentID("pod")
|
||||
|
||||
// MakeServiceNodeID produces a service node ID from its composite parts.
|
||||
func MakeServiceNodeID(namespaceID, serviceID string) string {
|
||||
return namespaceID + ScopeDelim + serviceID
|
||||
// MakeServiceNodeID produces a service node ID from its composite parts.
|
||||
MakeServiceNodeID = singleComponentID("service")
|
||||
|
||||
// MakeDeploymentNodeID produces a deployment node ID from its composite parts.
|
||||
MakeDeploymentNodeID = singleComponentID("deployment")
|
||||
|
||||
// MakeReplicaSetNodeID produces a replica set node ID from its composite parts.
|
||||
MakeReplicaSetNodeID = singleComponentID("replica_set")
|
||||
)
|
||||
|
||||
// singleComponentID makes a
|
||||
func singleComponentID(tag string) func(string) string {
|
||||
return func(id string) string {
|
||||
return id + ScopeDelim + "<" + tag + ">"
|
||||
}
|
||||
}
|
||||
|
||||
// MakeOverlayNodeID produces an overlay topology node ID from a router peer's
|
||||
|
||||
@@ -16,6 +16,8 @@ const (
|
||||
Container = "container"
|
||||
Pod = "pod"
|
||||
Service = "service"
|
||||
Deployment = "deployment"
|
||||
ReplicaSet = "replica_set"
|
||||
ContainerImage = "container_image"
|
||||
Host = "host"
|
||||
Overlay = "overlay"
|
||||
@@ -58,6 +60,16 @@ type Report struct {
|
||||
// present.
|
||||
Service Topology
|
||||
|
||||
// Deployment nodes represent all Kubernetes deployments running on hosts running probes.
|
||||
// Metadata includes things like deployment id, name etc. Edges are not
|
||||
// present.
|
||||
Deployment Topology
|
||||
|
||||
// ReplicaSet nodes represent all Kubernetes replicasets running on hosts running probes.
|
||||
// Metadata includes things like replicaset id, name etc. Edges are not
|
||||
// present.
|
||||
ReplicaSet Topology
|
||||
|
||||
// ContainerImages nodes represent all Docker containers images on
|
||||
// hosts running probes. Metadata includes things like image id, name etc.
|
||||
// Edges are not present.
|
||||
@@ -126,6 +138,14 @@ func MakeReport() Report {
|
||||
WithShape(Heptagon).
|
||||
WithLabel("service", "services"),
|
||||
|
||||
Deployment: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithLabel("deployment", "deployments"),
|
||||
|
||||
ReplicaSet: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithLabel("replica set", "replica sets"),
|
||||
|
||||
Overlay: MakeTopology(),
|
||||
|
||||
Sampling: Sampling{},
|
||||
@@ -145,6 +165,8 @@ func (r Report) Copy() Report {
|
||||
Host: r.Host.Copy(),
|
||||
Pod: r.Pod.Copy(),
|
||||
Service: r.Service.Copy(),
|
||||
Deployment: r.Deployment.Copy(),
|
||||
ReplicaSet: r.ReplicaSet.Copy(),
|
||||
Overlay: r.Overlay.Copy(),
|
||||
Sampling: r.Sampling,
|
||||
Window: r.Window,
|
||||
@@ -164,6 +186,8 @@ func (r Report) Merge(other Report) Report {
|
||||
cp.Host = r.Host.Merge(other.Host)
|
||||
cp.Pod = r.Pod.Merge(other.Pod)
|
||||
cp.Service = r.Service.Merge(other.Service)
|
||||
cp.Deployment = r.Deployment.Merge(other.Deployment)
|
||||
cp.ReplicaSet = r.ReplicaSet.Merge(other.ReplicaSet)
|
||||
cp.Overlay = r.Overlay.Merge(other.Overlay)
|
||||
cp.Sampling = r.Sampling.Merge(other.Sampling)
|
||||
cp.Window += other.Window
|
||||
@@ -180,6 +204,8 @@ func (r Report) Topologies() []Topology {
|
||||
r.ContainerImage,
|
||||
r.Pod,
|
||||
r.Service,
|
||||
r.Deployment,
|
||||
r.ReplicaSet,
|
||||
r.Host,
|
||||
r.Overlay,
|
||||
}
|
||||
@@ -194,6 +220,8 @@ func (r Report) Topology(name string) (Topology, bool) {
|
||||
ContainerImage: r.ContainerImage,
|
||||
Pod: r.Pod,
|
||||
Service: r.Service,
|
||||
Deployment: r.Deployment,
|
||||
ReplicaSet: r.ReplicaSet,
|
||||
Host: r.Host,
|
||||
Overlay: r.Overlay,
|
||||
}[name]
|
||||
|
||||
@@ -96,8 +96,10 @@ var (
|
||||
ServerPodUID = "i9h8g7f6e"
|
||||
ClientPodNodeID = report.MakePodNodeID(ClientPodUID)
|
||||
ServerPodNodeID = report.MakePodNodeID(ServerPodUID)
|
||||
ServiceName = "pongservice"
|
||||
ServiceID = "ping/pongservice"
|
||||
ServiceNodeID = report.MakeServiceNodeID(KubernetesNamespace, "pongservice")
|
||||
ServiceUID = "service1234"
|
||||
ServiceNodeID = report.MakeServiceNodeID(ServiceUID)
|
||||
|
||||
ClientProcess1CPUMetric = report.MakeMetric().Add(Now, 0.01).WithFirst(Now.Add(-1 * time.Second))
|
||||
ClientProcess1MemoryMetric = report.MakeMetric().Add(Now, 0.02).WithFirst(Now.Add(-2 * time.Second))
|
||||
@@ -367,30 +369,26 @@ var (
|
||||
Nodes: report.Nodes{
|
||||
ClientPodNodeID: report.MakeNodeWith(
|
||||
ClientPodNodeID, map[string]string{
|
||||
kubernetes.PodID: ClientPodID,
|
||||
kubernetes.PodName: "pong-a",
|
||||
kubernetes.ID: ClientPodID,
|
||||
kubernetes.Name: "pong-a",
|
||||
kubernetes.Namespace: KubernetesNamespace,
|
||||
report.HostNodeID: ClientHostNodeID,
|
||||
}).
|
||||
WithSets(report.EmptySets.
|
||||
Add(kubernetes.ServiceIDs, report.MakeStringSet(ServiceID))).
|
||||
WithTopology(report.Pod).WithParents(report.EmptySets.
|
||||
Add("host", report.MakeStringSet(ClientHostNodeID)).
|
||||
Add("service", report.MakeStringSet(ServiceID)),
|
||||
Add("service", report.MakeStringSet(ServiceNodeID)),
|
||||
),
|
||||
ServerPodNodeID: report.MakeNodeWith(
|
||||
ServerPodNodeID, map[string]string{
|
||||
kubernetes.PodID: ServerPodID,
|
||||
kubernetes.PodName: "pong-b",
|
||||
kubernetes.ID: ServerPodID,
|
||||
kubernetes.Name: "pong-b",
|
||||
kubernetes.Namespace: KubernetesNamespace,
|
||||
kubernetes.PodState: "running",
|
||||
kubernetes.State: "running",
|
||||
report.HostNodeID: ServerHostNodeID,
|
||||
}).
|
||||
WithSets(report.EmptySets.
|
||||
Add(kubernetes.ServiceIDs, report.MakeStringSet(ServiceID))).
|
||||
WithTopology(report.Pod).WithParents(report.EmptySets.
|
||||
Add("host", report.MakeStringSet(ServerHostNodeID)).
|
||||
Add("service", report.MakeStringSet(ServiceID)),
|
||||
Add("service", report.MakeStringSet(ServiceNodeID)),
|
||||
),
|
||||
},
|
||||
MetadataTemplates: kubernetes.PodMetadataTemplates,
|
||||
@@ -400,9 +398,9 @@ var (
|
||||
ServiceNodeID: report.MakeNodeWith(
|
||||
|
||||
ServiceNodeID, map[string]string{
|
||||
kubernetes.ServiceID: ServiceID,
|
||||
kubernetes.ServiceName: "pongservice",
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.ID: ServiceID,
|
||||
kubernetes.Name: "pongservice",
|
||||
kubernetes.Namespace: "ping",
|
||||
}).
|
||||
WithTopology(report.Service),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user