mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
Merge pull request #298 from paulbellamy/154-inspect-connections
Replace "Origin Endpoint" tables with "Connection Details" table
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -70,17 +71,17 @@ func DemoReport(nodeCount int) report.Report {
|
||||
// Endpoint topology
|
||||
if _, ok := r.Endpoint.NodeMetadatas[srcPortID]; !ok {
|
||||
r.Endpoint.NodeMetadatas[srcPortID] = report.NodeMetadata{
|
||||
"pid": "4000",
|
||||
"name": c.srcProc,
|
||||
"domain": "node-" + src,
|
||||
docker.PID: "4000",
|
||||
docker.Name: c.srcProc,
|
||||
docker.Domain: "node-" + src,
|
||||
}
|
||||
}
|
||||
r.Endpoint.Adjacency[srcID] = r.Endpoint.Adjacency[srcID].Add(dstPortID)
|
||||
if _, ok := r.Endpoint.NodeMetadatas[dstPortID]; !ok {
|
||||
r.Endpoint.NodeMetadatas[dstPortID] = report.NodeMetadata{
|
||||
"pid": "4000",
|
||||
"name": c.dstProc,
|
||||
"domain": "node-" + dst,
|
||||
docker.PID: "4000",
|
||||
docker.Name: c.dstProc,
|
||||
docker.Domain: "node-" + dst,
|
||||
}
|
||||
}
|
||||
r.Endpoint.Adjacency[dstID] = r.Endpoint.Adjacency[dstID].Add(srcPortID)
|
||||
@@ -100,13 +101,13 @@ func DemoReport(nodeCount int) report.Report {
|
||||
// Address topology
|
||||
if _, ok := r.Address.NodeMetadatas[srcAddressID]; !ok {
|
||||
r.Address.NodeMetadatas[srcAddressID] = report.NodeMetadata{
|
||||
"name": src,
|
||||
docker.Name: src,
|
||||
}
|
||||
}
|
||||
r.Address.Adjacency[nodeSrcAddressID] = r.Address.Adjacency[nodeSrcAddressID].Add(dstAddressID)
|
||||
if _, ok := r.Address.NodeMetadatas[dstAddressID]; !ok {
|
||||
r.Address.NodeMetadatas[dstAddressID] = report.NodeMetadata{
|
||||
"name": dst,
|
||||
docker.Name: dst,
|
||||
}
|
||||
}
|
||||
r.Address.Adjacency[nodeDstAddressID] = r.Address.Adjacency[nodeDstAddressID].Add(srcAddressID)
|
||||
|
||||
@@ -10,7 +10,12 @@ import (
|
||||
// These constants are keys used in node metadata
|
||||
// TODO: use these constants in report/{mapping.go, detailed_node.go} - pending some circular references
|
||||
const (
|
||||
Addr = "addr"
|
||||
ContainerID = "docker_container_id"
|
||||
Domain = "domain"
|
||||
Name = "name"
|
||||
PID = "pid"
|
||||
Port = "port"
|
||||
)
|
||||
|
||||
// These vars are exported for testing.
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/weaveworks/procspy"
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -80,16 +81,12 @@ func (r *Reporter) addConnection(rpt *report.Report, c *procspy.Connection) {
|
||||
|
||||
if _, ok := rpt.Address.NodeMetadatas[scopedLocal]; !ok {
|
||||
rpt.Address.NodeMetadatas[scopedLocal] = report.NodeMetadata{
|
||||
"name": r.hostName,
|
||||
"addr": c.LocalAddress.String(),
|
||||
docker.Name: r.hostName,
|
||||
docker.Addr: c.LocalAddress.String(),
|
||||
}
|
||||
}
|
||||
|
||||
// Count the TCP connection.
|
||||
edgeMeta := rpt.Address.EdgeMetadatas[edgeKey]
|
||||
edgeMeta.WithConnCountTCP = true
|
||||
edgeMeta.MaxConnCountTCP++
|
||||
rpt.Address.EdgeMetadatas[edgeKey] = edgeMeta
|
||||
countTCPConnection(rpt.Address.EdgeMetadatas, edgeKey)
|
||||
|
||||
if c.Proc.PID > 0 {
|
||||
var (
|
||||
@@ -111,10 +108,14 @@ func (r *Reporter) addConnection(rpt *report.Report, c *procspy.Connection) {
|
||||
|
||||
rpt.Endpoint.NodeMetadatas[scopedLocal] = md
|
||||
}
|
||||
// Count the TCP connection.
|
||||
edgeMeta := rpt.Endpoint.EdgeMetadatas[edgeKey]
|
||||
edgeMeta.WithConnCountTCP = true
|
||||
edgeMeta.MaxConnCountTCP++
|
||||
rpt.Endpoint.EdgeMetadatas[edgeKey] = edgeMeta
|
||||
|
||||
countTCPConnection(rpt.Endpoint.EdgeMetadatas, edgeKey)
|
||||
}
|
||||
}
|
||||
|
||||
func countTCPConnection(m report.EdgeMetadatas, edgeKey string) {
|
||||
edgeMeta := m[edgeKey]
|
||||
edgeMeta.WithConnCountTCP = true
|
||||
edgeMeta.MaxConnCountTCP++
|
||||
m[edgeKey] = edgeMeta
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/procspy"
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/probe/endpoint"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
@@ -95,7 +96,7 @@ func TestSpyNoProcesses(t *testing.T) {
|
||||
t.Fatalf("want %q, have %q", want, have)
|
||||
}
|
||||
|
||||
if want, have := nodeName, r.Address.NodeMetadatas[scopedLocal]["name"]; want != have {
|
||||
if want, have := nodeName, r.Address.NodeMetadatas[scopedLocal][docker.Name]; want != have {
|
||||
t.Fatalf("want %q, have %q", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
@@ -79,18 +78,17 @@ func MakeDetailedNode(r report.Report, n RenderableNode) DetailedNode {
|
||||
// multiple origins. The ultimate goal here is to generate tables to view
|
||||
// in the UI, so we skip the intermediate representations, but we could
|
||||
// add them later.
|
||||
outer:
|
||||
connections := []Row{}
|
||||
for _, id := range n.Origins {
|
||||
if table, ok := OriginTable(r, id); ok {
|
||||
// TODO there's a bug that yields duplicate tables. Quick fix.
|
||||
for _, existing := range tables {
|
||||
if reflect.DeepEqual(existing, table) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
tables = append(tables, table)
|
||||
} else if nmd, ok := r.Endpoint.NodeMetadatas[id]; ok {
|
||||
connections = append(connections, connectionDetailsRows(r.Endpoint, id, nmd)...)
|
||||
}
|
||||
}
|
||||
if len(connections) > 0 {
|
||||
tables = append(tables, connectionDetailsTable(connections))
|
||||
}
|
||||
|
||||
// Sort tables by rank
|
||||
sort.Sort(tables)
|
||||
@@ -107,9 +105,6 @@ outer:
|
||||
// OriginTable produces a table (to be consumed directly by the UI) based on
|
||||
// an origin ID, which is (optimistically) a node ID in one of our topologies.
|
||||
func OriginTable(r report.Report, originID string) (Table, bool) {
|
||||
if nmd, ok := r.Endpoint.NodeMetadatas[originID]; ok {
|
||||
return endpointOriginTable(nmd)
|
||||
}
|
||||
if nmd, ok := r.Address.NodeMetadatas[originID]; ok {
|
||||
return addressOriginTable(nmd)
|
||||
}
|
||||
@@ -128,22 +123,29 @@ func OriginTable(r report.Report, originID string) (Table, bool) {
|
||||
return Table{}, false
|
||||
}
|
||||
|
||||
func endpointOriginTable(nmd report.NodeMetadata) (Table, bool) {
|
||||
func connectionDetailsRows(endpointTopology report.Topology, originID string, nmd report.NodeMetadata) []Row {
|
||||
rows := []Row{}
|
||||
for _, tuple := range []struct{ key, human string }{
|
||||
{"addr", "Endpoint"},
|
||||
{"port", "Port"},
|
||||
} {
|
||||
if val, ok := nmd[tuple.key]; ok {
|
||||
rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
|
||||
local := fmt.Sprintf("%s:%s", nmd[docker.Addr], nmd[docker.Port])
|
||||
adjacencies := endpointTopology.Adjacency[report.MakeAdjacencyID(originID)]
|
||||
sort.Strings(adjacencies)
|
||||
for _, adj := range adjacencies {
|
||||
if _, address, port, ok := report.ParseEndpointNodeID(adj); ok {
|
||||
rows = append(rows, Row{
|
||||
Key: local,
|
||||
ValueMajor: fmt.Sprintf("%s:%s", address, port),
|
||||
})
|
||||
}
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func connectionDetailsTable(connectionRows []Row) Table {
|
||||
return Table{
|
||||
Title: "Origin Endpoint",
|
||||
Title: "Connection Details",
|
||||
Numeric: false,
|
||||
Rows: rows,
|
||||
Rows: append([]Row{{Key: "Local", ValueMajor: "Remote"}}, connectionRows...),
|
||||
Rank: endpointRank,
|
||||
}, len(rows) > 0
|
||||
}
|
||||
}
|
||||
|
||||
func addressOriginTable(nmd report.NodeMetadata) (Table, bool) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package render_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -13,14 +14,6 @@ func TestOriginTable(t *testing.T) {
|
||||
t.Errorf("unknown origin ID gave unexpected success")
|
||||
}
|
||||
for originID, want := range map[string]render.Table{
|
||||
test.Client54001NodeID: {
|
||||
Title: "Origin Endpoint",
|
||||
Numeric: false,
|
||||
Rows: []render.Row{
|
||||
{"Endpoint", test.ClientIP, ""},
|
||||
{"Port", test.ClientPort54001, ""},
|
||||
},
|
||||
},
|
||||
test.ClientAddressNodeID: {
|
||||
Title: "Origin Address",
|
||||
Numeric: false,
|
||||
@@ -107,11 +100,40 @@ func TestMakeDetailedNode(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Title: "Origin Endpoint",
|
||||
Title: "Connection Details",
|
||||
Numeric: false,
|
||||
Rows: []render.Row{
|
||||
{"Endpoint", test.ServerIP, ""},
|
||||
{"Port", test.ServerPort, ""},
|
||||
{"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),
|
||||
"",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
11
report/id.go
11
report/id.go
@@ -103,6 +103,17 @@ func ParseNodeID(nodeID string) (hostID string, remainder string, ok bool) {
|
||||
return fields[0], fields[1], true
|
||||
}
|
||||
|
||||
// ParseEndpointNodeID produces the host ID, address, and port and remainder
|
||||
// (typically an address) from an endpoint node ID. Note that hostID may be
|
||||
// blank.
|
||||
func ParseEndpointNodeID(endpointNodeID string) (hostID, address, port string, ok bool) {
|
||||
fields := strings.SplitN(endpointNodeID, ScopeDelim, 3)
|
||||
if len(fields) != 3 {
|
||||
return "", "", "", false
|
||||
}
|
||||
return fields[0], fields[1], fields[2], true
|
||||
}
|
||||
|
||||
// ExtractHostID extracts the host id from NodeMetadata
|
||||
func ExtractHostID(m NodeMetadata) string {
|
||||
hostid, _, _ := ParseNodeID(m[HostNodeID])
|
||||
|
||||
@@ -75,6 +75,42 @@ func TestAdjacencyID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEndpointNodeID(t *testing.T) {
|
||||
for _, bad := range []string{
|
||||
clientAddressNodeID,
|
||||
serverAddressNodeID,
|
||||
unknownAddressNodeID,
|
||||
clientHostNodeID,
|
||||
serverHostNodeID,
|
||||
"host.com;1.2.3.4",
|
||||
"a;b",
|
||||
"a;",
|
||||
";b",
|
||||
";",
|
||||
"",
|
||||
} {
|
||||
if haveName, haveAddress, havePort, ok := report.ParseEndpointNodeID(bad); ok {
|
||||
t.Errorf("%q: expected failure, but got {%q, %q, %q}", bad, haveName, haveAddress, havePort)
|
||||
}
|
||||
}
|
||||
|
||||
for input, want := range map[string]struct{ name, address, port string }{
|
||||
report.MakeEndpointNodeID("host.com", "1.2.3.4", "c"): {"", "1.2.3.4", "c"},
|
||||
"a;b;c": {"a", "b", "c"},
|
||||
} {
|
||||
haveName, haveAddress, havePort, ok := report.ParseEndpointNodeID(input)
|
||||
if !ok {
|
||||
t.Errorf("%q: not OK", input)
|
||||
continue
|
||||
}
|
||||
if want.name != haveName ||
|
||||
want.address != haveAddress ||
|
||||
want.port != havePort {
|
||||
t.Errorf("%q: want %q, have {%q, %q, %q}", input, want, haveName, haveAddress, havePort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEdgeID(t *testing.T) {
|
||||
for _, bad := range []string{
|
||||
client54001EndpointNodeID,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -223,84 +224,84 @@ func TestMergeNodeMetadatas(t *testing.T) {
|
||||
a: report.NodeMetadatas{},
|
||||
b: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
want: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Empty b": {
|
||||
a: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
b: report.NodeMetadatas{},
|
||||
want: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Simple merge": {
|
||||
a: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
b: report.NodeMetadatas{
|
||||
":192.168.1.2:12345": report.NodeMetadata{
|
||||
"pid": "42",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "42",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
want: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
":192.168.1.2:12345": report.NodeMetadata{
|
||||
"pid": "42",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "42",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Merge conflict": {
|
||||
a: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
b: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{ // <-- same ID
|
||||
"pid": "0",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "0",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
want: report.NodeMetadatas{
|
||||
":192.168.1.1:12345": report.NodeMetadata{
|
||||
"pid": "23128",
|
||||
"name": "curl",
|
||||
"domain": "node-a.local",
|
||||
docker.PID: "23128",
|
||||
docker.Name: "curl",
|
||||
docker.Domain: "node-a.local",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,11 +12,18 @@ var (
|
||||
ServerHostID = "server.hostname.com"
|
||||
UnknownHostID = ""
|
||||
|
||||
ClientIP = "10.10.10.20"
|
||||
ServerIP = "192.168.1.1"
|
||||
ClientPort54001 = "54001"
|
||||
ClientPort54002 = "54002"
|
||||
ServerPort = "80"
|
||||
ClientIP = "10.10.10.20"
|
||||
ServerIP = "192.168.1.1"
|
||||
ClientPort54001 = "54001"
|
||||
ClientPort54010 = "54010"
|
||||
ClientPort54002 = "54002"
|
||||
ClientPort54020 = "54020"
|
||||
ClientPort12345 = "12345"
|
||||
ServerPort = "80"
|
||||
UnknownClient1IP = "10.10.10.10"
|
||||
UnknownClient2IP = "10.10.10.10"
|
||||
UnknownClient3IP = "10.10.10.11"
|
||||
RandomClientIP = "51.52.53.54"
|
||||
|
||||
ClientHostName = ClientHostID
|
||||
ServerHostName = ServerHostID
|
||||
@@ -32,10 +39,10 @@ var (
|
||||
Client54001NodeID = report.MakeEndpointNodeID(ClientHostID, ClientIP, ClientPort54001) // curl (1)
|
||||
Client54002NodeID = report.MakeEndpointNodeID(ClientHostID, ClientIP, ClientPort54002) // curl (2)
|
||||
Server80NodeID = report.MakeEndpointNodeID(ServerHostID, ServerIP, ServerPort) // apache
|
||||
UnknownClient1NodeID = report.MakeEndpointNodeID(ServerHostID, "10.10.10.10", "54010") // we want to ensure two unknown clients, connnected
|
||||
UnknownClient2NodeID = report.MakeEndpointNodeID(ServerHostID, "10.10.10.10", "54020") // to the same server, are deduped.
|
||||
UnknownClient3NodeID = report.MakeEndpointNodeID(ServerHostID, "10.10.10.11", "54020") // Check this one isn't deduped
|
||||
RandomClientNodeID = report.MakeEndpointNodeID(ServerHostID, "51.52.53.54", "12345") // this should become an internet node
|
||||
UnknownClient1NodeID = report.MakeEndpointNodeID(ServerHostID, UnknownClient1IP, "54010") // we want to ensure two unknown clients, connnected
|
||||
UnknownClient2NodeID = report.MakeEndpointNodeID(ServerHostID, UnknownClient2IP, "54020") // to the same server, are deduped.
|
||||
UnknownClient3NodeID = report.MakeEndpointNodeID(ServerHostID, UnknownClient3IP, "54020") // Check this one isn't deduped
|
||||
RandomClientNodeID = report.MakeEndpointNodeID(ServerHostID, RandomClientIP, "12345") // this should become an internet node
|
||||
|
||||
ClientProcess1NodeID = report.MakeProcessNodeID(ClientHostID, Client1PID)
|
||||
ClientProcess2NodeID = report.MakeProcessNodeID(ClientHostID, Client2PID)
|
||||
|
||||
Reference in New Issue
Block a user