diff --git a/app/api_topologies.go b/app/api_topologies.go index 0d4a61fdd2..ee02ad3ebd 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -1,13 +1,16 @@ package app import ( + "fmt" "net/http" + "net/url" "sort" "sync" "github.com/gorilla/mux" "golang.org/x/net/context" + "github.com/weaveworks/scope/probe/kubernetes" "github.com/weaveworks/scope/render" "github.com/weaveworks/scope/report" ) @@ -21,30 +24,6 @@ var ( ) func init() { - serviceFilters := []APITopologyOptionGroup{ - { - ID: "system", - Default: "application", - Options: []APITopologyOption{ - {"system", "System services", render.IsSystem}, - {"application", "Application services", render.IsApplication}, - {"both", "Both", render.Noop}, - }, - }, - } - - podFilters := []APITopologyOptionGroup{ - { - ID: "system", - Default: "application", - Options: []APITopologyOption{ - {"system", "System pods", render.IsSystem}, - {"application", "Application pods", render.IsApplication}, - {"both", "Both", render.Noop}, - }, - }, - } - containerFilters := []APITopologyOptionGroup{ { ID: "system", @@ -52,7 +31,7 @@ func init() { Options: []APITopologyOption{ {"system", "System containers", render.IsSystem}, {"application", "Application containers", render.IsApplication}, - {"both", "Both", render.Noop}, + {"both", "Both", nil}, }, }, { @@ -61,7 +40,7 @@ func init() { Options: []APITopologyOption{ {"stopped", "Stopped containers", render.IsStopped}, {"running", "Running containers", render.IsRunning}, - {"both", "Both", render.Noop}, + {"both", "Both", nil}, }, }, } @@ -116,19 +95,12 @@ func init() { Name: "by DNS name", Options: containerFilters, }, - APITopologyDesc{ - id: "hosts", - renderer: render.HostRenderer, - Name: "Hosts", - Rank: 4, - }, APITopologyDesc{ id: "pods", renderer: render.PodRenderer, Name: "Pods", Rank: 3, HideIfEmpty: true, - Options: podFilters, }, APITopologyDesc{ id: "pods-by-service", @@ -136,11 +108,63 @@ func init() { renderer: render.PodServiceRenderer, Name: "by service", HideIfEmpty: true, - Options: serviceFilters, + }, + APITopologyDesc{ + id: "hosts", + renderer: render.HostRenderer, + Name: "Hosts", + Rank: 4, }, ) } +// kubernetesFilters generates the current kubernetes filters based on the +// available k8s topologies. +func kubernetesFilters(namespaces ...string) APITopologyOptionGroup { + options := APITopologyOptionGroup{ID: "namespace", Default: "all"} + for _, namespace := range namespaces { + options.Options = append(options.Options, APITopologyOption{namespace, namespace, render.IsNamespace(namespace)}) + } + options.Options = append(options.Options, APITopologyOption{"all", "All Namespaces", nil}) + return options +} + +// updateFilters updates the available filters based on the current report. +// 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 _, n := range t.Nodes { + if state, ok := n.Latest.Lookup(kubernetes.PodState); ok && state == kubernetes.StateDeleted { + continue + } + if namespace, ok := n.Latest.Lookup(kubernetes.Namespace); ok { + namespaces[namespace] = struct{}{} + } + } + } + var ns []string + for namespace := range namespaces { + ns = append(ns, namespace) + } + sort.Strings(ns) + for i, t := range topologies { + if t.id == "pods" || t.id == "pods-by-service" { + topologies[i] = updateTopologyFilters(t, []APITopologyOptionGroup{kubernetesFilters(ns...)}) + } + } + return topologies +} + +// updateTopologyFilters recursively sets the options on a topology description +func updateTopologyFilters(t APITopologyDesc, options []APITopologyOptionGroup) APITopologyDesc { + t.Options = options + for i, sub := range t.SubTopologies { + t.SubTopologies[i] = updateTopologyFilters(sub, options) + } + return t +} + // registry is a threadsafe store of the available topologies type registry struct { sync.RWMutex @@ -239,23 +263,23 @@ func (r *registry) makeTopologyList(rep Reporter) CtxHandlerFunc { respondWith(w, http.StatusInternalServerError, err.Error()) return } - topologies := r.renderTopologies(report, req) - respondWith(w, http.StatusOK, topologies) + respondWith(w, http.StatusOK, r.renderTopologies(report, req)) } } func (r *registry) renderTopologies(rpt report.Report, req *http.Request) []APITopologyDesc { topologies := []APITopologyDesc{} + req.ParseForm() r.walk(func(desc APITopologyDesc) { - renderer, decorator := renderedForRequest(req, desc) + renderer, decorator, _ := r.rendererForTopology(desc.id, req.Form, rpt) desc.Stats = decorateWithStats(rpt, renderer, decorator) - for i := range desc.SubTopologies { - renderer, decorator := renderedForRequest(req, desc.SubTopologies[i]) + for i, sub := range desc.SubTopologies { + renderer, decorator, _ := r.rendererForTopology(sub.id, req.Form, rpt) desc.SubTopologies[i].Stats = decorateWithStats(rpt, renderer, decorator) } topologies = append(topologies, desc) }) - return topologies + return updateFilters(rpt, topologies) } func decorateWithStats(rpt report.Report, renderer render.Renderer, decorator render.Decorator) topologyStats { @@ -280,10 +304,16 @@ func decorateWithStats(rpt report.Report, renderer render.Renderer, decorator re } } -func renderedForRequest(r *http.Request, topology APITopologyDesc) (render.Renderer, render.Decorator) { +func (r *registry) rendererForTopology(topologyID string, values url.Values, rpt report.Report) (render.Renderer, render.Decorator, error) { + topology, ok := r.get(topologyID) + if !ok { + return nil, nil, fmt.Errorf("topology not found: %s", topologyID) + } + topology = updateFilters(rpt, []APITopologyDesc{topology})[0] + var filters []render.FilterFunc for _, group := range topology.Options { - value := r.FormValue(group.ID) + value := values.Get(group.ID) for _, opt := range group.Options { if opt.filter == nil { continue @@ -299,23 +329,37 @@ func renderedForRequest(r *http.Request, topology APITopologyDesc) (render.Rende return render.MakeFilter(render.ComposeFilterFuncs(filters...), renderer) } } - return topology.renderer, decorator + return topology.renderer, decorator, nil } -type reportRenderHandler func( - context.Context, - Reporter, render.Renderer, render.Decorator, - http.ResponseWriter, *http.Request, -) +type reporterHandler func(context.Context, Reporter, http.ResponseWriter, *http.Request) + +func captureReporter(rep Reporter, f reporterHandler) CtxHandlerFunc { + return func(ctx context.Context, w http.ResponseWriter, r *http.Request) { + f(ctx, rep, w, r) + } +} -func (r *registry) captureRenderer(rep Reporter, f reportRenderHandler) CtxHandlerFunc { +type rendererHandler func(context.Context, render.Renderer, render.Decorator, report.Report, http.ResponseWriter, *http.Request) + +func (r *registry) captureRenderer(rep Reporter, f rendererHandler) CtxHandlerFunc { return func(ctx context.Context, w http.ResponseWriter, req *http.Request) { - topology, ok := r.get(mux.Vars(req)["topology"]) - if !ok { + topologyID := mux.Vars(req)["topology"] + if _, ok := r.get(topologyID); !ok { http.NotFound(w, req) return } - renderer, decorator := renderedForRequest(req, topology) - f(ctx, rep, renderer, decorator, w, req) + rpt, err := rep.Report(ctx) + if err != nil { + respondWith(w, http.StatusInternalServerError, err.Error()) + return + } + req.ParseForm() + renderer, decorator, err := r.rendererForTopology(topologyID, req.Form, rpt) + if err != nil { + respondWith(w, http.StatusInternalServerError, err.Error()) + return + } + f(ctx, renderer, decorator, rpt, w, req) } } diff --git a/app/api_topology.go b/app/api_topology.go index d9ecd73788..3a6eabb89d 100644 --- a/app/api_topology.go +++ b/app/api_topology.go @@ -11,6 +11,7 @@ import ( "github.com/weaveworks/scope/common/xfer" "github.com/weaveworks/scope/render" "github.com/weaveworks/scope/render/detailed" + "github.com/weaveworks/scope/report" ) const ( @@ -28,60 +29,21 @@ type APINode struct { } // Full topology. -func handleTopology( - ctx context.Context, - rep Reporter, renderer render.Renderer, decorator render.Decorator, - w http.ResponseWriter, r *http.Request, -) { - report, err := rep.Report(ctx) - if err != nil { - respondWith(w, http.StatusInternalServerError, err.Error()) - return - } +func handleTopology(ctx context.Context, renderer render.Renderer, decorator render.Decorator, report report.Report, w http.ResponseWriter, r *http.Request) { respondWith(w, http.StatusOK, APITopology{ Nodes: detailed.Summaries(report, renderer.Render(report, decorator)), }) } -// Websocket for the full topology. This route overlaps with the next. -func handleWs( - ctx context.Context, - rep Reporter, renderer render.Renderer, decorator render.Decorator, - w http.ResponseWriter, r *http.Request, -) { - if err := r.ParseForm(); err != nil { - respondWith(w, http.StatusInternalServerError, err.Error()) - return - } - loop := websocketLoop - if t := r.Form.Get("t"); t != "" { - var err error - if loop, err = time.ParseDuration(t); err != nil { - respondWith(w, http.StatusBadRequest, t) - return - } - } - handleWebsocket(ctx, w, r, rep, renderer, decorator, loop) -} - // Individual nodes. -func handleNode( - ctx context.Context, - rep Reporter, renderer render.Renderer, _ render.Decorator, - w http.ResponseWriter, r *http.Request, -) { +func handleNode(ctx context.Context, renderer render.Renderer, _ render.Decorator, report report.Report, w http.ResponseWriter, r *http.Request) { var ( - vars = mux.Vars(r) - topologyID = vars["topology"] - nodeID = vars["id"] - report, err = rep.Report(ctx) - rendered = renderer.Render(report, render.FilterNoop) - node, ok = rendered[nodeID] + vars = mux.Vars(r) + topologyID = vars["topology"] + nodeID = vars["id"] + rendered = renderer.Render(report, nil) + node, ok = rendered[nodeID] ) - if err != nil { - respondWith(w, http.StatusInternalServerError, err.Error()) - return - } if !ok { http.NotFound(w, r) return @@ -89,15 +51,26 @@ func handleNode( respondWith(w, http.StatusOK, APINode{Node: detailed.MakeNode(topologyID, report, rendered, node)}) } +// Websocket for the full topology. func handleWebsocket( ctx context.Context, + rep Reporter, w http.ResponseWriter, r *http.Request, - rep Reporter, - renderer render.Renderer, - decorator render.Decorator, - loop time.Duration, ) { + if err := r.ParseForm(); err != nil { + respondWith(w, http.StatusInternalServerError, err.Error()) + return + } + loop := websocketLoop + if t := r.Form.Get("t"); t != "" { + var err error + if loop, err = time.ParseDuration(t); err != nil { + respondWith(w, http.StatusBadRequest, t) + return + } + } + conn, err := xfer.Upgrade(w, r, nil) if err != nil { // log.Info("Upgrade:", err) @@ -122,6 +95,7 @@ func handleWebsocket( previousTopo detailed.NodeSummaries tick = time.Tick(loop) wait = make(chan struct{}, 1) + topologyID = mux.Vars(r)["topology"] ) rep.WaitOn(ctx, wait) defer rep.UnWait(ctx, wait) @@ -132,6 +106,11 @@ func handleWebsocket( log.Errorf("Error generating report: %v", err) return } + renderer, decorator, err := topologyRegistry.rendererForTopology(topologyID, r.Form, report) + if err != nil { + log.Errorf("Error generating report: %v", err) + return + } newTopo := detailed.Summaries(report, renderer.Render(report, decorator)) diff := detailed.TopoDiff(previousTopo, newTopo) previousTopo = newTopo diff --git a/app/router.go b/app/router.go index d2ca136dda..960717ba5a 100644 --- a/app/router.go +++ b/app/router.go @@ -91,7 +91,7 @@ func RegisterTopologyRoutes(router *mux.Router, r Reporter) { get.HandleFunc("/api/topology/{topology}", gzipHandler(requestContextDecorator(topologyRegistry.captureRenderer(r, handleTopology)))) get.HandleFunc("/api/topology/{topology}/ws", - requestContextDecorator(topologyRegistry.captureRenderer(r, handleWs))) // NB not gzip! + requestContextDecorator(captureReporter(r, handleWebsocket))) // NB not gzip! get.MatcherFunc(URLMatcher("/api/topology/{topology}/{id}")).HandlerFunc( gzipHandler(requestContextDecorator(topologyRegistry.captureRenderer(r, handleNode)))) get.HandleFunc("/api/report", diff --git a/probe/kubernetes/pod.go b/probe/kubernetes/pod.go index 02db0e382c..b5a1165154 100644 --- a/probe/kubernetes/pod.go +++ b/probe/kubernetes/pod.go @@ -37,13 +37,13 @@ type Pod interface { type pod struct { *api.Pod - serviceIDs []string + serviceIDs report.StringSet Node *api.Node } // NewPod creates a new Pod func NewPod(p *api.Pod) Pod { - return &pod{Pod: p} + return &pod{Pod: p, serviceIDs: report.MakeStringSet()} } func (p *pod) UID() string { @@ -75,7 +75,7 @@ func (p *pod) Labels() labels.Labels { } func (p *pod) AddServiceID(id string) { - p.serviceIDs = append(p.serviceIDs, id) + p.serviceIDs = p.serviceIDs.Add(id) } func (p *pod) State() string { @@ -95,10 +95,7 @@ func (p *pod) GetNode(probeID string) report.Node { PodState: p.State(), PodIP: p.Status.PodIP, report.ControlProbeID: probeID, - }) - if len(p.serviceIDs) > 0 { - n = n.WithLatests(map[string]string{ServiceIDs: strings.Join(p.serviceIDs, " ")}) - } + }).WithSets(report.EmptySets.Add(ServiceIDs, p.serviceIDs)) for _, serviceID := range p.serviceIDs { segments := strings.SplitN(serviceID, "/", 2) if len(segments) != 2 { diff --git a/probe/kubernetes/reporter_test.go b/probe/kubernetes/reporter_test.go index aa7fc14a35..b7b65475d9 100644 --- a/probe/kubernetes/reporter_test.go +++ b/probe/kubernetes/reporter_test.go @@ -174,20 +174,23 @@ 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(), - kubernetes.ServiceIDs: "ping/pongservice", + }, map[string]report.StringSet{ + kubernetes.ServiceIDs: report.MakeStringSet("ping/pongservice"), }}, {pod2ID, serviceID, map[string]string{ kubernetes.PodID: "ping/pong-b", kubernetes.PodName: "pong-b", kubernetes.Namespace: "ping", kubernetes.PodCreated: pod1.Created(), - kubernetes.ServiceIDs: "ping/pongservice", + }, map[string]report.StringSet{ + kubernetes.ServiceIDs: report.MakeStringSet("ping/pongservice"), }}, } { node, ok := rpt.Pod.Nodes[pod.id] @@ -204,6 +207,12 @@ 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 diff --git a/render/expected/expected.go b/render/expected/expected.go index 351f19c993..b436d72e54 100644 --- a/render/expected/expected.go +++ b/render/expected/expected.go @@ -238,8 +238,8 @@ var ( render.OutgoingInternetID: theOutgoingInternetNode, } - unmanagedServerID = render.MakePseudoNodeID(render.UnmanagedID, fixture.ServerHostID) - unmanagedServerNode = pseudo(unmanagedServerID, render.OutgoingInternetID).WithChildren(report.MakeNodeSet( + UnmanagedServerID = render.MakePseudoNodeID(render.UnmanagedID, fixture.ServerHostID) + unmanagedServerNode = pseudo(UnmanagedServerID, render.OutgoingInternetID).WithChildren(report.MakeNodeSet( uncontainedServerNode, RenderedEndpoints[fixture.NonContainerNodeID], RenderedProcesses[fixture.NonContainerProcessNodeID], @@ -262,7 +262,7 @@ var ( RenderedContainers[fixture.ServerContainerNodeID], )), - unmanagedServerID: unmanagedServerNode, + UnmanagedServerID: unmanagedServerNode, render.IncomingInternetID: theIncomingInternetNode(fixture.ServerPodNodeID), render.OutgoingInternetID: theOutgoingInternetNode, } @@ -282,7 +282,7 @@ var ( RenderedPods[fixture.ServerPodNodeID], )), - unmanagedServerID: unmanagedServerNode, + UnmanagedServerID: unmanagedServerNode, render.IncomingInternetID: theIncomingInternetNode(fixture.ServiceNodeID), render.OutgoingInternetID: theOutgoingInternetNode, } diff --git a/render/filters.go b/render/filters.go index 6b18ee459f..0d075ce326 100644 --- a/render/filters.go +++ b/render/filters.go @@ -275,6 +275,14 @@ func HasChildren(topology string) FilterFunc { } } +// IsNamespace checks if the node is a pod/service in the specified namespace +func IsNamespace(namespace string) FilterFunc { + return func(n report.Node) bool { + gotNamespace, ok := n.Latest.Lookup(kubernetes.Namespace) + return !ok || namespace == gotNamespace + } +} + var systemContainerNames = map[string]struct{}{ "weavescope": {}, "weavedns": {}, diff --git a/render/pod.go b/render/pod.go index fdb1fda371..7f7c540ab3 100644 --- a/render/pod.go +++ b/render/pod.go @@ -16,37 +16,40 @@ const ( // PodRenderer is a Renderer which produces a renderable kubernetes // graph by merging the container graph and the pods topology. -var PodRenderer = MakeFilter( - func(n report.Node) bool { - // Drop deleted or empty pods - state, ok := n.Latest.Lookup(kubernetes.PodState) - return HasChildren(report.Container)(n) && (!ok || state != kubernetes.StateDeleted) - }, - MakeReduce( - MakeFilter( - func(n report.Node) bool { - // Drop unconnected pseudo nodes (could appear due to filtering) - _, isConnected := n.Latest.Lookup(IsConnected) - return n.Topology != Pseudo || isConnected - }, - ColorConnected(MakeMap( - MapContainer2Pod, - ContainerWithImageNameRenderer, - )), +var PodRenderer = ApplyDecorators( + MakeFilter( + func(n report.Node) bool { + state, ok := n.Latest.Lookup(kubernetes.PodState) + return (!ok || state != kubernetes.StateDeleted) + }, + MakeReduce( + MakeFilter( + func(n report.Node) bool { + // Drop unconnected pseudo nodes (could appear due to filtering) + _, isConnected := n.Latest.Lookup(IsConnected) + return n.Topology != Pseudo || isConnected + }, + ColorConnected(MakeMap( + MapContainer2Pod, + ContainerWithImageNameRenderer, + )), + ), + SelectPod, ), - SelectPod, ), ) // PodServiceRenderer is a Renderer which produces a renderable kubernetes services // graph by merging the pods graph and the services topology. -var PodServiceRenderer = FilterEmpty(report.Pod, - MakeReduce( - MakeMap( - MapPod2Service, - PodRenderer, +var PodServiceRenderer = ApplyDecorators( + FilterEmpty(report.Pod, + MakeReduce( + MakeMap( + MapPod2Service, + PodRenderer, + ), + SelectService, ), - SelectService, ), ) @@ -117,13 +120,13 @@ func MapPod2Service(pod report.Node, _ report.Networks) report.Nodes { if !ok { return report.Nodes{} } - ids, ok := pod.Latest.Lookup(kubernetes.ServiceIDs) + serviceIDs, ok := pod.Sets.Lookup(kubernetes.ServiceIDs) if !ok { return report.Nodes{} } result := report.Nodes{} - for _, serviceID := range strings.Fields(ids) { + for _, serviceID := range serviceIDs { serviceName := strings.TrimPrefix(serviceID, namespace+"/") id := report.MakeServiceNodeID(namespace, serviceName) node := NewDerivedNode(id, pod).WithTopology(report.Service) diff --git a/render/pod_test.go b/render/pod_test.go index d4776939e3..f091f8c227 100644 --- a/render/pod_test.go +++ b/render/pod_test.go @@ -7,14 +7,13 @@ import ( "github.com/weaveworks/scope/probe/kubernetes" "github.com/weaveworks/scope/render" "github.com/weaveworks/scope/render/expected" - "github.com/weaveworks/scope/report" "github.com/weaveworks/scope/test" "github.com/weaveworks/scope/test/fixture" "github.com/weaveworks/scope/test/reflect" ) func TestPodRenderer(t *testing.T) { - have := Prune(render.PodRenderer.Render(fixture.Report, render.FilterNoop)) + have := Prune(render.PodRenderer.Render(fixture.Report, nil)) want := Prune(expected.RenderedPods) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -26,7 +25,7 @@ func TestPodFilterRenderer(t *testing.T) { // it is filtered out correctly. input := fixture.Report.Copy() input.Pod.Nodes[fixture.ClientPodNodeID] = input.Pod.Nodes[fixture.ClientPodNodeID].WithLatests(map[string]string{ - kubernetes.PodID: "pod:kube-system/foo", + kubernetes.PodID: "kube-system/foo", kubernetes.Namespace: "kube-system", kubernetes.PodName: "foo", }) @@ -43,7 +42,7 @@ func TestPodFilterRenderer(t *testing.T) { } func TestPodServiceRenderer(t *testing.T) { - have := Prune(render.PodServiceRenderer.Render(fixture.Report, render.FilterNoop)) + have := Prune(render.PodServiceRenderer.Render(fixture.Report, nil)) want := Prune(expected.RenderedPodServices) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -54,25 +53,12 @@ func TestPodServiceFilterRenderer(t *testing.T) { // tag on containers or pod namespace in the topology and ensure // it is filtered out correctly. input := fixture.Report.Copy() - input.Pod.Nodes[fixture.ClientPodNodeID] = input.Pod.Nodes[fixture.ClientPodNodeID].WithLatests(map[string]string{ - kubernetes.PodID: "pod:kube-system/foo", - kubernetes.Namespace: "kube-system", - kubernetes.PodName: "foo", - }) - input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{ - docker.LabelPrefix + "io.kubernetes.pod.name": "kube-system/foo", - }) - have := Prune(render.PodServiceRenderer.Render(input, render.FilterApplication)) + have := Prune(render.PodServiceRenderer.Render(input, render.FilterSystem)) want := Prune(expected.RenderedPodServices.Copy()) - wantNode := want[fixture.ServiceNodeID] - wantNode.Adjacency = nil - wantNode.Children = report.MakeNodeSet( - expected.RenderedEndpoints[fixture.Server80NodeID], - expected.RenderedProcesses[fixture.ServerProcessNodeID], - expected.RenderedContainers[fixture.ServerContainerNodeID], - expected.RenderedPods[fixture.ServerPodNodeID], - ) - want[fixture.ServiceNodeID] = wantNode + delete(want, fixture.ServiceNodeID) + delete(want, expected.UnmanagedServerID) + delete(want, render.IncomingInternetID) + delete(want, render.OutgoingInternetID) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } diff --git a/test/fixture/report_fixture.go b/test/fixture/report_fixture.go index 679d3b718e..84b9d358db 100644 --- a/test/fixture/report_fixture.go +++ b/test/fixture/report_fixture.go @@ -367,25 +367,27 @@ var ( Nodes: report.Nodes{ ClientPodNodeID: report.MakeNodeWith( ClientPodNodeID, map[string]string{ - kubernetes.PodID: ClientPodID, - kubernetes.PodName: "pong-a", - kubernetes.Namespace: KubernetesNamespace, - kubernetes.ServiceIDs: ServiceID, - report.HostNodeID: ClientHostNodeID, + kubernetes.PodID: ClientPodID, + kubernetes.PodName: "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)), ), ServerPodNodeID: report.MakeNodeWith( ServerPodNodeID, map[string]string{ - kubernetes.PodID: ServerPodID, - kubernetes.PodName: "pong-b", - kubernetes.Namespace: KubernetesNamespace, - kubernetes.PodState: "running", - kubernetes.ServiceIDs: ServiceID, - report.HostNodeID: ServerHostNodeID, + kubernetes.PodID: ServerPodID, + kubernetes.PodName: "pong-b", + kubernetes.Namespace: KubernetesNamespace, + kubernetes.PodState: "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)),