Example #1
0
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))
	}
}
Example #2
0
// Set the list of endpoints for the given hostname.
func (c *multiClient) Set(hostname string, endpoints []string) {
	wg := sync.WaitGroup{}
	wg.Add(len(endpoints))
	clients := make(chan clientTuple, len(endpoints))
	for _, endpoint := range endpoints {
		go func(endpoint string) {
			c.sema.acquire()
			defer c.sema.release()
			defer wg.Done()

			client, err := c.clientFactory(hostname, endpoint)
			if err != nil {
				log.Errorf("Error creating new app client: %v", err)
				return
			}

			details, err := client.Details()
			if err != nil {
				log.Errorf("Error fetching app details: %v", err)
				return
			}

			clients <- clientTuple{details, client}
		}(endpoint)
	}

	wg.Wait()
	close(clients)
	c.mtx.Lock()
	defer c.mtx.Unlock()

	// Start any new apps, and replace the list of app ids for this hostname
	hostIDs := report.MakeIDList()
	for tuple := range clients {
		hostIDs = hostIDs.Add(tuple.ID)

		_, ok := c.clients[tuple.ID]
		if !ok {
			c.clients[tuple.ID] = tuple.AppClient
			tuple.AppClient.ControlConnection()
		}
	}
	c.ids[hostname] = hostIDs

	// Remove apps that are no longer referenced (by id) from any hostname
	allReferencedIDs := report.MakeIDList()
	for _, ids := range c.ids {
		allReferencedIDs = allReferencedIDs.Add(ids...)
	}
	for id, client := range c.clients {
		if !allReferencedIDs.Contains(id) {
			client.Stop()
			delete(c.clients, id)
		}
	}
}
Example #3
0
func assertAdjacent(t *testing.T, n report.RenderableNode, ids ...string) {
	want := report.MakeIDList(ids...)

	if have := n.Adjacency; !reflect.DeepEqual(want, have) {
		t.Fatalf("want adjacency list %v, have %v", want, have)
	}
}
Example #4
0
// MakeRenderableNodes converts a topology to a set of RenderableNodes
func MakeRenderableNodes(t report.Topology) RenderableNodes {
	result := RenderableNodes{}
	for id, nmd := range t.Nodes {
		rn := NewRenderableNode(id).WithNode(nmd)
		rn.Origins = report.MakeIDList(id)
		if hostNodeID, ok := nmd.Metadata[report.HostNodeID]; ok {
			rn.Origins = rn.Origins.Add(hostNodeID)
		}
		result[id] = rn
	}

	// Push EdgeMetadata to both ends of the edges
	for srcID, srcNode := range result {
		for dstID, emd := range srcNode.Edges {
			srcNode.EdgeMetadata = srcNode.EdgeMetadata.Flatten(emd)

			dstNode := result[dstID]
			dstNode.EdgeMetadata = dstNode.EdgeMetadata.Flatten(emd.Reversed())
			result[dstID] = dstNode
		}

		result[srcID] = srcNode
	}
	return result
}
Example #5
0
func TestFilterRender(t *testing.T) {
	renderer := render.FilterUnconnected(
		mockRenderer{RenderableNodes: render.RenderableNodes{
			"foo": {ID: "foo", Adjacency: report.MakeIDList("bar"), NodeMetadata: report.MakeNodeMetadata()},
			"bar": {ID: "bar", Adjacency: report.MakeIDList("foo"), NodeMetadata: report.MakeNodeMetadata()},
			"baz": {ID: "baz", Adjacency: report.MakeIDList(), NodeMetadata: report.MakeNodeMetadata()},
		}})
	want := render.RenderableNodes{
		"foo": {ID: "foo", Adjacency: report.MakeIDList("bar"), NodeMetadata: report.MakeNodeMetadata()},
		"bar": {ID: "bar", Adjacency: report.MakeIDList("foo"), NodeMetadata: report.MakeNodeMetadata()},
	}
	have := sterilize(renderer.Render(report.MakeReport()), true)
	if !reflect.DeepEqual(want, have) {
		t.Errorf("want %+v, have %+v", want, have)
	}
}
Example #6
0
func ids(nodes RenderableNodes) report.IDList {
	result := report.MakeIDList()
	for id := range nodes {
		result = result.Add(id)
	}
	return result
}
Example #7
0
func TestMapEdge(t *testing.T) {
	selector := func(_ report.Report) report.Topology {
		return report.Topology{
			NodeMetadatas: report.NodeMetadatas{
				"foo": report.NewNodeMetadata(map[string]string{"id": "foo"}),
				"bar": report.NewNodeMetadata(map[string]string{"id": "bar"}),
			},
			Adjacency: report.Adjacency{
				">foo": report.MakeIDList("bar"),
				">bar": report.MakeIDList("foo"),
			},
			EdgeMetadatas: report.EdgeMetadatas{
				"foo|bar": report.EdgeMetadata{WithBytes: true, BytesIngress: 1, BytesEgress: 2},
				"bar|foo": report.EdgeMetadata{WithBytes: true, BytesIngress: 3, BytesEgress: 4},
			},
		}
	}

	identity := func(nmd report.NodeMetadata) (render.RenderableNode, bool) {
		return render.NewRenderableNode(nmd.Metadata["id"], "", "", "", nmd), true
	}

	mapper := render.Map{
		MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) {
			return render.RenderableNode{ID: "_" + nodes.ID}, true
		},
		Renderer: render.LeafMap{
			Selector: selector,
			Mapper:   identity,
			Pseudo:   nil,
		},
	}

	want := render.AggregateMetadata{
		render.KeyBytesIngress: 1,
		render.KeyBytesEgress:  2,
	}
	have := mapper.AggregateMetadata(report.MakeReport(), "_foo", "_bar")
	if !reflect.DeepEqual(want, have) {
		t.Errorf("want %+v, have %+v", want, have)
	}
}
Example #8
0
func TestMapRender3(t *testing.T) {
	// 3. Check we can remap adjacencies
	mapper := render.Map{
		MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) {
			return render.RenderableNode{ID: "_" + nodes.ID}, true
		},
		Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{
			"foo": {ID: "foo", Adjacency: report.MakeIDList("baz")},
			"baz": {ID: "baz", Adjacency: report.MakeIDList("foo")},
		}},
	}
	want := render.RenderableNodes{
		"_foo": {ID: "_foo", Adjacency: report.MakeIDList("_baz")},
		"_baz": {ID: "_baz", Adjacency: report.MakeIDList("_foo")},
	}
	have := mapper.Render(report.MakeReport())
	if !reflect.DeepEqual(want, have) {
		t.Errorf("want %+v, have %+v", want, have)
	}
}
Example #9
0
func TestMapEdge(t *testing.T) {
	selector := func(_ report.Report) report.Topology {
		return report.Topology{
			NodeMetadatas: report.NodeMetadatas{
				"foo": report.MakeNodeMetadataWith(map[string]string{"id": "foo"}),
				"bar": report.MakeNodeMetadataWith(map[string]string{"id": "bar"}),
			},
			Adjacency: report.Adjacency{
				">foo": report.MakeIDList("bar"),
				">bar": report.MakeIDList("foo"),
			},
			EdgeMetadatas: report.EdgeMetadatas{
				"foo|bar": report.EdgeMetadata{EgressPacketCount: newu64(1), EgressByteCount: newu64(2)},
				"bar|foo": report.EdgeMetadata{EgressPacketCount: newu64(3), EgressByteCount: newu64(4)},
			},
		}
	}

	identity := func(nmd report.NodeMetadata) render.RenderableNodes {
		return render.RenderableNodes{nmd.Metadata["id"]: render.NewRenderableNode(nmd.Metadata["id"], "", "", "", nmd)}
	}

	mapper := render.Map{
		MapFunc: func(nodes render.RenderableNode) render.RenderableNodes {
			id := "_" + nodes.ID
			return render.RenderableNodes{id: render.RenderableNode{ID: id}}
		},
		Renderer: render.LeafMap{
			Selector: selector,
			Mapper:   identity,
			Pseudo:   nil,
		},
	}

	if want, have := (report.EdgeMetadata{
		EgressPacketCount: newu64(1),
		EgressByteCount:   newu64(2),
	}), mapper.EdgeMetadata(report.MakeReport(), "_foo", "_bar"); !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
Example #10
0
// NewRenderableNode makes a new RenderableNode
func NewRenderableNode(id string) RenderableNode {
	return RenderableNode{
		ID:           id,
		LabelMajor:   "",
		LabelMinor:   "",
		Rank:         "",
		Pseudo:       false,
		Origins:      report.MakeIDList(),
		EdgeMetadata: report.EdgeMetadata{},
		Node:         report.MakeNode(),
	}
}
Example #11
0
func TestMergeRenderableNode(t *testing.T) {
	node1 := render.RenderableNode{
		ID:         "foo",
		LabelMajor: "",
		LabelMinor: "minor",
		Rank:       "",
		Pseudo:     false,
		Adjacency:  report.MakeIDList("a1"),
		Origins:    report.MakeIDList("o1"),
	}
	node2 := render.RenderableNode{
		ID:         "foo",
		LabelMajor: "major",
		LabelMinor: "",
		Rank:       "rank",
		Pseudo:     false,
		Adjacency:  report.MakeIDList("a2"),
		Origins:    report.MakeIDList("o2"),
	}

	want := render.RenderableNode{
		ID:         "foo",
		LabelMajor: "major",
		LabelMinor: "minor",
		Rank:       "rank",
		Pseudo:     false,
		Adjacency:  report.MakeIDList("a1", "a2"),
		Origins:    report.MakeIDList("o1", "o2"),
	}
	node1.Merge(node2)

	if !reflect.DeepEqual(want, node1) {
		t.Errorf("want %+v, have %+v", want, node1)
	}
}
Example #12
0
func TestIDList(t *testing.T) {
	have := report.MakeIDList("alpha", "mu", "zeta")
	have = have.Add("alpha")
	have = have.Add("nu")
	have = have.Add("mu")
	have = have.Add("alpha")
	have = have.Add("alpha")
	have = have.Add("epsilon")
	have = have.Add("delta")
	if want := report.IDList([]string{"alpha", "delta", "epsilon", "mu", "nu", "zeta"}); !reflect.DeepEqual(want, have) {
		t.Errorf("want %+v, have %+v", want, have)
	}
}
Example #13
0
func (w Weave) tagContainer(r report.Report, containerIDPrefix, macAddress string, ips []string) {
	for nodeid, nmd := range r.Container.NodeMetadatas {
		idPrefix := nmd.Metadata[docker.ContainerID][:12]
		if idPrefix != containerIDPrefix {
			continue
		}

		existingIPs := report.MakeIDList(docker.ExtractContainerIPs(nmd)...)
		existingIPs = existingIPs.Add(ips...)
		nmd.Metadata[docker.ContainerIPs] = strings.Join(existingIPs, " ")
		nmd.Metadata[WeaveMACAddress] = macAddress
		r.Container.NodeMetadatas[nodeid] = nmd
		break
	}
}
Example #14
0
// EdgeMetadata gives the metadata of an edge from the perspective of the
// srcRenderableID. Since an edgeID can have multiple edges on the address
// level, it uses the supplied mapping function to translate address IDs to
// renderable node (mapped) IDs.
func (m LeafMap) EdgeMetadata(rpt report.Report, srcRenderableID, dstRenderableID string) report.EdgeMetadata {
	t := m.Selector(rpt)
	metadata := report.EdgeMetadata{}
	for edgeID, edgeMeta := range t.EdgeMetadatas {
		src, dst, ok := report.ParseEdgeID(edgeID)
		if !ok {
			log.Printf("bad edge ID %q", edgeID)
			continue
		}
		srcs, dsts := report.MakeIDList(src), report.MakeIDList(dst)
		if src != report.TheInternet {
			mapped := m.Mapper(t.NodeMetadatas[src])
			srcs = ids(mapped)
		}
		if dst != report.TheInternet {
			mapped := m.Mapper(t.NodeMetadatas[dst])
			dsts = ids(mapped)
		}
		if srcs.Contains(srcRenderableID) && dsts.Contains(dstRenderableID) {
			metadata = metadata.Flatten(edgeMeta)
		}
	}
	return metadata
}
Example #15
0
// Tag implements Tagger.
func (w *Weave) Tag(r report.Report) (report.Report, error) {
	w.mtx.RLock()
	defer w.mtx.RUnlock()

	// Put information from weaveDNS on the container nodes
	for _, entry := range w.status.DNS.Entries {
		if entry.Tombstone > 0 {
			continue
		}
		nodeID := report.MakeContainerNodeID(w.hostID, entry.ContainerID)
		node, ok := r.Container.Nodes[nodeID]
		if !ok {
			continue
		}
		hostnames := report.IDList(strings.Fields(node.Metadata[WeaveDNSHostname]))
		hostnames = hostnames.Add(strings.TrimSuffix(entry.Hostname, "."))
		node.Metadata[WeaveDNSHostname] = strings.Join(hostnames, " ")
	}

	// Put information from weave ps on the container nodes
	psEntries, err := w.ps()
	if err != nil {
		return r, nil
	}
	containersByPrefix := map[string]report.Node{}
	for _, node := range r.Container.Nodes {
		prefix := node.Metadata[docker.ContainerID][:12]
		containersByPrefix[prefix] = node
	}
	for _, e := range psEntries {
		node, ok := containersByPrefix[e.containerIDPrefix]
		if !ok {
			continue
		}

		existingIPs := report.MakeIDList(docker.ExtractContainerIPs(node)...)
		existingIPs = existingIPs.Add(e.ips...)
		node.Metadata[docker.ContainerIPs] = strings.Join(existingIPs, " ")
		node.Metadata[WeaveMACAddress] = e.macAddress
	}
	return r, nil
}
Example #16
0
func (m Map) render(rpt report.Report) (RenderableNodes, map[string]string) {
	input := m.Renderer.Render(rpt)
	output := RenderableNodes{}
	mapped := map[string]string{}             // input node ID -> output node ID
	adjacencies := map[string]report.IDList{} // output node ID -> input node Adjacencies

	for _, inRenderable := range input {
		outRenderable, ok := m.MapFunc(inRenderable)
		if !ok {
			continue
		}

		existing, ok := output[outRenderable.ID]
		if ok {
			outRenderable.Merge(existing)
		}

		output[outRenderable.ID] = outRenderable
		mapped[inRenderable.ID] = outRenderable.ID
		adjacencies[outRenderable.ID] = adjacencies[outRenderable.ID].Add(inRenderable.Adjacency...)
	}

	// Rewrite Adjacency for new node IDs.
	// NB we don't do pseudo nodes here; we assume the input graph
	// is properly-connected, and if the map func dropped a node,
	// we drop links to it.
	for outNodeID, inAdjacency := range adjacencies {
		outAdjacency := report.MakeIDList()
		for _, inAdjacent := range inAdjacency {
			if outAdjacent, ok := mapped[inAdjacent]; ok {
				outAdjacency = outAdjacency.Add(outAdjacent)
			}
		}
		outNode := output[outNodeID]
		outNode.Adjacency = outAdjacency
		output[outNodeID] = outNode
	}

	return output, mapped
}
Example #17
0
func (f Filter) render(rpt report.Report) (RenderableNodes, int) {
	output := RenderableNodes{}
	inDegrees := map[string]int{}
	filtered := 0
	for id, node := range f.Renderer.Render(rpt) {
		if f.FilterFunc(node) {
			output[id] = node
			inDegrees[id] = 0
		} else {
			filtered++
		}
	}

	// Deleted nodes also need to be cut as destinations in adjacency lists.
	for id, node := range output {
		newAdjacency := report.MakeIDList()
		for _, dstID := range node.Adjacency {
			if _, ok := output[dstID]; ok {
				newAdjacency = newAdjacency.Add(dstID)
				inDegrees[dstID]++
			}
		}
		node.Adjacency = newAdjacency
		output[id] = node
	}

	// Remove unconnected pseudo nodes, see #483.
	for id, inDegree := range inDegrees {
		if inDegree > 0 {
			continue
		}
		node := output[id]
		if !node.Pseudo || len(node.Adjacency) > 0 {
			continue
		}
		delete(output, id)
		filtered++
	}
	return output, filtered
}
Example #18
0
func (m Map) render(rpt report.Report) (RenderableNodes, map[string]report.IDList) {
	var (
		input         = m.Renderer.Render(rpt)
		output        = RenderableNodes{}
		mapped        = map[string]report.IDList{} // input node ID -> output node IDs
		adjacencies   = map[string]report.IDList{} // output node ID -> input node Adjacencies
		localNetworks = LocalNetworks(rpt)
	)

	// Rewrite all the nodes according to the map function
	for _, inRenderable := range input {
		for _, outRenderable := range m.MapFunc(inRenderable, localNetworks) {
			existing, ok := output[outRenderable.ID]
			if ok {
				outRenderable = outRenderable.Merge(existing)
			}

			output[outRenderable.ID] = outRenderable
			mapped[inRenderable.ID] = mapped[inRenderable.ID].Add(outRenderable.ID)
			adjacencies[outRenderable.ID] = adjacencies[outRenderable.ID].Merge(inRenderable.Adjacency)
		}
	}

	// Rewrite Adjacency for new node IDs.
	for outNodeID, inAdjacency := range adjacencies {
		outAdjacency := report.MakeIDList()
		for _, inAdjacent := range inAdjacency {
			for _, outAdjacent := range mapped[inAdjacent] {
				outAdjacency = outAdjacency.Add(outAdjacent)
			}
		}
		outNode := output[outNodeID]
		outNode.Adjacency = outAdjacency
		output[outNodeID] = outNode
	}

	return output, mapped
}
Example #19
0
			Nodes: report.Nodes{
				ClientAddressNodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr:     ClientIP,
					report.HostNodeID: ClientHostNodeID,
				}).WithEdge(ServerAddressNodeID, report.EdgeMetadata{
					MaxConnCountTCP: newu64(3),
				}),

				ServerAddressNodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr:     ServerIP,
					report.HostNodeID: ServerHostNodeID,
				}),

				UnknownAddress1NodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr: UnknownClient1IP,
				}).WithAdjacency(report.MakeIDList(ServerAddressNodeID)),

				UnknownAddress2NodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr: UnknownClient2IP,
				}).WithAdjacency(report.MakeIDList(ServerAddressNodeID)),

				UnknownAddress3NodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr: UnknownClient3IP,
				}).WithAdjacency(report.MakeIDList(ServerAddressNodeID)),

				RandomAddressNodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr: RandomClientIP,
				}).WithAdjacency(report.MakeIDList(ServerAddressNodeID)),
			},
		},
		Host: report.Topology{
Example #20
0
	uncontainedServerID  = render.MakePseudoNodeID(render.UncontainedID, test.ServerHostName)
	unknownPseudoNode1ID = render.MakePseudoNodeID("10.10.10.10", test.ServerIP, "80")
	unknownPseudoNode2ID = render.MakePseudoNodeID("10.10.10.11", test.ServerIP, "80")
	unknownPseudoNode1   = func(adjacency report.IDList) render.RenderableNode {
		return render.RenderableNode{
			ID:           unknownPseudoNode1ID,
			LabelMajor:   "10.10.10.10",
			Pseudo:       true,
			NodeMetadata: report.MakeNodeMetadata(),
			EdgeMetadata: report.EdgeMetadata{
				EgressPacketCount: newu64(70),
				EgressByteCount:   newu64(700),
			},
			Adjacency: adjacency,
			Origins: report.MakeIDList(
				test.UnknownClient1NodeID,
				test.UnknownClient2NodeID,
			),
		}
	}
	unknownPseudoNode2 = func(adjacency report.IDList) render.RenderableNode {
		return render.RenderableNode{
			ID:           unknownPseudoNode2ID,
			LabelMajor:   "10.10.10.11",
			Pseudo:       true,
			NodeMetadata: report.MakeNodeMetadata(),
			EdgeMetadata: report.EdgeMetadata{
				EgressPacketCount: newu64(50),
				EgressByteCount:   newu64(500),
			},
			Adjacency: adjacency,
			Origins: report.MakeIDList(
Example #21
0
	ClientContainerImageID     = "imageid123"
	ServerContainerImageID     = "imageid456"
	ClientContainerImageNodeID = report.MakeContainerNodeID(ClientHostID, ClientContainerImageID)
	ServerContainerImageNodeID = report.MakeContainerNodeID(ServerHostID, ServerContainerImageID)

	ClientAddressNodeID   = report.MakeAddressNodeID(ClientHostID, "10.10.10.20")
	ServerAddressNodeID   = report.MakeAddressNodeID(ServerHostID, "192.168.1.1")
	UnknownAddress1NodeID = report.MakeAddressNodeID(ServerHostID, "10.10.10.10")
	UnknownAddress2NodeID = report.MakeAddressNodeID(ServerHostID, "10.10.10.11")
	RandomAddressNodeID   = report.MakeAddressNodeID(ServerHostID, "51.52.53.54") // this should become an internet node

	Report = report.Report{
		Endpoint: report.Topology{
			Adjacency: report.Adjacency{
				report.MakeAdjacencyID(Client54001NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(Client54002NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(Server80NodeID): report.MakeIDList(
					Client54001NodeID, Client54002NodeID, UnknownClient1NodeID, UnknownClient2NodeID,
					UnknownClient3NodeID, RandomClientNodeID),
			},
			NodeMetadatas: report.NodeMetadatas{
				// NodeMetadata is arbitrary. We're free to put only precisely what we
				// care to test into the fixture. Just be sure to include the bits
				// that the mapping funcs extract :)
				Client54001NodeID: report.NodeMetadata{
					"addr":            ClientIP,
					"port":            ClientPort54001,
					"pid":             ClientPID,
					report.HostNodeID: ClientHostNodeID,
				},
				serverHostNodeID: report.MakeNodeWith(map[string]string{
					report.HostNodeID: serverHostNodeID,
				}).WithSets(report.Sets{
					host.LocalNetworks: report.MakeStringSet("192.168.0.0/16"),
				}),
			},
		},
	}

	want = (render.RenderableNodes{
		render.TheInternetID: {
			ID:         render.TheInternetID,
			LabelMajor: render.TheInternetMajor,
			Pseudo:     true,
			Node:       report.MakeNode().WithAdjacent(containerID),
			Origins:    report.MakeIDList(randomEndpointNodeID),
		},
		containerID: {
			ID:          containerID,
			LabelMajor:  containerName,
			LabelMinor:  serverHostID,
			Rank:        "",
			Pseudo:      false,
			Origins:     report.MakeIDList(containerNodeID, serverEndpointNodeID, serverHostNodeID),
			Node:        report.MakeNode(),
			ControlNode: containerNodeID,
		},
	}).Prune()
)

func TestShortLivedInternetNodeConnections(t *testing.T) {
Example #23
0
// Render transforms a given Report into a set of RenderableNodes, which
// the UI will render collectively as a graph. Note that a RenderableNode will
// always be rendered with other nodes, and therefore contains limited detail.
//
// Nodes with the same mapped IDs will be merged.
func (m LeafMap) Render(rpt report.Report) RenderableNodes {
	var (
		t             = m.Selector(rpt)
		nodes         = RenderableNodes{}
		localNetworks = LocalNetworks(rpt)
	)

	// Build a set of RenderableNodes for all non-pseudo probes, and an
	// addressID to nodeID lookup map. Multiple addressIDs can map to the same
	// RenderableNodes.
	source2mapped := map[string]report.IDList{} // source node ID -> mapped node IDs
	for nodeID, metadata := range t.NodeMetadatas {
		for _, mapped := range m.Mapper(metadata) {
			// mapped.ID needs not be unique over all addressIDs. If not, we merge with
			// the existing data, on the assumption that the MapFunc returns the same
			// data.
			existing, ok := nodes[mapped.ID]
			if ok {
				mapped.Merge(existing)
			}

			origins := mapped.Origins
			origins = origins.Add(nodeID)
			origins = origins.Add(metadata.Metadata[report.HostNodeID])
			mapped.Origins = origins

			nodes[mapped.ID] = mapped
			source2mapped[nodeID] = source2mapped[nodeID].Add(mapped.ID)
		}
	}

	mkPseudoNode := func(srcNodeID, dstNodeID string, srcIsClient bool) report.IDList {
		pseudoNode, ok := m.Pseudo(srcNodeID, dstNodeID, srcIsClient, localNetworks)
		if !ok {
			return report.MakeIDList()
		}
		pseudoNode.Origins = pseudoNode.Origins.Add(srcNodeID)
		existing, ok := nodes[pseudoNode.ID]
		if ok {
			pseudoNode.Merge(existing)
		}

		nodes[pseudoNode.ID] = pseudoNode
		source2mapped[pseudoNode.ID] = source2mapped[pseudoNode.ID].Add(srcNodeID)
		return report.MakeIDList(pseudoNode.ID)
	}

	// Walk the graph and make connections.
	for src, dsts := range t.Adjacency {
		srcNodeID, ok := report.ParseAdjacencyID(src)
		if !ok {
			log.Printf("bad adjacency ID %q", src)
			continue
		}

		srcRenderableIDs, ok := source2mapped[srcNodeID]
		if !ok {
			// One of the entries in dsts must be a non-pseudo node, unless
			// it was dropped by the mapping function.
			for _, dstNodeID := range dsts {
				if _, ok := source2mapped[dstNodeID]; ok {
					srcRenderableIDs = mkPseudoNode(srcNodeID, dstNodeID, true)
					break
				}
			}
		}
		if len(srcRenderableIDs) == 0 {
			continue
		}

		for _, srcRenderableID := range srcRenderableIDs {
			srcRenderableNode := nodes[srcRenderableID]

			for _, dstNodeID := range dsts {
				dstRenderableIDs, ok := source2mapped[dstNodeID]
				if !ok {
					dstRenderableIDs = mkPseudoNode(dstNodeID, srcNodeID, false)
				}
				if len(dstRenderableIDs) == 0 {
					continue
				}
				for _, dstRenderableID := range dstRenderableIDs {
					dstRenderableNode := nodes[dstRenderableID]
					srcRenderableNode.Adjacency = srcRenderableNode.Adjacency.Add(dstRenderableID)

					// We propagate edge metadata to nodes on both ends of the edges.
					// TODO we should 'reverse' one end of the edge meta data - ingress -> egress etc.
					if md, ok := t.EdgeMetadatas[report.MakeEdgeID(srcNodeID, dstNodeID)]; ok {
						srcRenderableNode.EdgeMetadata = srcRenderableNode.EdgeMetadata.Merge(md)
						dstRenderableNode.EdgeMetadata = dstRenderableNode.EdgeMetadata.Merge(md)
						nodes[dstRenderableID] = dstRenderableNode
					}
				}
			}

			nodes[srcRenderableID] = srcRenderableNode
		}
	}

	return nodes
}
Example #24
0
		Pseudo:            true,
		AggregateMetadata: render.AggregateMetadata{},
	}

	ClientProcessID       = render.MakeProcessID(test.ClientHostID, test.ClientPID)
	ServerProcessID       = render.MakeProcessID(test.ServerHostID, test.ServerPID)
	nonContainerProcessID = render.MakeProcessID(test.ServerHostID, test.NonContainerPID)

	RenderedProcesses = render.RenderableNodes{
		ClientProcessID: {
			ID:         ClientProcessID,
			LabelMajor: "curl",
			LabelMinor: fmt.Sprintf("%s (%s)", test.ClientHostID, test.ClientPID),
			Rank:       test.ClientPID,
			Pseudo:     false,
			Adjacency:  report.MakeIDList(ServerProcessID),
			Origins: report.MakeIDList(
				test.Client54001NodeID,
				test.Client54002NodeID,
				test.ClientProcessNodeID,
				test.ClientHostNodeID,
			),
			AggregateMetadata: render.AggregateMetadata{
				render.KeyBytesIngress: 300,
				render.KeyBytesEgress:  30,
			},
		},
		ServerProcessID: {
			ID:         ServerProcessID,
			LabelMajor: "apache",
			LabelMinor: fmt.Sprintf("%s (%s)", test.ServerHostID, test.ServerPID),
Example #25
0
func TestMergeAdjacency(t *testing.T) {
	for name, c := range map[string]struct {
		a, b, want report.Adjacency
	}{
		"Empty b": {
			a: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(":192.168.1.2:80"),
				"hostA|:192.168.1.1:8888":  report.MakeIDList(":1.2.3.4:22"),
				"hostB|:192.168.1.2:80":    report.MakeIDList(":192.168.1.1:12345"),
			},
			b: report.Adjacency{},
			want: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(":192.168.1.2:80"),
				"hostA|:192.168.1.1:8888":  report.MakeIDList(":1.2.3.4:22"),
				"hostB|:192.168.1.2:80":    report.MakeIDList(":192.168.1.1:12345"),
			},
		},
		"Empty a": {
			a: report.Adjacency{},
			b: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(":192.168.1.2:80"),
				"hostA|:192.168.1.1:8888":  report.MakeIDList(":1.2.3.4:22"),
				"hostB|:192.168.1.2:80":    report.MakeIDList(":192.168.1.1:12345"),
			},
			want: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(":192.168.1.2:80"),
				"hostA|:192.168.1.1:8888":  report.MakeIDList(":1.2.3.4:22"),
				"hostB|:192.168.1.2:80":    report.MakeIDList(":192.168.1.1:12345"),
			},
		},
		"Same address": {
			a: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(":192.168.1.2:80"),
			},
			b: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(":192.168.1.2:8080"),
			},
			want: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(
					":192.168.1.2:80", ":192.168.1.2:8080",
				),
			},
		},
		"No duplicates": {
			a: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(
					":192.168.1.2:80",
					":192.168.1.2:8080",
					":192.168.1.2:555",
				),
			},
			b: report.Adjacency{
				"hostA|:192.168.1.1:12345": report.MakeIDList(
					":192.168.1.2:8080",
					":192.168.1.2:80",
					":192.168.1.2:444",
				),
			},
			want: report.Adjacency{
				"hostA|:192.168.1.1:12345": []string{
					":192.168.1.2:444",
					":192.168.1.2:555",
					":192.168.1.2:80",
					":192.168.1.2:8080",
				},
			},
		},
		"Double keys": {
			a: report.Adjacency{
				"key1": report.MakeIDList("a", "c", "d", "b"),
				"key2": report.MakeIDList("c", "a"),
			},
			b: report.Adjacency{
				"key1": report.MakeIDList("a", "b", "e"),
				"key3": report.MakeIDList("e", "a", "a", "a", "e"),
			},
			want: report.Adjacency{
				"key1": report.MakeIDList("a", "b", "c", "d", "e"),
				"key2": report.MakeIDList("a", "c"),
				"key3": report.MakeIDList("a", "e"),
			},
		},
	} {
		if have := c.a.Merge(c.b); !reflect.DeepEqual(c.want, have) {
			t.Errorf("%s: want\n\t%#v\nhave\n\t%#v", name, c.want, have)
		}
	}
}
Example #26
0
func TestMapEdge(t *testing.T) {
	selector := render.TopologySelector(func(_ report.Report) render.RenderableNodes {
		return render.MakeRenderableNodes(report.Topology{
			Nodes: report.Nodes{
				"foo": report.MakeNode().WithMetadata(map[string]string{
					"id": "foo",
				}).WithEdge("bar", report.EdgeMetadata{
					EgressPacketCount: newu64(1),
					EgressByteCount:   newu64(2),
				}),

				"bar": report.MakeNode().WithMetadata(map[string]string{
					"id": "bar",
				}).WithEdge("foo", report.EdgeMetadata{
					EgressPacketCount: newu64(3),
					EgressByteCount:   newu64(4),
				}),
			},
		})
	})

	mapper := render.Map{
		MapFunc: func(node render.RenderableNode, _ report.Networks) render.RenderableNodes {
			id := "_" + node.ID
			return render.RenderableNodes{id: render.NewDerivedNode(id, node)}
		},
		Renderer: selector,
	}

	have := mapper.Render(report.MakeReport()).Prune()
	want := (render.RenderableNodes{
		"_foo": {
			ID:      "_foo",
			Origins: report.MakeIDList("foo"),
			Node:    report.MakeNode().WithAdjacent("_bar"),
			EdgeMetadata: report.EdgeMetadata{
				EgressPacketCount:  newu64(1),
				EgressByteCount:    newu64(2),
				IngressPacketCount: newu64(3),
				IngressByteCount:   newu64(4),
			},
		},
		"_bar": {
			ID:      "_bar",
			Origins: report.MakeIDList("bar"),
			Node:    report.MakeNode().WithAdjacent("_foo"),
			EdgeMetadata: report.EdgeMetadata{
				EgressPacketCount:  newu64(3),
				EgressByteCount:    newu64(4),
				IngressPacketCount: newu64(1),
				IngressByteCount:   newu64(2),
			},
		},
	}).Prune()
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}

	if want, have := (report.EdgeMetadata{
		EgressPacketCount: newu64(1),
		EgressByteCount:   newu64(2),
	}), mapper.EdgeMetadata(report.MakeReport(), "_foo", "_bar"); !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
