Update detail node logic to deal with connection directionality; also correctly merge edge metadata for pseudo nodes.

This commit is contained in:
Tom Wilkie
2015-08-17 12:46:11 +00:00
parent 60d1b503c1
commit 7fb1a98eca
4 changed files with 131 additions and 76 deletions

View File

@@ -48,6 +48,23 @@ type Row struct {
ValueMinor string `json:"value_minor,omitempty"` // e.g. KB/s
}
type rows []Row
func (r rows) Len() int { return len(r) }
func (r rows) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r rows) Less(i, j int) bool {
switch {
case r[i].Key != r[j].Key:
return r[i].Key < r[j].Key
case r[i].ValueMajor != r[j].ValueMajor:
return r[i].ValueMajor < r[j].ValueMajor
default:
return r[i].ValueMinor < r[j].ValueMinor
}
}
type tables []Table
func (t tables) Len() int { return len(t) }
@@ -118,6 +135,7 @@ func MakeDetailedNode(r report.Report, n RenderableNode) DetailedNode {
}
}
if len(connections) > 0 {
sort.Sort(rows(connections))
tables = append(tables, connectionDetailsTable(connections))
}
@@ -166,16 +184,26 @@ func connectionDetailsRows(topology report.Topology, originID string) []Row {
if !ok {
return rows
}
adjacencies := topology.Adjacency[report.MakeAdjacencyID(originID)]
sort.Strings(adjacencies)
for _, nodeID := range adjacencies {
if remote, ok := labeler(nodeID); ok {
for _, serverNodeID := range topology.Adjacency[report.MakeAdjacencyID(originID)] {
if remote, ok := labeler(serverNodeID); ok {
rows = append(rows, Row{
Key: local,
ValueMajor: remote,
})
}
}
for clientAdjID, serverNodeIDs := range topology.Adjacency {
if serverNodeIDs.Contains(originID) {
if clientNodeID, ok := report.ParseAdjacencyID(clientAdjID); ok {
if remote, ok := labeler(clientNodeID); ok {
rows = append(rows, Row{
Key: remote,
ValueMajor: local,
})
}
}
}
}
return rows
}
@@ -183,7 +211,7 @@ func connectionDetailsTable(connectionRows []Row) Table {
return Table{
Title: "Connection Details",
Numeric: false,
Rows: append([]Row{{Key: "Local", ValueMajor: "Remote"}}, connectionRows...),
Rows: append([]Row{{Key: "Client", ValueMajor: "Server"}}, connectionRows...),
Rank: endpointRank,
}
}

View File

@@ -1,7 +1,7 @@
package render_test
import (
// "fmt"
"fmt"
"reflect"
"testing"
@@ -121,15 +121,15 @@ func TestMakeDetailedContainerNode(t *testing.T) {
LabelMinor: test.ServerHostName,
Pseudo: false,
Tables: []render.Table{
// {
// Title: "Connections",
// Numeric: true,
// Rank: 100,
// Rows: []render.Row{
// {"Egress packet rate", "75", "packets/sec"},
// {"Egress byte rate", "750", "Bps"},
// },
// },
{
Title: "Connections",
Numeric: true,
Rank: 100,
Rows: []render.Row{
{"Egress packet rate", "105", "packets/sec"},
{"Egress byte rate", "1.0", "KBps"},
},
},
{
Title: "Origin Container",
Numeric: false,
@@ -159,43 +159,43 @@ func TestMakeDetailedContainerNode(t *testing.T) {
{"Operating system", "Linux", ""},
},
},
// {
// Title: "Connection Details",
// Numeric: false,
// Rows: []render.Row{
// {"Local", "Remote", ""},
// {
// fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
// fmt.Sprintf("%s:%s", test.UnknownClient1IP, test.ClientPort54010),
// "",
// },
// {
// fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
// fmt.Sprintf("%s:%s", test.UnknownClient1IP, test.ClientPort54020),
// "",
// },
// {
// fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
// fmt.Sprintf("%s:%s", test.UnknownClient3IP, test.ClientPort54020),
// "",
// },
// {
// fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
// fmt.Sprintf("%s:%s", test.ClientIP, test.ClientPort54001),
// "",
// },
// {
// fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
// fmt.Sprintf("%s:%s", test.ClientIP, test.ClientPort54002),
// "",
// },
// {
// fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
// fmt.Sprintf("%s:%s", test.RandomClientIP, test.ClientPort12345),
// "",
// },
// },
// },
{
Title: "Connection Details",
Numeric: false,
Rows: []render.Row{
{"Client", "Server", ""},
{
fmt.Sprintf("%s:%s", test.UnknownClient1IP, test.ClientPort54010),
fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
"",
},
{
fmt.Sprintf("%s:%s", test.UnknownClient1IP, test.ClientPort54020),
fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
"",
},
{
fmt.Sprintf("%s:%s", test.UnknownClient3IP, test.ClientPort54020),
fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
"",
},
{
fmt.Sprintf("%s:%s", test.ClientIP, test.ClientPort54001),
fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
"",
},
{
fmt.Sprintf("%s:%s", test.ClientIP, test.ClientPort54002),
fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
"",
},
{
fmt.Sprintf("%s:%s", test.RandomClientIP, test.ClientPort12345),
fmt.Sprintf("%s:%s", test.ServerIP, test.ServerPort),
"",
},
},
},
},
}
if !reflect.DeepEqual(want, have) {

View File

@@ -20,8 +20,8 @@ var (
Pseudo: true,
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{
EgressPacketCount: newu64(40),
EgressByteCount: newu64(400),
EgressPacketCount: newu64(70),
EgressByteCount: newu64(700),
},
Adjacency: adjacency,
}
@@ -107,7 +107,10 @@ var (
test.ServerHostNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
EdgeMetadata: report.EdgeMetadata{
EgressPacketCount: newu64(210),
EgressByteCount: newu64(2100),
},
},
nonContainerProcessID: {
ID: nonContainerProcessID,
@@ -162,7 +165,10 @@ var (
test.ServerHostNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
EdgeMetadata: report.EdgeMetadata{
EgressPacketCount: newu64(210),
EgressByteCount: newu64(2100),
},
},
"bash": {
ID: "bash",
@@ -218,7 +224,10 @@ var (
test.ServerHostNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
EdgeMetadata: report.EdgeMetadata{
EgressPacketCount: newu64(210),
EgressByteCount: newu64(2100),
},
},
uncontainedServerID: {
ID: uncontainedServerID,
@@ -273,7 +282,10 @@ var (
test.ServerProcessNodeID,
test.ServerHostNodeID),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
EdgeMetadata: report.EdgeMetadata{
EgressPacketCount: newu64(210),
EgressByteCount: newu64(2100),
},
},
uncontainedServerID: {
ID: uncontainedServerID,
@@ -309,7 +321,9 @@ var (
test.ServerAddressNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
EdgeMetadata: report.EdgeMetadata{
MaxConnCountTCP: newu64(3),
},
},
ClientHostRenderedID: {
ID: ClientHostRenderedID,

View File

@@ -177,6 +177,24 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
source2mapped[nodeID] = mapped.ID
}
mkPseudoNode := func(srcID, dstId string, srcIsClient bool) (string, bool) {
pseudoNode, ok := m.Pseudo(srcID, dstId, srcIsClient, localNetworks)
if !ok {
return "", false
}
// TODO(tomwilkie): we should propagate origin nodes for pseudo nodes.
// Not worth doing until they are selectable in the UI
// pseudoNode.Origins = pseudoNode.Origins.Add(srcID)
existing, ok := nodes[pseudoNode.ID]
if ok {
pseudoNode.Merge(existing)
}
nodes[pseudoNode.ID] = pseudoNode
source2mapped[pseudoNode.ID] = srcID
return pseudoNode.ID, true
}
// Walk the graph and make connections.
for src, dsts := range t.Adjacency {
srcNodeID, ok := report.ParseAdjacencyID(src)
@@ -185,11 +203,8 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
continue
}
var (
srcRenderableID, ok1 = source2mapped[srcNodeID]
srcRenderableNode = nodes[srcRenderableID]
)
if !ok1 {
srcRenderableID, ok := source2mapped[srcNodeID]
if !ok {
// One of the entries in dsts must be a non-pseudo node
var existingDstNodeID string
for _, dstNodeID := range dsts {
@@ -199,33 +214,31 @@ func (m LeafMap) Render(rpt report.Report) RenderableNodes {
}
}
pseudoNode, ok := m.Pseudo(srcNodeID, existingDstNodeID, true, localNetworks)
srcRenderableID, ok = mkPseudoNode(srcNodeID, existingDstNodeID, true)
if !ok {
continue
}
srcRenderableID = pseudoNode.ID
srcRenderableNode = pseudoNode
nodes[srcRenderableID] = srcRenderableNode
source2mapped[srcNodeID] = srcRenderableID
}
srcRenderableNode := nodes[srcRenderableID]
for _, dstNodeID := range dsts {
dstRenderableID, ok := source2mapped[dstNodeID]
if !ok {
pseudoNode, ok := m.Pseudo(dstNodeID, srcNodeID, false, localNetworks)
dstRenderableID, ok = mkPseudoNode(dstNodeID, srcNodeID, false)
if !ok {
continue
}
dstRenderableID = pseudoNode.ID
nodes[dstRenderableID] = pseudoNode
source2mapped[dstNodeID] = dstRenderableID
}
dstRenderableNode := nodes[dstRenderableID]
srcRenderableNode.Adjacency = srcRenderableNode.Adjacency.Add(dstRenderableID)
edgeID := report.MakeEdgeID(srcNodeID, dstNodeID)
if md, ok := t.EdgeMetadatas[edgeID]; ok {
// 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.Merge(md)
dstRenderableNode.EdgeMetadata.Merge(md)
nodes[dstRenderableID] = dstRenderableNode
}
}