Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace "Origin Endpoint" tables with "Connection Details" table #298

Merged
merged 4 commits into from
Jul 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions experimental/demoprobe/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"time"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/report"
)

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions probe/docker/tagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
25 changes: 13 additions & 12 deletions probe/endpoint/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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 (
Expand All @@ -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
}
3 changes: 2 additions & 1 deletion probe/endpoint/reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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)
}
}
Expand Down
44 changes: 23 additions & 21 deletions render/detailed_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package render

import (
"fmt"
"reflect"
"sort"
"strconv"

Expand Down Expand Up @@ -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 {

This comment was marked as abuse.

// 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)
Expand All @@ -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)
}
Expand All @@ -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...),

This comment was marked as abuse.

This comment was marked as abuse.

Rank: endpointRank,
}, len(rows) > 0
}
}

func addressOriginTable(nmd report.NodeMetadata) (Table, bool) {
Expand Down
44 changes: 33 additions & 11 deletions render/detailed_node_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package render_test

import (
"fmt"
"reflect"
"testing"

Expand All @@ -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,
Expand Down Expand Up @@ -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),
"",
},
},
},
},
Expand Down
11 changes: 11 additions & 0 deletions report/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
36 changes: 36 additions & 0 deletions report/id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading