Skip to content

Commit

Permalink
Index Pods by UID and join with containers based on this.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomwilkie committed Apr 29, 2016
1 parent eba1cce commit ac45e9d
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 72 deletions.
14 changes: 7 additions & 7 deletions probe/kubernetes/controls.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ const (
)

// GetLogs is the control to get the logs for a kubernetes pod
func (r *Reporter) GetLogs(req xfer.Request, namespaceID, podID string) xfer.Response {
readCloser, err := r.client.GetLogs(namespaceID, podID)
func (r *Reporter) GetLogs(req xfer.Request, uid string) xfer.Response {
readCloser, err := r.client.GetLogs(uid, uid)
if err != nil {
return xfer.ResponseError(err)
}
Expand All @@ -41,8 +41,8 @@ func (r *Reporter) GetLogs(req xfer.Request, namespaceID, podID string) xfer.Res
}
}

func (r *Reporter) deletePod(req xfer.Request, namespaceID, podID string) xfer.Response {
if err := r.client.DeletePod(namespaceID, podID); err != nil {
func (r *Reporter) deletePod(req xfer.Request, uid string) xfer.Response {
if err := r.client.DeletePod(uid, uid); err != nil {
return xfer.ResponseError(err)
}
return xfer.Response{
Expand All @@ -51,13 +51,13 @@ func (r *Reporter) deletePod(req xfer.Request, namespaceID, podID string) xfer.R
}

// CapturePod is exported for testing
func CapturePod(f func(xfer.Request, string, string) xfer.Response) func(xfer.Request) xfer.Response {
func CapturePod(f func(xfer.Request, string) xfer.Response) func(xfer.Request) xfer.Response {
return func(req xfer.Request) xfer.Response {
namespaceID, podID, ok := report.ParsePodNodeID(req.NodeID)
uid, ok := report.ParsePodNodeID(req.NodeID)
if !ok {
return xfer.ResponseErrorf("Invalid ID: %s", req.NodeID)
}
return f(req, namespaceID, podID)
return f(req, uid)
}
}

Expand Down
34 changes: 16 additions & 18 deletions probe/kubernetes/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,22 @@ import (

// These constants are keys used in node metadata
const (
PodID = "kubernetes_pod_id"
PodName = "kubernetes_pod_name"
PodCreated = "kubernetes_pod_created"
PodContainerIDs = "kubernetes_pod_container_ids"
PodState = "kubernetes_pod_state"
PodLabelPrefix = "kubernetes_pod_labels_"
ServiceIDs = "kubernetes_service_ids"
PodID = "kubernetes_pod_id"
PodName = "kubernetes_pod_name"
PodCreated = "kubernetes_pod_created"
PodState = "kubernetes_pod_state"
PodLabelPrefix = "kubernetes_pod_labels_"
ServiceIDs = "kubernetes_service_ids"

StateDeleted = "deleted"
)

// Pod represents a Kubernetes pod
type Pod interface {
UID() string
ID() string
Name() string
Namespace() string
ContainerIDs() []string
Created() string
AddServiceID(id string)
Labels() labels.Labels
Expand All @@ -46,6 +45,14 @@ func NewPod(p *api.Pod) Pod {
return &pod{Pod: p}
}

func (p *pod) UID() string {
// Work around for master pod not reporting the right UID.
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
}
Expand All @@ -62,14 +69,6 @@ func (p *pod) Created() string {
return p.ObjectMeta.CreationTimestamp.Format(time.RFC822)
}

func (p *pod) ContainerIDs() []string {
ids := []string{}
for _, container := range p.Status.ContainerStatuses {
ids = append(ids, strings.TrimPrefix(container.ContainerID, "docker://"))
}
return ids
}

func (p *pod) Labels() labels.Labels {
return labels.Set(p.ObjectMeta.Labels)
}
Expand All @@ -87,12 +86,11 @@ func (p *pod) NodeName() string {
}

func (p *pod) GetNode(probeID string) report.Node {
n := report.MakeNodeWith(report.MakePodNodeID(p.Namespace(), p.Name()), map[string]string{
n := report.MakeNodeWith(report.MakePodNodeID(p.UID()), map[string]string{
PodID: p.ID(),
PodName: p.Name(),
Namespace: p.Namespace(),
PodCreated: p.Created(),
PodContainerIDs: strings.Join(p.ContainerIDs(), " "),
PodState: p.State(),
report.ControlProbeID: probeID,
})
Expand Down
25 changes: 6 additions & 19 deletions probe/kubernetes/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

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

Expand Down Expand Up @@ -81,7 +80,7 @@ func (r *Reporter) podEvent(e Event, pod Pod) {
rpt.Shortcut = true
rpt.Pod.AddNode(
report.MakeNodeWith(
report.MakePodNodeID(pod.Namespace(), pod.Name()),
report.MakePodNodeID(pod.UID()),
map[string]string{PodState: StateDeleted},
),
)
Expand All @@ -96,13 +95,12 @@ func (r *Reporter) Report() (report.Report, error) {
if err != nil {
return result, err
}
podTopology, containerTopology, err := r.podTopology(services)
podTopology, err := r.podTopology(services)
if err != nil {
return result, err
}
result.Service = result.Service.Merge(serviceTopology)
result.Pod = result.Pod.Merge(podTopology)
result.Container = result.Container.Merge(containerTopology)
return result, nil
}

Expand Down Expand Up @@ -142,13 +140,12 @@ var GetNodeName = func(r *Reporter) (string, error) {
return nodeName, err
}

func (r *Reporter) podTopology(services []Service) (report.Topology, report.Topology, error) {
func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
var (
pods = report.MakeTopology().
WithMetadataTemplates(PodMetadataTemplates).
WithTableTemplates(PodTableTemplates)
containers = report.MakeTopology()
selectors = map[string]labels.Selector{}
selectors = map[string]labels.Selector{}
)
pods.Controls.AddControl(report.Control{
ID: GetLogs,
Expand All @@ -168,7 +165,7 @@ func (r *Reporter) podTopology(services []Service) (report.Topology, report.Topo

thisNodeName, err := GetNodeName(r)
if err != nil {
return pods, containers, err
return pods, err
}
err = r.client.WalkPods(func(p Pod) error {
if p.NodeName() != thisNodeName {
Expand All @@ -179,18 +176,8 @@ func (r *Reporter) podTopology(services []Service) (report.Topology, report.Topo
p.AddServiceID(serviceID)
}
}
nodeID := report.MakePodNodeID(p.Namespace(), p.Name())
pods = pods.AddNode(p.GetNode(r.probeID))

for _, containerID := range p.ContainerIDs() {
container := report.MakeNodeWith(report.MakeContainerNodeID(containerID), map[string]string{
PodID: p.ID(),
Namespace: p.Namespace(),
docker.ContainerID: containerID,
}).WithParents(report.EmptySets.Add(report.Pod, report.MakeStringSet(nodeID)))
containers.AddNode(container)
}
return nil
})
return pods, containers, err
return pods, err
}
5 changes: 5 additions & 0 deletions probe/kubernetes/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (

// Service represents a Kubernetes service
type Service interface {
UID() string
ID() string
Name() string
Namespace() string
Expand All @@ -36,6 +37,10 @@ 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
}
Expand Down
36 changes: 14 additions & 22 deletions render/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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 @@ -61,7 +62,7 @@ var PodServiceRenderer = FilterEmpty(report.Pod,
// It does not have enough info to do that, and the resulting graph
// must be merged with a container graph to get that info.
func MapContainer2Pod(n report.Node, _ report.Networks) report.Nodes {
// Uncontainerd becomes unmanaged in the pods view
// Uncontained becomes unmanaged in the pods view
if strings.HasPrefix(n.ID, MakePseudoNodeID(UncontainedID)) {
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
node := NewDerivedPseudoNode(id, n)
Expand All @@ -73,34 +74,25 @@ func MapContainer2Pod(n report.Node, _ report.Networks) report.Nodes {
return report.Nodes{n.ID: n}
}

// Otherwise, if some some reason the container doesn't have a pod_id (maybe
// slightly out of sync reports, or its not in a pod), just drop it
namespace, ok := n.Latest.Lookup(kubernetes.Namespace)
if !ok {
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
node := NewDerivedPseudoNode(id, n)
return report.Nodes{id: node}
// Ignore non-running containers
if state, ok := n.Latest.Lookup(docker.ContainerState); ok && state != docker.StateRunning {
return report.Nodes{}
}
podID, ok := n.Latest.Lookup(kubernetes.PodID)

// Otherwise, if some some reason the container doesn't have a pod uid (maybe
// slightly out of sync reports, or its not in a pod), make it part of unmanaged.
uid, ok := n.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.uid")
if !ok {
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
node := NewDerivedPseudoNode(id, n)
return report.Nodes{id: node}
}
podName := strings.TrimPrefix(podID, namespace+"/")
id := report.MakePodNodeID(namespace, podName)

// Due to a bug in kubernetes, addon pods on the master node are not returned
// from the API. Adding the namespace and pod name is a workaround until
// https://github.com/kubernetes/kubernetes/issues/14738 is fixed.
return report.Nodes{
id: NewDerivedNode(id, n).
WithTopology(report.Pod).
WithLatests(map[string]string{
kubernetes.Namespace: namespace,
kubernetes.PodName: podName,
}),
}
id := report.MakePodNodeID(uid)
node := NewDerivedNode(id, n).
WithTopology(report.Pod)
node.Counters = node.Counters.Add(n.Topology, 1)
return report.Nodes{id: node}
}

// MapPod2Service maps pod Nodes to service Nodes.
Expand Down
12 changes: 6 additions & 6 deletions report/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ func MakeContainerImageNodeID(containerImageID string) string {
}

// MakePodNodeID produces a pod node ID from its composite parts.
func MakePodNodeID(namespaceID, podID string) string {
return namespaceID + ScopeDelim + podID
func MakePodNodeID(uid string) string {
return uid + ScopeDelim + "<pod>"
}

// MakeServiceNodeID produces a service node ID from its composite parts.
Expand Down Expand Up @@ -167,12 +167,12 @@ func ParseAddressNodeID(addressNodeID string) (hostID, address string, ok bool)
}

// ParsePodNodeID produces the namespace ID and pod ID from an pod node ID.
func ParsePodNodeID(podNodeID string) (namespaceID, podID string, ok bool) {
func ParsePodNodeID(podNodeID string) (uid string, ok bool) {
fields := strings.SplitN(podNodeID, ScopeDelim, 2)
if len(fields) != 2 {
return "", "", false
if len(fields) != 2 || fields[1] != "<pod>" {
return "", false
}
return fields[0], fields[1], true
return fields[0], true
}

// ExtractHostID extracts the host id from Node
Expand Down

0 comments on commit ac45e9d

Please sign in to comment.