mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-18 04:49:55 +00:00
Index services by UID, and refactor out common k8s metadata handling
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
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
|
||||
@@ -24,26 +20,22 @@ const (
|
||||
|
||||
// Pod represents a Kubernetes pod
|
||||
type Pod interface {
|
||||
UID() string
|
||||
ID() string
|
||||
Name() string
|
||||
Namespace() string
|
||||
Created() string
|
||||
Meta
|
||||
AddServiceID(id string)
|
||||
Labels() labels.Labels
|
||||
NodeName() string
|
||||
GetNode(probeID string) report.Node
|
||||
}
|
||||
|
||||
type pod struct {
|
||||
*api.Pod
|
||||
Meta
|
||||
serviceIDs report.StringSet
|
||||
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}, serviceIDs: report.MakeStringSet()}
|
||||
}
|
||||
|
||||
func (p *pod) UID() string {
|
||||
@@ -51,27 +43,7 @@ func (p *pod) UID() string {
|
||||
if hash, ok := p.ObjectMeta.Annotations["kubernetes.io/config.hash"]; ok {
|
||||
return hash
|
||||
}
|
||||
return string(p.ObjectMeta.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)
|
||||
return p.Meta.UID()
|
||||
}
|
||||
|
||||
func (p *pod) AddServiceID(id string) {
|
||||
@@ -97,12 +69,8 @@ func (p *pod) GetNode(probeID string) report.Node {
|
||||
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]))),
|
||||
Add(report.Service, report.MakeStringSet(report.MakeServiceNodeID(serviceID))),
|
||||
)
|
||||
}
|
||||
n = n.AddTable(PodLabelPrefix, p.ObjectMeta.Labels)
|
||||
|
||||
@@ -192,7 +192,14 @@ func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
|
||||
pods = report.MakeTopology().
|
||||
WithMetadataTemplates(PodMetadataTemplates).
|
||||
WithTableTemplates(PodTableTemplates)
|
||||
selectors = map[string]labels.Selector{}
|
||||
selectors = []func(Pod){}
|
||||
match = func(selector labels.Selector, f func(Pod, string), id string) func(Pod) {
|
||||
return func(p Pod) {
|
||||
if selector.Matches(p.Labels()) {
|
||||
f(p, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
pods.Controls.AddControl(report.Control{
|
||||
ID: GetLogs,
|
||||
@@ -207,7 +214,7 @@ 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(), Pod.AddServiceID, service.UID()))
|
||||
}
|
||||
|
||||
thisNodeName, err := GetNodeName(r)
|
||||
@@ -218,10 +225,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(),
|
||||
},
|
||||
@@ -166,7 +168,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
|
||||
@@ -182,7 +184,7 @@ func TestReporter(t *testing.T) {
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.PodCreated: pod1.Created(),
|
||||
}, map[string]report.StringSet{
|
||||
kubernetes.ServiceIDs: report.MakeStringSet("ping/pongservice"),
|
||||
kubernetes.ServiceIDs: report.MakeStringSet(serviceUID),
|
||||
}},
|
||||
{pod2ID, serviceID, map[string]string{
|
||||
kubernetes.PodID: "ping/pong-b",
|
||||
@@ -190,7 +192,7 @@ func TestReporter(t *testing.T) {
|
||||
kubernetes.Namespace: "ping",
|
||||
kubernetes.PodCreated: pod1.Created(),
|
||||
}, map[string]report.StringSet{
|
||||
kubernetes.ServiceIDs: report.MakeStringSet("ping/pongservice"),
|
||||
kubernetes.ServiceIDs: report.MakeStringSet(serviceUID),
|
||||
}},
|
||||
} {
|
||||
node, ok := rpt.Pod.Nodes[pod.id]
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
@@ -20,37 +18,19 @@ const (
|
||||
|
||||
// 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 {
|
||||
@@ -64,7 +44,7 @@ func (s *service) GetNode() report.Node {
|
||||
latest := map[string]string{
|
||||
ServiceID: s.ID(),
|
||||
ServiceName: s.Name(),
|
||||
ServiceCreated: s.ObjectMeta.CreationTimestamp.Format(time.RFC822),
|
||||
ServiceCreated: s.Created(),
|
||||
Namespace: s.Namespace(),
|
||||
ServiceIP: s.Spec.ClusterIP,
|
||||
}
|
||||
@@ -72,8 +52,8 @@ func (s *service) GetNode() report.Node {
|
||||
latest[ServicePublicIP] = s.Spec.LoadBalancerIP
|
||||
}
|
||||
return report.MakeNodeWith(
|
||||
report.MakeServiceNodeID(s.Namespace(), s.Name()),
|
||||
report.MakeServiceNodeID(s.UID()),
|
||||
latest,
|
||||
).
|
||||
AddTable(ServiceLabelPrefix, s.Labels)
|
||||
AddTable(ServiceLabelPrefix, s.ObjectMeta.Labels)
|
||||
}
|
||||
|
||||
@@ -95,40 +95,34 @@ 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 (
|
||||
MapPod2Service = MapPod2Grouping(report.Service, kubernetes.ServiceIDs, report.MakeServiceNodeID)
|
||||
)
|
||||
|
||||
// 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{}
|
||||
}
|
||||
// MapPod2Grouping maps pod Nodes to some kubernetes grouping.
|
||||
func MapPod2Grouping(topology, setKey string, idMaker func(uid string) string) func(pod report.Node, _ report.Networks) report.Nodes {
|
||||
return func(pod report.Node, _ report.Networks) report.Nodes {
|
||||
// Propagate all pseudo nodes
|
||||
if pod.Topology == Pseudo {
|
||||
return report.Nodes{pod.ID: pod}
|
||||
}
|
||||
|
||||
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 pod doesn't have any of these ids
|
||||
// (maybe slightly out of sync reports, or its not in this group), just
|
||||
// drop it
|
||||
groupIDs, ok := pod.Sets.Lookup(setKey)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
result := report.Nodes{}
|
||||
for _, groupID := range groupIDs {
|
||||
id := idMaker(groupID)
|
||||
node := NewDerivedNode(id, pod).WithTopology(topology)
|
||||
node.Counters = node.Counters.Add(pod.Topology, 1)
|
||||
result[id] = node
|
||||
}
|
||||
return result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
40
report/id.go
40
report/id.go
@@ -96,32 +96,28 @@ 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")
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
@@ -97,7 +97,8 @@ var (
|
||||
ClientPodNodeID = report.MakePodNodeID(ClientPodUID)
|
||||
ServerPodNodeID = report.MakePodNodeID(ServerPodUID)
|
||||
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))
|
||||
@@ -373,7 +374,7 @@ var (
|
||||
report.HostNodeID: ClientHostNodeID,
|
||||
}).
|
||||
WithSets(report.EmptySets.
|
||||
Add(kubernetes.ServiceIDs, report.MakeStringSet(ServiceID))).
|
||||
Add(kubernetes.ServiceIDs, report.MakeStringSet(ServiceUID))).
|
||||
WithTopology(report.Pod).WithParents(report.EmptySets.
|
||||
Add("host", report.MakeStringSet(ClientHostNodeID)).
|
||||
Add("service", report.MakeStringSet(ServiceID)),
|
||||
@@ -387,7 +388,7 @@ var (
|
||||
report.HostNodeID: ServerHostNodeID,
|
||||
}).
|
||||
WithSets(report.EmptySets.
|
||||
Add(kubernetes.ServiceIDs, report.MakeStringSet(ServiceID))).
|
||||
Add(kubernetes.ServiceIDs, report.MakeStringSet(ServiceUID))).
|
||||
WithTopology(report.Pod).WithParents(report.EmptySets.
|
||||
Add("host", report.MakeStringSet(ServerHostNodeID)).
|
||||
Add("service", report.MakeStringSet(ServiceID)),
|
||||
|
||||
Reference in New Issue
Block a user