Example #27
0
	ServerContainerImageID     = "imageid456"
	ClientContainerImageNodeID = report.MakeContainerNodeID(ClientHostID, ClientContainerImageID)
	ServerContainerImageNodeID = report.MakeContainerNodeID(ServerHostID, ServerContainerImageID)
	ClientContainerImageName   = "image/client"
	ServerContainerImageName   = "image/server"

	ClientAddressNodeID   = report.MakeAddressNodeID(ClientHostID, "10.10.10.20")
	ServerAddressNodeID   = report.MakeAddressNodeID(ServerHostID, "192.168.1.1")
	UnknownAddress1NodeID = report.MakeAddressNodeID(ServerHostID, "10.10.10.10")
	UnknownAddress2NodeID = report.MakeAddressNodeID(ServerHostID, "10.10.10.11")
	RandomAddressNodeID   = report.MakeAddressNodeID(ServerHostID, "51.52.53.54") // this should become an internet node

	Report = report.Report{
		Endpoint: report.Topology{
			Adjacency: report.Adjacency{
				report.MakeAdjacencyID(Client54001NodeID):    report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(Client54002NodeID):    report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(UnknownClient1NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(UnknownClient2NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(UnknownClient3NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(RandomClientNodeID):   report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(NonContainerNodeID):   report.MakeIDList(GoogleEndpointNodeID),
			},
			NodeMetadatas: report.NodeMetadatas{
				// NodeMetadata is arbitrary. We're free to put only precisely what we
				// care to test into the fixture. Just be sure to include the bits
				// that the mapping funcs extract :)
				Client54001NodeID: report.MakeNodeMetadataWith(map[string]string{
					endpoint.Addr:     ClientIP,
					endpoint.Port:     ClientPort54001,
					process.PID:       Client1PID,
Example #28
0
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{
		Adjacency: report.Adjacency{
			report.MakeAdjacencyID(srcEndpointNodeID): report.MakeIDList(
				dstEndpointNodeID,
			),
		},
		EdgeMetadatas: report.EdgeMetadatas{
			report.MakeEdgeID(srcEndpointNodeID, dstEndpointNodeID): report.EdgeMetadata{
				EgressPacketCount: newu64(1),
				EgressByteCount:   newu64(256),
			},
		},
		NodeMetadatas: report.NodeMetadatas{
			srcEndpointNodeID: report.MakeNodeMetadata(),
		},
	}), 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{
		Adjacency: report.Adjacency{
			report.MakeAdjacencyID(srcAddressNodeID): report.MakeIDList(
				dstAddressNodeID,
			),
		},
		EdgeMetadatas: report.EdgeMetadatas{
			report.MakeEdgeID(srcAddressNodeID, dstAddressNodeID): report.EdgeMetadata{
				EgressPacketCount: newu64(1),
				EgressByteCount:   newu64(512),
			},
		},
		NodeMetadatas: report.NodeMetadatas{
			srcAddressNodeID: report.MakeNodeMetadata(),
		},
	}), rpt.Address; !reflect.DeepEqual(want, have) {
		t.Errorf("%s", test.Diff(want, have))
	}
}
Example #29
0
var (
	uncontainedServerID  = render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostName)
	unknownPseudoNode1ID = render.MakePseudoNodeID("10.10.10.10", fixture.ServerIP, "80")
	unknownPseudoNode2ID = render.MakePseudoNodeID("10.10.10.11", fixture.ServerIP, "80")
	unknownPseudoNode1   = func(adjacent string) render.RenderableNode {
		return render.RenderableNode{
			ID:         unknownPseudoNode1ID,
			LabelMajor: "10.10.10.10",
			Pseudo:     true,
			Node:       report.MakeNode().WithAdjacent(adjacent),
			EdgeMetadata: report.EdgeMetadata{
				EgressPacketCount: newu64(70),
				EgressByteCount:   newu64(700),
			},
			Origins: report.MakeIDList(
				fixture.UnknownClient1NodeID,
				fixture.UnknownClient2NodeID,
			),
		}
	}
	unknownPseudoNode2 = func(adjacent string) render.RenderableNode {
		return render.RenderableNode{
			ID:         unknownPseudoNode2ID,
			LabelMajor: "10.10.10.11",
			Pseudo:     true,
			Node:       report.MakeNode().WithAdjacent(adjacent),
			EdgeMetadata: report.EdgeMetadata{
				EgressPacketCount: newu64(50),
				EgressByteCount:   newu64(500),
			},
			Origins: report.MakeIDList(
				fixture.UnknownClient3NodeID,