// MapContainer2Pod maps container Nodes to pod // Nodes. // // If this function is given a node without a kubernetes_pod_id // (including other pseudo nodes), it will produce an "Unmanaged" // 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 container graph to get that info. func MapContainer2Pod(n report.Node, _ report.Networks) report.Nodes { // Uncontained becomes unmanaged in the pods view if strings.HasPrefix(n.ID, MakePseudoNodeID(UncontainedID)) { id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n)) node := NewDerivedPseudoNode(id, n) return report.Nodes{id: node} } // Propagate all pseudo nodes if n.Topology == Pseudo { return report.Nodes{n.ID: n} } // Ignore non-running containers if state, ok := n.Latest.Lookup(docker.ContainerState); ok && state != docker.StateRunning { return report.Nodes{} } // 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} } id := report.MakePodNodeID(uid) node := NewDerivedNode(id, n). WithTopology(report.Pod) node.Counters = node.Counters.Add(n.Topology, 1) return report.Nodes{id: node} }
func (p *pod) GetNode(probeID string) report.Node { return p.MetaNode(report.MakePodNodeID(p.UID())).WithLatests(map[string]string{ State: p.State(), IP: p.Status.PodIP, report.ControlProbeID: probeID, }). WithParents(p.parents). WithControls(GetLogs, DeletePod) }
func TestTagger(t *testing.T) { rpt := report.MakeReport() rpt.Container.AddNode(report.MakeNodeWith("container1", map[string]string{ docker.LabelPrefix + "io.kubernetes.pod.uid": "123456", })) rpt, err := kubernetes.NewReporter(newMockClient(), nil, "", "", nil).Tag(rpt) if err != nil { t.Errorf("Unexpected error: %v", err) } have, ok := rpt.Container.Nodes["container1"].Parents.Lookup(report.Pod) want := report.EmptyStringSet.Add(report.MakePodNodeID("123456")) if !ok || !reflect.DeepEqual(have, want) { t.Errorf("Expected container to have pod parent %v %v", have, want) } }
// Tag adds pod parents to container nodes. func (r *Reporter) Tag(rpt report.Report) (report.Report, error) { for id, n := range rpt.Container.Nodes { uid, ok := n.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.uid") if !ok { continue } // Tag the pause containers with "does-not-make-connections" if isPauseContainer(n, rpt) { n = n.WithLatest(report.DoesNotMakeConnections, mtime.Now(), "") } rpt.Container.Nodes[id] = n.WithParents(report.EmptySets.Add( report.Pod, report.EmptyStringSet.Add(report.MakePodNodeID(uid)), )) } return rpt, nil }
func (r *Reporter) podEvent(e Event, pod Pod) { switch e { case ADD: rpt := report.MakeReport() rpt.Shortcut = true rpt.Pod.AddNode(pod.GetNode(r.probeID)) r.probe.Publish(rpt) case DELETE: rpt := report.MakeReport() rpt.Shortcut = true rpt.Pod.AddNode( report.MakeNodeWith( report.MakePodNodeID(pod.UID()), map[string]string{State: StateDeleted}, ), ) r.probe.Publish(rpt) } }
ClientContainerHostname = ClientContainerName + ".hostname.com" ServerContainerHostname = ServerContainerName + ".hostname.com" ClientContainerImageID = "imageid123" ServerContainerImageID = "imageid456" ClientContainerImageNodeID = report.MakeContainerImageNodeID(ClientContainerImageID) ServerContainerImageNodeID = report.MakeContainerImageNodeID(ServerContainerImageID) ClientContainerImageName = "image/client" ServerContainerImageName = "image/server" KubernetesNamespace = "ping" ClientPodID = "ping/pong-a" ServerPodID = "ping/pong-b" ClientPodUID = "5d4c3b2a1" ServerPodUID = "i9h8g7f6e" ClientPodNodeID = report.MakePodNodeID(ClientPodUID) ServerPodNodeID = report.MakePodNodeID(ServerPodUID) ServiceName = "pongservice" ServiceID = "ping/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)) ClientContainerCPUMetric = report.MakeMetric().Add(Now, 0.03).WithFirst(Now.Add(-3 * time.Second)) ClientContainerMemoryMetric = report.MakeMetric().Add(Now, 0.04).WithFirst(Now.Add(-4 * time.Second)) ServerContainerCPUMetric = report.MakeMetric().Add(Now, 0.05).WithFirst(Now.Add(-5 * time.Second)) ServerContainerMemoryMetric = report.MakeMetric().Add(Now, 0.06).WithFirst(Now.Add(-6 * time.Second))
func TestReporterGetLogs(t *testing.T) { oldGetNodeName := kubernetes.GetNodeName defer func() { kubernetes.GetNodeName = oldGetNodeName }() kubernetes.GetNodeName = func(*kubernetes.Reporter) (string, error) { return nodeName, nil } client := newMockClient() pipes := mockPipeClient{} reporter := kubernetes.NewReporter(client, pipes, "", "", nil) // Should error on invalid IDs { resp := reporter.CapturePod(reporter.GetLogs)(xfer.Request{ NodeID: "invalidID", Control: kubernetes.GetLogs, }) if want := "Invalid ID: invalidID"; resp.Error != want { t.Errorf("Expected error on invalid ID: %q, got %q", want, resp.Error) } } // Should pass through errors from k8s (e.g if pod does not exist) { resp := reporter.CapturePod(reporter.GetLogs)(xfer.Request{ AppID: "appID", NodeID: report.MakePodNodeID("notfound"), Control: kubernetes.GetLogs, }) if want := "Pod not found: notfound"; resp.Error != want { t.Errorf("Expected error on invalid ID: %q, got %q", want, resp.Error) } } podNamespaceAndID := "ping;pong-a" pod1Request := xfer.Request{ AppID: "appID", NodeID: report.MakePodNodeID(pod1UID), Control: kubernetes.GetLogs, } // Inject our logs content, and watch for it to be closed closed := false wantContents := "logs: ping/pong-a" client.logs[podNamespaceAndID] = &callbackReadCloser{Reader: strings.NewReader(wantContents), close: func() error { closed = true return nil }} // Should create a new pipe for the stream resp := reporter.CapturePod(reporter.GetLogs)(pod1Request) if resp.Pipe == "" { t.Errorf("Expected pipe id to be returned, but got %#v", resp) } pipe, ok := pipes[resp.Pipe] if !ok { t.Fatalf("Expected pipe %q to have been created, but wasn't", resp.Pipe) } // Should push logs from k8s client into the pipe _, readWriter := pipe.Ends() contents, err := ioutil.ReadAll(readWriter) if err != nil { t.Error(err) } if string(contents) != wantContents { t.Errorf("Expected pipe to contain %q, but got %q", wantContents, string(contents)) } // Should close the stream when the pipe closes if err := pipe.Close(); err != nil { t.Error(err) } if !closed { t.Errorf("Expected pipe to close the underlying log stream") } }
func TestReporter(t *testing.T) { oldGetNodeName := kubernetes.GetNodeName defer func() { kubernetes.GetNodeName = oldGetNodeName }() kubernetes.GetNodeName = func(*kubernetes.Reporter) (string, error) { return nodeName, nil } pod1ID := report.MakePodNodeID(pod1UID) pod2ID := report.MakePodNodeID(pod2UID) serviceID := report.MakeServiceNodeID(serviceUID) rpt, _ := kubernetes.NewReporter(newMockClient(), nil, "", "foo", nil).Report() // Reporter should have added the following pods for _, pod := range []struct { id string parentService string latest map[string]string }{ {pod1ID, serviceID, map[string]string{ kubernetes.ID: "ping/pong-a", kubernetes.Name: "pong-a", kubernetes.Namespace: "ping", kubernetes.Created: pod1.Created(), }}, {pod2ID, serviceID, map[string]string{ kubernetes.ID: "ping/pong-b", kubernetes.Name: "pong-b", kubernetes.Namespace: "ping", kubernetes.Created: pod1.Created(), }}, } { node, ok := rpt.Pod.Nodes[pod.id] if !ok { t.Errorf("Expected report to have pod %q, but not found", pod.id) } if parents, ok := node.Parents.Lookup(report.Service); !ok || !parents.Contains(pod.parentService) { t.Errorf("Expected pod %s to have parent service %q, got %q", pod.id, pod.parentService, parents) } for k, want := range pod.latest { if have, ok := node.Latest.Lookup(k); !ok || have != want { t.Errorf("Expected pod %s latest %q: %q, got %q", pod.id, k, want, have) } } } // Reporter should have added a service { node, ok := rpt.Service.Nodes[serviceID] if !ok { t.Errorf("Expected report to have service %q, but not found", serviceID) } for k, want := range map[string]string{ 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) } } } }