func BenchmarkNodeSetMerge(b *testing.B) { n, other := report.NodeSet{}, report.NodeSet{} for i := 0; i < 600; i++ { n = n.Add( report.MakeNode().WithID(fmt.Sprint(i)).WithLatests(map[string]string{ "a": "1", "b": "2", }), ) } for i := 400; i < 1000; i++ { other = other.Add( report.MakeNode().WithID(fmt.Sprint(i)).WithLatests(map[string]string{ "c": "1", "d": "2", }), ) } b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchmarkResult = n.Merge(other) } }
func TestCollector(t *testing.T) { window := time.Millisecond c := xfer.NewCollector(window) r1 := report.MakeReport() r1.Endpoint.Nodes["foo"] = report.MakeNode() r2 := report.MakeReport() r2.Endpoint.Nodes["bar"] = report.MakeNode() if want, have := report.MakeReport(), c.Report(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } c.Add(r1) if want, have := r1, c.Report(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } c.Add(r2) merged := report.MakeReport() merged = merged.Merge(r1) merged = merged.Merge(r2) if want, have := merged, c.Report(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestMergeRenderableNode(t *testing.T) { node1 := render.RenderableNode{ ID: "foo", LabelMajor: "", LabelMinor: "minor", Rank: "", Pseudo: false, Node: report.MakeNode().WithAdjacent("a1"), Origins: report.MakeIDList("o1"), } node2 := render.RenderableNode{ ID: "foo", LabelMajor: "major", LabelMinor: "", Rank: "rank", Pseudo: false, Node: report.MakeNode().WithAdjacent("a2"), Origins: report.MakeIDList("o2"), } want := render.RenderableNode{ ID: "foo", LabelMajor: "major", LabelMinor: "minor", Rank: "rank", Pseudo: false, Node: report.MakeNode().WithAdjacency(report.MakeIDList("a1", "a2")), Origins: report.MakeIDList("o1", "o2"), EdgeMetadata: report.EdgeMetadata{}, } have := node1.Merge(node2) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestNode(t *testing.T) { { node := report.MakeNode().WithLatests(map[string]string{ "foo": "bar", }) if v, _ := node.Latest.Lookup("foo"); v != "bar" { t.Errorf("want foo, have %s", v) } } { node := report.MakeNode().WithCounters( map[string]int{"foo": 1}, ) if value, _ := node.Counters.Lookup("foo"); value != 1 { t.Errorf("want foo, have %d", value) } } { node := report.MakeNode().WithAdjacent("foo") if node.Adjacency[0] != "foo" { t.Errorf("want foo, have %v", node.Adjacency) } } { node := report.MakeNode().WithEdge("foo", report.EdgeMetadata{ EgressPacketCount: newu64(13), }) if node.Adjacency[0] != "foo" { t.Errorf("want foo, have %v", node.Adjacency) } if v, ok := node.Edges.Lookup("foo"); ok && *v.EgressPacketCount != 13 { t.Errorf("want 13, have %v", node.Edges) } } }
func TestNode(t *testing.T) { { node := report.MakeNode().WithMetadata(report.Metadata{ "foo": "bar", }) if node.Metadata["foo"] != "bar" { t.Errorf("want foo, have %s", node.Metadata["foo"]) } } { node := report.MakeNode().WithCounters(report.Counters{ "foo": 1, }) if node.Counters["foo"] != 1 { t.Errorf("want foo, have %d", node.Counters["foo"]) } } { node := report.MakeNode().WithAdjacent("foo") if node.Adjacency[0] != "foo" { t.Errorf("want foo, have %v", node.Adjacency) } } { node := report.MakeNode().WithEdge("foo", report.EdgeMetadata{ EgressPacketCount: newu64(13), }) if node.Adjacency[0] != "foo" { t.Errorf("want foo, have %v", node.Adjacency) } if *node.Edges["foo"].EgressPacketCount != 13 { t.Errorf("want 13, have %v", node.Edges) } } }
func TestApply(t *testing.T) { var ( endpointNodeID = "c" addressNodeID = "d" endpointNode = report.MakeNodeWith(map[string]string{"5": "6"}) addressNode = report.MakeNodeWith(map[string]string{"7": "8"}) ) p := New(0, 0, nil) p.AddTagger(NewTopologyTagger()) r := report.MakeReport() r.Endpoint.AddNode(endpointNodeID, endpointNode) r.Address.AddNode(addressNodeID, addressNode) r = p.tag(r) for _, tuple := range []struct { want report.Node from report.Topology via string }{ {endpointNode.Merge(report.MakeNode().WithID("c").WithTopology(report.Endpoint)), r.Endpoint, endpointNodeID}, {addressNode.Merge(report.MakeNode().WithID("d").WithTopology(report.Address)), r.Address, addressNodeID}, } { if want, have := tuple.want, tuple.from.Nodes[tuple.via]; !reflect.DeepEqual(want, have) { t.Errorf("want %+v, have %+v", want, have) } } }
// Report implements Reporter. func (r *Reporter) Report() (report.Report, error) { defer func(begin time.Time) { SpyDuration.WithLabelValues().Observe(float64(time.Since(begin))) }(time.Now()) hostNodeID := report.MakeHostNodeID(r.hostID) rpt := report.MakeReport() { conns, err := procspy.Connections(r.includeProcesses) if err != nil { return rpt, err } commonNodeInfo := report.MakeNode().WithMetadata(report.Metadata{ Procspied: "true", }) for conn := conns.Next(); conn != nil; conn = conns.Next() { var ( localPort = conn.LocalPort remotePort = conn.RemotePort localAddr = conn.LocalAddress.String() remoteAddr = conn.RemoteAddress.String() ) extraNodeInfo := commonNodeInfo.Copy() if conn.Proc.PID > 0 { extraNodeInfo = extraNodeInfo.WithMetadata(report.Metadata{ process.PID: strconv.FormatUint(uint64(conn.Proc.PID), 10), report.HostNodeID: hostNodeID, }) } r.addConnection(&rpt, localAddr, remoteAddr, localPort, remotePort, &extraNodeInfo, &commonNodeInfo) } } if r.conntracker != nil { extraNodeInfo := report.MakeNode().WithMetadata(report.Metadata{ Conntracked: "true", }) r.conntracker.WalkFlows(func(f Flow) { var ( localPort = uint16(f.Original.Layer4.SrcPort) remotePort = uint16(f.Original.Layer4.DstPort) localAddr = f.Original.Layer3.SrcIP remoteAddr = f.Original.Layer3.DstIP ) r.addConnection(&rpt, localAddr, remoteAddr, localPort, remotePort, &extraNodeInfo, &extraNodeInfo) }) } if r.natmapper != nil { r.natmapper.ApplyNAT(rpt, r.hostID) } return rpt, nil }
func TestMerge(t *testing.T) { var ( hostID = "xyz" src = newMockSource([]byte{}, nil) on = time.Millisecond off = time.Millisecond rpt = report.MakeReport() p = sniff.Packet{ SrcIP: "1.0.0.0", SrcPort: "1000", DstIP: "2.0.0.0", DstPort: "2000", Network: 512, Transport: 256, } _, ipnet, _ = net.ParseCIDR(p.SrcIP + "/24") // ;) localNets = report.Networks([]*net.IPNet{ipnet}) ) sniff.New(hostID, localNets, src, on, off).Merge(p, &rpt) var ( srcEndpointNodeID = report.MakeEndpointNodeID(hostID, p.SrcIP, p.SrcPort) dstEndpointNodeID = report.MakeEndpointNodeID(hostID, p.DstIP, p.DstPort) ) if want, have := (report.Topology{ Nodes: report.Nodes{ srcEndpointNodeID: report.MakeNode().WithEdge(dstEndpointNodeID, report.EdgeMetadata{ EgressPacketCount: newu64(1), EgressByteCount: newu64(256), }), dstEndpointNodeID: report.MakeNode(), }, }), rpt.Endpoint; !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } var ( srcAddressNodeID = report.MakeAddressNodeID(hostID, p.SrcIP) dstAddressNodeID = report.MakeAddressNodeID(hostID, p.DstIP) ) if want, have := (report.Topology{ Nodes: report.Nodes{ srcAddressNodeID: report.MakeNode().WithEdge(dstAddressNodeID, report.EdgeMetadata{ EgressPacketCount: newu64(1), EgressByteCount: newu64(512), }), dstAddressNodeID: report.MakeNode(), }, }), rpt.Address; !reflect.DeepEqual(want, have) { t.Errorf("%s", test.Diff(want, have)) } }
func TestNodeSetDelete(t *testing.T) { for _, testcase := range []struct { input report.NodeSet nodes []string want report.NodeSet }{ { input: report.NodeSet{}, nodes: []string{}, want: report.NodeSet{}, }, { input: report.EmptyNodeSet, nodes: []string{}, want: report.EmptyNodeSet, }, { input: report.MakeNodeSet(report.MakeNode("a")), nodes: []string{}, want: report.MakeNodeSet(report.MakeNode("a")), }, { input: report.EmptyNodeSet, nodes: []string{"a"}, want: report.EmptyNodeSet, }, { input: report.MakeNodeSet(report.MakeNode("a")), nodes: []string{"a"}, want: report.EmptyNodeSet, }, { input: report.MakeNodeSet(report.MakeNode("b")), nodes: []string{"a", "b"}, want: report.EmptyNodeSet, }, { input: report.MakeNodeSet(report.MakeNode("a")), nodes: []string{"c", "b"}, want: report.MakeNodeSet(report.MakeNode("a")), }, { input: report.MakeNodeSet(report.MakeNode("a"), report.MakeNode("c")), nodes: []string{"a", "a", "a"}, want: report.MakeNodeSet(report.MakeNode("c")), }, } { originalLen := testcase.input.Size() if want, have := testcase.want, testcase.input.Delete(testcase.nodes...); !reflect.DeepEqual(want, have) { t.Errorf("%v + %v: want %v, have %v", testcase.input, testcase.nodes, want, have) } if testcase.input.Size() != originalLen { t.Errorf("%v + %v: modified the original input!", testcase.input, testcase.nodes) } } }
func TestMakeRenderableNodes(t *testing.T) { var ( newu64 = func(value uint64) *uint64 { return &value } srcNodeID = "srcNode" dstNode1ID = "dstNode1" dstNode2ID = "dstNode2" srcNode = report.MakeNode(). WithEdge(dstNode1ID, report.EdgeMetadata{EgressPacketCount: newu64(100), EgressByteCount: newu64(1000)}). WithEdge(dstNode2ID, report.EdgeMetadata{EgressPacketCount: newu64(200), EgressByteCount: newu64(2000)}) dstNode1 = report.MakeNode() dstNode2 = report.MakeNode() topology = report.MakeTopology(). AddNode(srcNodeID, srcNode). AddNode(dstNode1ID, dstNode1). AddNode(dstNode2ID, dstNode2) ) result := render.MakeRenderableNodes(topology) mustLookup := func(id string) render.RenderableNode { node, ok := result[id] if !ok { t.Fatalf("Expected result to contain node: %q, got: %v", id, result) } return node } // Source nodes should have the flattened edge metadata { have := mustLookup(srcNodeID).EdgeMetadata want := report.EdgeMetadata{EgressPacketCount: newu64(300), EgressByteCount: newu64(3000)} if !reflect.DeepEqual(want, have) { t.Errorf(test.Diff(want, have)) } } // Result destination nodes should have the reverse of the source nodes { have := mustLookup(dstNode1ID).EdgeMetadata want := report.EdgeMetadata{IngressPacketCount: newu64(100), IngressByteCount: newu64(1000)} if !reflect.DeepEqual(want, have) { t.Errorf(test.Diff(want, have)) } have = mustLookup(dstNode2ID).EdgeMetadata want = report.EdgeMetadata{IngressPacketCount: newu64(200), IngressByteCount: newu64(2000)} if !reflect.DeepEqual(want, have) { t.Errorf(test.Diff(want, have)) } } }
func TestReduceRender(t *testing.T) { renderer := render.Reduce([]render.Renderer{ mockRenderer{Nodes: report.Nodes{"foo": report.MakeNode("foo")}}, mockRenderer{Nodes: report.Nodes{"bar": report.MakeNode("bar")}}, }) want := report.Nodes{ "foo": report.MakeNode("foo"), "bar": report.MakeNode("bar"), } have := renderer.Render(report.MakeReport(), FilterNoop) if !reflect.DeepEqual(want, have) { t.Errorf("want %+v, have %+v", want, have) } }
// Report implements Reporter. func (w *Weave) Report() (report.Report, error) { w.mtx.RLock() defer w.mtx.RUnlock() r := report.MakeReport() r.Container = r.Container.WithMetadataTemplates(report.MetadataTemplates{ WeaveMACAddress: {ID: WeaveMACAddress, Label: "Weave MAC", From: report.FromLatest, Priority: 17}, WeaveDNSHostname: {ID: WeaveDNSHostname, Label: "Weave DNS Name", From: report.FromLatest, Priority: 18}, }) for _, peer := range w.statusCache.Router.Peers { r.Overlay.AddNode(report.MakeNodeWith(report.MakeOverlayNodeID(peer.Name), map[string]string{ WeavePeerName: peer.Name, WeavePeerNickName: peer.NickName, })) } if w.statusCache.IPAM.DefaultSubnet != "" { r.Overlay.AddNode( report.MakeNode(report.MakeOverlayNodeID(w.statusCache.Router.Name)).WithSets( report.MakeSets().Add(host.LocalNetworks, report.MakeStringSet(w.statusCache.IPAM.DefaultSubnet)), ), ) } return r, nil }
func TestMapHostIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), true}, // TODO it's questionable if this is actually correct } { testMap(t, render.MapHostIdentity, input) } }
func TestFilterRender(t *testing.T) { renderer := render.FilterUnconnected( mockRenderer{RenderableNodes: render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode().WithAdjacent("bar")}, "bar": {ID: "bar", Node: report.MakeNode().WithAdjacent("foo")}, "baz": {ID: "baz", Node: report.MakeNode()}, }}) want := render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode().WithAdjacent("bar")}, "bar": {ID: "bar", Node: report.MakeNode().WithAdjacent("foo")}, } have := renderer.Render(report.MakeReport()).Prune() if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestMakeNodeSet(t *testing.T) { for _, testcase := range []struct { inputs []string wants []string }{ {inputs: nil, wants: nil}, { inputs: []string{"a"}, wants: []string{"a"}, }, { inputs: []string{"b", "c", "a"}, wants: []string{"a", "b", "c"}, }, { inputs: []string{"a", "a", "a"}, wants: []string{"a"}, }, } { var inputs []report.Node for _, id := range testcase.inputs { inputs = append(inputs, report.MakeNode(id)) } set := report.MakeNodeSet(inputs...) var have []string set.ForEach(func(node report.Node) { have = append(have, node.ID) }) if !reflect.DeepEqual(testcase.wants, have) { t.Errorf("%#v: want %#v, have %#v", testcase.inputs, testcase.wants, have) } } }
func TestFilterRender(t *testing.T) { renderer := render.FilterUnconnected( mockRenderer{RenderableNodes: render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode().WithAdjacent("bar")}, "bar": {ID: "bar", Node: report.MakeNode().WithAdjacent("foo")}, "baz": {ID: "baz", Node: report.MakeNode()}, }}) want := render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode().WithAdjacent("bar")}, "bar": {ID: "bar", Node: report.MakeNode().WithAdjacent("foo")}, } have := expected.Sterilize(renderer.Render(report.MakeReport())) if !reflect.DeepEqual(want, have) { t.Errorf("want %+v, have %+v", want, have) } }
func TestMapAddressIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "192.168.1.1"})), true}, } { testMap(t, render.MapAddressIdentity, input) } }
func TestMapContainerImageIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), false}, {nrn(report.MakeNodeWith(map[string]string{docker.ImageID: "a1b2c3"})), true}, } { testMap(t, render.MapContainerImageIdentity, input) } }
func TestMapProcessIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), false}, {nrn(report.MakeNodeWith(map[string]string{process.PID: "201"})), true}, } { testMap(t, render.MapProcessIdentity, input) } }
func TestMapServiceIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), false}, {nrn(report.MakeNodeWith(map[string]string{kubernetes.ServiceID: "ping/pong", kubernetes.ServiceName: "pong"})), true}, } { testMap(t, render.MapServiceIdentity, input) } }
func TestFilterPseudo(t *testing.T) { // Test pseudonodes are removed { nodes := render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode()}, "bar": {ID: "bar", Pseudo: true, Node: report.MakeNode()}, } renderer := render.FilterPseudo(mockRenderer{RenderableNodes: nodes}) want := render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode()}, } have := renderer.Render(report.MakeReport()).Prune() if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } } }
func TestMergeRenderableNode(t *testing.T) { node1 := render.RenderableNode{ ID: "foo", LabelMajor: "", LabelMinor: "minor", Rank: "", Pseudo: false, Node: report.MakeNode().WithAdjacent("a1"), Children: report.MakeNodeSet(report.MakeNode().WithID("child1")), } node2 := render.RenderableNode{ ID: "foo", LabelMajor: "major", LabelMinor: "", Rank: "rank", Pseudo: false, Node: report.MakeNode().WithAdjacent("a2"), Children: report.MakeNodeSet(report.MakeNode().WithID("child2")), } want := render.RenderableNode{ ID: "foo", LabelMajor: "major", LabelMinor: "minor", Rank: "rank", Pseudo: false, Node: report.MakeNode().WithID("foo").WithAdjacent("a1").WithAdjacent("a2"), Children: report.MakeNodeSet(report.MakeNode().WithID("child1"), report.MakeNode().WithID("child2")), EdgeMetadata: report.EdgeMetadata{}, }.Prune() have := node1.Merge(node2).Prune() if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
// FIXME: Hideous hack to remove persistent-connection edges to virtual service // IPs attributed to the internet. We add each service IP as a /32 network // (the global service-cluster-ip-range is not exposed by the API // server so we treat each IP as a /32 network see // https://github.com/kubernetes/kubernetes/issues/25533). // The right way of fixing this is performing DNAT mapping on persistent // connections for which we don't have a robust solution // (see https://github.com/weaveworks/scope/issues/1491) func (r *Reporter) hostTopology(services []Service) report.Topology { localNetworks := report.EmptyStringSet for _, service := range services { localNetworks = localNetworks.Add(service.ClusterIP() + "/32") } node := report.MakeNode(report.MakeHostNodeID(r.hostID)) node = node.WithSets(report.EmptySets. Add(host.LocalNetworks, localNetworks)) return report.MakeTopology().AddNode(node) }
func TestTagMissingID(t *testing.T) { const nodeID = "not-found" r := report.MakeReport() want := report.MakeNode() rpt, _ := newTopologyTagger().Tag(r) have := rpt.Endpoint.Nodes[nodeID].Copy() if !reflect.DeepEqual(want, have) { t.Error("TopologyTagger erroneously tagged a missing node ID") } }
// NewRenderableNode makes a new RenderableNode func NewRenderableNode(id string) RenderableNode { return RenderableNode{ ID: id, LabelMajor: "", LabelMinor: "", Rank: "", Pseudo: false, EdgeMetadata: report.EdgeMetadata{}, Node: report.MakeNode(), } }
// PruneNode returns a copy of the Node with all information not strictly // necessary for rendering nodes and edges stripped away. Specifically, that // means cutting out parts of the Node. func PruneNode(node report.Node) report.Node { prunedChildren := report.MakeNodeSet() node.Children.ForEach(func(child report.Node) { prunedChildren = prunedChildren.Add(PruneNode(child)) }) return report.MakeNode( node.ID). WithTopology(node.Topology). WithAdjacent(node.Adjacency.Copy()...). WithChildren(prunedChildren) }
func TestFilterRender2(t *testing.T) { // Test adjacencies are removed for filtered nodes. renderer := render.Filter{ FilterFunc: func(node render.RenderableNode) bool { return node.ID != "bar" }, Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode().WithAdjacent("bar")}, "bar": {ID: "bar", Node: report.MakeNode().WithAdjacent("foo")}, "baz": {ID: "baz", Node: report.MakeNode()}, }}, } want := render.RenderableNodes{ "foo": {ID: "foo", Node: report.MakeNode()}, "baz": {ID: "baz", Node: report.MakeNode()}, } have := renderer.Render(report.MakeReport()).Prune() if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestMapRender2(t *testing.T) { // 2. Check we can remap two nodes into one mapper := render.Map{ MapFunc: func(nodes report.Node, _ report.Networks) report.Nodes { return report.Nodes{ "bar": report.MakeNode("bar"), } }, Renderer: mockRenderer{Nodes: report.Nodes{ "foo": report.MakeNode("foo"), "baz": report.MakeNode("baz"), }}, } want := report.Nodes{ "bar": report.MakeNode("bar"), } have := mapper.Render(report.MakeReport(), FilterNoop) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestMapRender3(t *testing.T) { // 3. Check we can remap adjacencies mapper := render.Map{ MapFunc: func(nodes render.RenderableNode, _ report.Networks) render.RenderableNodes { id := "_" + nodes.ID return render.RenderableNodes{id: render.NewRenderableNode(id)} }, Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ "foo": render.NewRenderableNode("foo").WithNode(report.MakeNode().WithAdjacent("baz")), "baz": render.NewRenderableNode("baz").WithNode(report.MakeNode().WithAdjacent("foo")), }}, } want := render.RenderableNodes{ "_foo": render.NewRenderableNode("_foo").WithNode(report.MakeNode().WithAdjacent("_baz")), "_baz": render.NewRenderableNode("_baz").WithNode(report.MakeNode().WithAdjacent("_foo")), } have := mapper.Render(report.MakeReport()) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestMapEndpointIdentity(t *testing.T) { for _, input := range []testcase{ {nrn(report.MakeNode()), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "1.2.3.4"})), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Port: "1234"})), false}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "1234"})), true}, {nrn(report.MakeNodeWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "40000"})), true}, {nrn(report.MakeNodeWith(map[string]string{report.HostNodeID: report.MakeHostNodeID("foo"), endpoint.Addr: "10.0.0.1", endpoint.Port: "20001"})), true}, } { testMap(t, render.MapEndpointIdentity, input) } }