Beispiel #1
0
func TestAdjacencyID(t *testing.T) {
	for _, bad := range []string{
		client54001EndpointNodeID,
		client54002EndpointNodeID,
		unknown1EndpointNodeID,
		unknown2EndpointNodeID,
		unknown3EndpointNodeID,
		clientAddressNodeID,
		serverAddressNodeID,
		unknownAddressNodeID,
		clientHostNodeID,
		serverHostNodeID,
		";",
		"",
	} {
		if srcNodeID, ok := report.ParseAdjacencyID(bad); ok {
			t.Errorf("%q: expected failure, but got (%q)", bad, srcNodeID)
		}
	}

	for input, want := range map[string]struct{ srcNodeID string }{
		report.MakeAdjacencyID(report.MakeEndpointNodeID("a", "b", "c")): {report.MakeEndpointNodeID("a", "b", "c")},
		report.MakeAdjacencyID(report.MakeAddressNodeID("a", "b")):       {report.MakeAddressNodeID("a", "b")},
		report.MakeAdjacencyID(report.MakeProcessNodeID("a", "b")):       {report.MakeProcessNodeID("a", "b")},
		report.MakeAdjacencyID(report.MakeHostNodeID("a")):               {report.MakeHostNodeID("a")},
		">host.com;1.2.3.4":                                              {"host.com;1.2.3.4"},
		">a;b;c":                                                         {"a;b;c"},
		">a;b":                                                           {"a;b"},
		">a;":                                                            {"a;"},
		">;b":                                                            {";b"},
		">;":                                                             {";"},
	} {
		srcNodeID, ok := report.ParseAdjacencyID(input)
		if !ok {
			t.Errorf("%q: not OK", input)
			continue
		}
		if want, have := want.srcNodeID, srcNodeID; want != have {
			t.Errorf("%q: want %q, have %q", input, want, have)
		}
	}
}
Beispiel #2
0
func connectionDetailsRows(topology report.Topology, originID string) []Row {
	rows := []Row{}
	labeler := func(nodeID string) (string, bool) {
		if _, addr, port, ok := report.ParseEndpointNodeID(nodeID); ok {
			return fmt.Sprintf("%s:%s", addr, port), true
		}
		if _, addr, ok := report.ParseAddressNodeID(nodeID); ok {
			return addr, true
		}
		return "", false
	}
	local, ok := labeler(originID)
	if !ok {
		return rows
	}
	// Firstly, collection outgoing connections from this node.
	originAdjID := report.MakeAdjacencyID(originID)
	for _, serverNodeID := range topology.Adjacency[originAdjID] {
		remote, ok := labeler(serverNodeID)
		if !ok {
			continue
		}
		rows = append(rows, Row{
			Key:        local,
			ValueMajor: remote,
			Expandable: true,
		})
	}
	// Next, scan the topology for incoming connections to this node.
	for clientAdjID, serverNodeIDs := range topology.Adjacency {
		if clientAdjID == originAdjID {
			continue
		}
		if !serverNodeIDs.Contains(originID) {
			continue
		}
		clientNodeID, ok := report.ParseAdjacencyID(clientAdjID)
		if !ok {
			continue
		}
		remote, ok := labeler(clientNodeID)
		if !ok {
			continue
		}
		rows = append(rows, Row{
			Key:        remote,
			ValueMajor: local,
			Expandable: true,
		})
	}
	return rows
}
Beispiel #3
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]string{} // source node ID -> mapped node ID
	for nodeID, metadata := range t.NodeMetadatas {
		mapped, ok := m.Mapper(metadata)
		if !ok {
			continue
		}

		// 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[report.HostNodeID])
		mapped.Origins = origins

		nodes[mapped.ID] = mapped
		source2mapped[nodeID] = mapped.ID
	}

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

		for _, dstNodeID := range dsts {
			dstRenderableID, ok := source2mapped[dstNodeID]
			if !ok {
				pseudoNode, ok := m.Pseudo(srcNodeID, srcRenderableNode, dstNodeID, localNetworks)
				if !ok {
					continue
				}
				dstRenderableID = pseudoNode.ID
				nodes[dstRenderableID] = pseudoNode
				source2mapped[dstNodeID] = dstRenderableID
			}

			srcRenderableNode.Adjacency = srcRenderableNode.Adjacency.Add(dstRenderableID)
			srcRenderableNode.Origins = srcRenderableNode.Origins.Add(srcNodeID)
			edgeID := report.MakeEdgeID(srcNodeID, dstNodeID)
			if md, ok := t.EdgeMetadatas[edgeID]; ok {
				srcRenderableNode.AggregateMetadata.Merge(AggregateMetadataOf(md))
			}
		}

		nodes[srcRenderableID] = srcRenderableNode
	}

	return nodes
}
Beispiel #4
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
}