mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-17 20:41:51 +00:00
Review Feedback
Squash of: - including children in topologies_test.go - report.Node.Prune should prune children also - rewrote ShortLivedInternetConnections test to express its intent - adding tests for detail Summary rendering
This commit is contained in:
@@ -10,10 +10,11 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/weaveworks/scope/render/detailed"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
func dot(w io.Writer, t report.Nodes) {
|
||||
func dot(w io.Writer, t detailed.NodeSummaries) {
|
||||
fmt.Fprintf(w, "digraph G {\n")
|
||||
fmt.Fprintf(w, "\toutputorder=edgesfirst;\n")
|
||||
fmt.Fprintf(w, "\toverlap=scale;\n")
|
||||
|
||||
@@ -4,10 +4,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/render/detailed"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
func renderTo(rpt report.Report, topology string) (report.Nodes, error) {
|
||||
func renderTo(rpt report.Report, topology string) (detailed.NodeSummaries, error) {
|
||||
renderer, ok := map[string]render.Renderer{
|
||||
"processes": render.FilterUnconnected(render.ProcessWithContainerNameRenderer),
|
||||
"processes-by-name": render.FilterUnconnected(render.ProcessNameRenderer),
|
||||
@@ -16,7 +17,7 @@ func renderTo(rpt report.Report, topology string) (report.Nodes, error) {
|
||||
"hosts": render.HostRenderer,
|
||||
}[topology]
|
||||
if !ok {
|
||||
return report.Nodes{}, fmt.Errorf("unknown topology %v", topology)
|
||||
return detailed.NodeSummaries{}, fmt.Errorf("unknown topology %v", topology)
|
||||
}
|
||||
return renderer.Render(rpt), nil
|
||||
return detailed.Summaries(renderer.Render(rpt)), nil
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ func (m *MetricRow) CodecDecodeSelf(decoder *codec.Decoder) {
|
||||
}
|
||||
|
||||
// NodeMetrics 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.
|
||||
// an a report.Node, which is (hopefully) a node in one of our topologies.
|
||||
func NodeMetrics(n report.Node) []MetricRow {
|
||||
if _, ok := n.Counters.Lookup(n.Topology); ok {
|
||||
// This is a group of nodes, so no metrics!
|
||||
|
||||
@@ -181,11 +181,14 @@ var (
|
||||
func children(n report.Node) []NodeSummaryGroup {
|
||||
summaries := map[string][]NodeSummary{}
|
||||
n.Children.ForEach(func(child report.Node) {
|
||||
if child.ID != n.ID {
|
||||
if summary, ok := MakeNodeSummary(child); ok {
|
||||
summaries[child.Topology] = append(summaries[child.Topology], summary.SummarizeMetrics())
|
||||
}
|
||||
if child.ID == n.ID {
|
||||
return
|
||||
}
|
||||
summary, ok := MakeNodeSummary(child)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
summaries[child.Topology] = append(summaries[child.Topology], summary.SummarizeMetrics())
|
||||
})
|
||||
|
||||
nodeSummaryGroups := []NodeSummaryGroup{}
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestMakeDetailedContainerNode(t *testing.T) {
|
||||
{ID: "docker_image_id", Value: fixture.ServerContainerImageID},
|
||||
},
|
||||
DockerLabels: []detailed.MetadataRow{
|
||||
{ID: "label_" + render.AmazonECSContainerNameLabel, Value: `server`},
|
||||
{ID: "label_" + detailed.AmazonECSContainerNameLabel, Value: `server`},
|
||||
{ID: "label_foo1", Value: `bar1`},
|
||||
{ID: "label_foo2", Value: `bar2`},
|
||||
{ID: "label_io.kubernetes.pod.name", Value: "ping/pong-b"},
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/probe/kubernetes"
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -55,7 +54,7 @@ func Parents(r report.Report, n report.Node) (result []Parent) {
|
||||
}
|
||||
|
||||
func containerParent(n report.Node) Parent {
|
||||
label, _ := render.GetRenderableContainerName(n)
|
||||
label := getRenderableContainerName(n)
|
||||
containerID, _ := n.Latest.Lookup(docker.ContainerID)
|
||||
return Parent{
|
||||
ID: report.MakeContainerNodeID(containerID),
|
||||
|
||||
@@ -20,6 +20,12 @@ const (
|
||||
Heptagon = "heptagon"
|
||||
Hexagon = "hexagon"
|
||||
Cloud = "cloud"
|
||||
|
||||
ImageNameNone = "<none>"
|
||||
|
||||
// Keys we use to render container names
|
||||
AmazonECSContainerNameLabel = "com.amazonaws.ecs.container-name"
|
||||
KubernetesContainerNameLabel = "io.kubernetes.container.name"
|
||||
)
|
||||
|
||||
// NodeSummaryGroup is a topology-typed group of children for a Node.
|
||||
@@ -88,9 +94,7 @@ func MakeNodeSummary(n report.Node) (NodeSummary, bool) {
|
||||
report.Host: hostNodeSummary,
|
||||
}
|
||||
if renderer, ok := renderers[n.Topology]; ok {
|
||||
if summary, ok := baseNodeSummary(NodeSummary{}, n); ok {
|
||||
return renderer(summary, n)
|
||||
}
|
||||
return renderer(baseNodeSummary(n), n)
|
||||
}
|
||||
return NodeSummary{}, false
|
||||
}
|
||||
@@ -129,15 +133,16 @@ func (n NodeSummary) Copy() NodeSummary {
|
||||
return result
|
||||
}
|
||||
|
||||
func baseNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base.ID = n.ID
|
||||
base.Shape = Circle
|
||||
base.Linkable = true
|
||||
base.Metadata = NodeMetadata(n)
|
||||
base.DockerLabels = NodeDockerLabels(n)
|
||||
base.Metrics = NodeMetrics(n)
|
||||
base.Adjacency = n.Adjacency.Copy()
|
||||
return base, true
|
||||
func baseNodeSummary(n report.Node) NodeSummary {
|
||||
return NodeSummary{
|
||||
ID: n.ID,
|
||||
Shape: Circle,
|
||||
Linkable: true,
|
||||
Metadata: NodeMetadata(n),
|
||||
DockerLabels: NodeDockerLabels(n),
|
||||
Metrics: NodeMetrics(n),
|
||||
Adjacency: n.Adjacency.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
func pseudoNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
@@ -158,7 +163,8 @@ func pseudoNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
// try rendering it as an uncontained node
|
||||
if strings.HasPrefix(n.ID, render.MakePseudoNodeID(render.UncontainedID)) {
|
||||
base.Label = render.UncontainedMajor
|
||||
base.Shape = Circle
|
||||
base.Shape = Square
|
||||
base.Stack = true
|
||||
base.LabelMinor = report.ExtractHostID(n)
|
||||
return base, true
|
||||
}
|
||||
@@ -202,7 +208,7 @@ func processNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
}
|
||||
|
||||
func containerNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base.Label, _ = render.GetRenderableContainerName(n)
|
||||
base.Label = getRenderableContainerName(n)
|
||||
|
||||
if c, ok := n.Counters.Lookup(report.Container); ok {
|
||||
base.Stack = true
|
||||
@@ -235,7 +241,7 @@ func containerImageNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bo
|
||||
base.Shape = Hexagon
|
||||
base.Stack = true
|
||||
|
||||
if base.Label == "<none>" {
|
||||
if base.Label == ImageNameNone {
|
||||
base.Label, _ = n.Latest.Lookup(docker.ImageID)
|
||||
if len(base.Label) > 12 {
|
||||
base.Label = base.Label[:12]
|
||||
@@ -356,3 +362,28 @@ func (n NodeSummaries) Copy() NodeSummaries {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getRenderableContainerName obtains a user-friendly container name, to render in the UI
|
||||
func getRenderableContainerName(nmd report.Node) string {
|
||||
for _, key := range []string{
|
||||
// Amazon's ecs-agent produces huge Docker container names, destructively
|
||||
// derived from mangling Container Definition names in Task
|
||||
// Definitions.
|
||||
//
|
||||
// However, the ecs-agent provides a label containing the original Container
|
||||
// Definition name.
|
||||
docker.LabelPrefix + AmazonECSContainerNameLabel,
|
||||
// Kubernetes also mangles its Docker container names and provides a
|
||||
// label with the original container name. However, note that this label
|
||||
// is only provided by Kubernetes versions >= 1.2 (see
|
||||
// https://github.com/kubernetes/kubernetes/pull/17234/ )
|
||||
docker.LabelPrefix + KubernetesContainerNameLabel,
|
||||
docker.ContainerName,
|
||||
docker.ContainerHostname,
|
||||
} {
|
||||
if label, ok := nmd.Latest.Lookup(key); ok {
|
||||
return label
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
186
render/detailed/summary_test.go
Normal file
186
render/detailed/summary_test.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package detailed_test
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/common/mtime"
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/probe/process"
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/render/detailed"
|
||||
"github.com/weaveworks/scope/render/expected"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/test"
|
||||
"github.com/weaveworks/scope/test/fixture"
|
||||
"github.com/weaveworks/scope/test/reflect"
|
||||
)
|
||||
|
||||
func TestSummaries(t *testing.T) {
|
||||
{
|
||||
// Just a convenient source of some rendered nodes
|
||||
have := detailed.Summaries(render.ProcessRenderer.Render(fixture.Report))
|
||||
// The ids of the processes rendered above
|
||||
expectedIDs := []string{
|
||||
fixture.ClientProcess1NodeID,
|
||||
fixture.ClientProcess2NodeID,
|
||||
fixture.ServerProcessNodeID,
|
||||
fixture.NonContainerProcessNodeID,
|
||||
expected.UnknownPseudoNode1ID,
|
||||
expected.UnknownPseudoNode2ID,
|
||||
render.IncomingInternetID,
|
||||
render.OutgoingInternetID,
|
||||
}
|
||||
sort.Strings(expectedIDs)
|
||||
|
||||
// It should summarize each node
|
||||
ids := []string{}
|
||||
for id := range have {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
sort.Strings(ids)
|
||||
if !reflect.DeepEqual(expectedIDs, ids) {
|
||||
t.Fatalf("Expected Summaries to have summarized every node in the process renderer: %v, but got %v", expectedIDs, ids)
|
||||
}
|
||||
}
|
||||
|
||||
// It should summarize nodes' metrics
|
||||
{
|
||||
t1, t2 := mtime.Now().Add(-1*time.Minute), mtime.Now()
|
||||
metric := report.MakeMetric().Add(t1, 1).Add(t2, 2)
|
||||
input := fixture.Report.Copy()
|
||||
|
||||
input.Process.Nodes[fixture.ClientProcess1NodeID] = input.Process.Nodes[fixture.ClientProcess1NodeID].WithMetrics(report.Metrics{process.CPUUsage: metric})
|
||||
have := detailed.Summaries(render.ProcessRenderer.Render(input))
|
||||
|
||||
node, ok := have[fixture.ClientProcess1NodeID]
|
||||
if !ok {
|
||||
t.Fatalf("Expected output to have the node we added the metric to")
|
||||
}
|
||||
|
||||
var row detailed.MetricRow
|
||||
ok = false
|
||||
for _, metric := range node.Metrics {
|
||||
if metric.ID == process.CPUUsage {
|
||||
row = metric
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("Expected node to have the metric we added")
|
||||
}
|
||||
|
||||
// Our summarized MetricRow
|
||||
want := detailed.MetricRow{
|
||||
ID: process.CPUUsage,
|
||||
Format: "percent",
|
||||
Value: 2,
|
||||
Metric: &report.Metric{
|
||||
Samples: nil,
|
||||
Min: metric.Min,
|
||||
Max: metric.Max,
|
||||
First: metric.First,
|
||||
Last: metric.Last,
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(want, row) {
|
||||
t.Fatalf("Expected to have summarized the node's metrics: %s", test.Diff(want, row))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeNodeSummary(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input report.Node
|
||||
ok bool
|
||||
want detailed.NodeSummary
|
||||
}{
|
||||
{
|
||||
name: "single process rendering",
|
||||
input: expected.RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
ok: true,
|
||||
want: detailed.NodeSummary{
|
||||
ID: fixture.ClientProcess1NodeID,
|
||||
Label: fixture.Client1Name,
|
||||
LabelMinor: "client.hostname.com (10001)",
|
||||
Rank: fixture.Client1Name,
|
||||
Shape: "square",
|
||||
Metadata: []detailed.MetadataRow{
|
||||
{ID: process.PID, Value: fixture.Client1PID, Prime: true, Datatype: "number"},
|
||||
},
|
||||
Metrics: []detailed.MetricRow{},
|
||||
Adjacency: report.MakeIDList(fixture.ServerProcessNodeID),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single container rendering",
|
||||
input: expected.RenderedContainers[fixture.ClientContainerNodeID],
|
||||
ok: true,
|
||||
want: detailed.NodeSummary{
|
||||
ID: fixture.ClientContainerNodeID,
|
||||
Label: fixture.ClientContainerName,
|
||||
LabelMinor: fixture.ClientHostName,
|
||||
Rank: fixture.ClientContainerImageName,
|
||||
Shape: "hexagon",
|
||||
Linkable: true,
|
||||
Metadata: []detailed.MetadataRow{
|
||||
{ID: docker.ContainerID, Value: fixture.ClientContainerID, Prime: true},
|
||||
},
|
||||
Metrics: []detailed.MetricRow{},
|
||||
Adjacency: report.MakeIDList(fixture.ServerContainerNodeID),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single container image rendering",
|
||||
input: expected.RenderedContainerImages[fixture.ClientContainerImageNodeID],
|
||||
ok: true,
|
||||
want: detailed.NodeSummary{
|
||||
ID: fixture.ClientContainerImageNodeID,
|
||||
Label: fixture.ClientContainerImageName,
|
||||
LabelMinor: "1 container",
|
||||
Rank: fixture.ClientContainerImageName,
|
||||
Shape: "hexagon",
|
||||
Linkable: true,
|
||||
Stack: true,
|
||||
Metadata: []detailed.MetadataRow{
|
||||
{ID: docker.ImageID, Value: fixture.ClientContainerImageID, Prime: true},
|
||||
{ID: report.Container, Value: "1", Prime: true, Datatype: "number"},
|
||||
},
|
||||
Adjacency: report.MakeIDList(fixture.ServerContainerImageNodeID),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single host rendering",
|
||||
input: expected.RenderedHosts[fixture.ClientHostNodeID],
|
||||
ok: true,
|
||||
want: detailed.NodeSummary{
|
||||
ID: fixture.ClientHostNodeID,
|
||||
Label: "client",
|
||||
LabelMinor: "hostname.com",
|
||||
Rank: "hostname.com",
|
||||
Shape: "circle",
|
||||
Linkable: true,
|
||||
Metadata: []detailed.MetadataRow{
|
||||
{ID: host.HostName, Value: fixture.ClientHostName, Prime: false},
|
||||
},
|
||||
Metrics: []detailed.MetricRow{},
|
||||
Adjacency: report.MakeIDList(fixture.ServerHostNodeID),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
have, ok := detailed.MakeNodeSummary(testcase.input)
|
||||
if ok != testcase.ok {
|
||||
t.Errorf("%s: MakeNodeSummary failed: expected ok value to be: %v", testcase.name, testcase.ok)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(testcase.want, have) {
|
||||
t.Errorf("%s: Node Summary did not match: %s", testcase.name, test.Diff(testcase.want, have))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package expected
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/probe/process"
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/test/fixture"
|
||||
@@ -25,13 +28,41 @@ var (
|
||||
}
|
||||
}
|
||||
pseudo = node(render.Pseudo)
|
||||
endpoint = node("") // TODO: endpoints don't have a topology for some reason? Not being tagged?
|
||||
process = node(report.Process)
|
||||
endpoint = node(report.Endpoint)
|
||||
processNode = node(report.Process)
|
||||
container = node(report.Container)
|
||||
containerImage = node(report.ContainerImage)
|
||||
pod = node(report.Pod)
|
||||
service = node(report.Service)
|
||||
host = node(report.Host)
|
||||
hostNode = node(report.Host)
|
||||
|
||||
UnknownPseudoNode1ID = render.MakePseudoNodeID(fixture.UnknownClient1IP)
|
||||
UnknownPseudoNode2ID = render.MakePseudoNodeID(fixture.UnknownClient3IP)
|
||||
|
||||
unknownPseudoNode1 = func(adjacent ...string) report.Node {
|
||||
return pseudo(UnknownPseudoNode1ID, adjacent...).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.UnknownClient1NodeID],
|
||||
RenderedEndpoints[fixture.UnknownClient2NodeID],
|
||||
))
|
||||
}
|
||||
unknownPseudoNode2 = func(adjacent ...string) report.Node {
|
||||
return pseudo(UnknownPseudoNode2ID, adjacent...).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.UnknownClient3NodeID],
|
||||
))
|
||||
}
|
||||
|
||||
theIncomingInternetNode = func(adjacent ...string) report.Node {
|
||||
return pseudo(render.IncomingInternetID, adjacent...).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.RandomClientNodeID],
|
||||
))
|
||||
}
|
||||
|
||||
theOutgoingInternetNode = pseudo(render.OutgoingInternetID).WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.GoogleEndpointNodeID],
|
||||
))
|
||||
|
||||
RenderedEndpoints = report.Nodes{
|
||||
fixture.Client54001NodeID: endpoint(fixture.Client54001NodeID, fixture.Server80NodeID),
|
||||
@@ -43,81 +74,203 @@ var (
|
||||
fixture.RandomClientNodeID: endpoint(fixture.RandomClientNodeID, fixture.Server80NodeID),
|
||||
fixture.NonContainerNodeID: endpoint(fixture.NonContainerNodeID, fixture.GoogleEndpointNodeID),
|
||||
fixture.GoogleEndpointNodeID: endpoint(fixture.GoogleEndpointNodeID),
|
||||
}.Prune()
|
||||
}
|
||||
|
||||
RenderedProcesses = report.Nodes{
|
||||
fixture.ClientProcess1NodeID: process(fixture.ClientProcess1NodeID, fixture.ServerProcessNodeID),
|
||||
fixture.ClientProcess2NodeID: process(fixture.ClientProcess2NodeID, fixture.ServerProcessNodeID),
|
||||
fixture.ServerProcessNodeID: process(fixture.ServerProcessNodeID),
|
||||
fixture.NonContainerProcessNodeID: process(fixture.NonContainerProcessNodeID, render.OutgoingInternetID),
|
||||
unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServerProcessNodeID),
|
||||
unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServerProcessNodeID),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServerProcessNodeID),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.ClientProcess1NodeID: processNode(fixture.ClientProcess1NodeID, fixture.ServerProcessNodeID).
|
||||
WithLatests(map[string]string{
|
||||
report.HostNodeID: fixture.ClientHostNodeID,
|
||||
process.PID: fixture.Client1PID,
|
||||
process.Name: fixture.Client1Name,
|
||||
}).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
)),
|
||||
|
||||
unknownPseudoNode1ID = render.MakePseudoNodeID(fixture.UnknownClient1IP)
|
||||
unknownPseudoNode2ID = render.MakePseudoNodeID(fixture.UnknownClient3IP)
|
||||
fixture.ClientProcess2NodeID: processNode(fixture.ClientProcess2NodeID, fixture.ServerProcessNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
)),
|
||||
|
||||
fixture.ServerProcessNodeID: processNode(fixture.ServerProcessNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
)),
|
||||
|
||||
fixture.NonContainerProcessNodeID: processNode(fixture.NonContainerProcessNodeID, render.OutgoingInternetID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.NonContainerNodeID],
|
||||
)),
|
||||
|
||||
UnknownPseudoNode1ID: unknownPseudoNode1(fixture.ServerProcessNodeID),
|
||||
UnknownPseudoNode2ID: unknownPseudoNode2(fixture.ServerProcessNodeID),
|
||||
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerProcessNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
|
||||
RenderedProcessNames = report.Nodes{
|
||||
fixture.Client1Name: process(fixture.Client1Name, fixture.ServerName),
|
||||
fixture.ServerName: process(fixture.ServerName),
|
||||
fixture.NonContainerName: process(fixture.NonContainerName, render.OutgoingInternetID),
|
||||
unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServerName),
|
||||
unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServerName),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServerName),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.Client1Name: processNode(fixture.Client1Name, fixture.ServerName).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess2NodeID],
|
||||
)),
|
||||
|
||||
uncontainedServerID = render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID)
|
||||
fixture.ServerName: processNode(fixture.ServerName).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
RenderedProcesses[fixture.ServerProcessNodeID],
|
||||
)),
|
||||
|
||||
fixture.NonContainerName: processNode(fixture.NonContainerName, render.OutgoingInternetID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.NonContainerNodeID],
|
||||
RenderedProcesses[fixture.NonContainerProcessNodeID],
|
||||
)),
|
||||
|
||||
UnknownPseudoNode1ID: unknownPseudoNode1(fixture.ServerName),
|
||||
UnknownPseudoNode2ID: unknownPseudoNode2(fixture.ServerName),
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerName),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
|
||||
uncontainedServerID = render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID)
|
||||
uncontainedServerNode = pseudo(uncontainedServerID, render.OutgoingInternetID).WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.NonContainerNodeID],
|
||||
RenderedProcesses[fixture.NonContainerProcessNodeID],
|
||||
))
|
||||
|
||||
RenderedContainers = report.Nodes{
|
||||
fixture.ClientContainerNodeID: container(fixture.ClientContainerNodeID, fixture.ServerContainerNodeID),
|
||||
fixture.ServerContainerNodeID: container(fixture.ServerContainerNodeID),
|
||||
uncontainedServerID: pseudo(uncontainedServerID, render.OutgoingInternetID),
|
||||
// unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServerContainerNodeID),
|
||||
// unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServerContainerNodeID),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServerContainerNodeID),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.ClientContainerNodeID: container(fixture.ClientContainerNodeID, fixture.ServerContainerNodeID).
|
||||
WithLatests(map[string]string{
|
||||
report.HostNodeID: fixture.ClientHostNodeID,
|
||||
docker.ContainerID: fixture.ClientContainerID,
|
||||
docker.ContainerName: fixture.ClientContainerName,
|
||||
docker.ImageName: fixture.ClientContainerImageName,
|
||||
}).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess2NodeID],
|
||||
)),
|
||||
|
||||
fixture.ServerContainerNodeID: container(fixture.ServerContainerNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
RenderedProcesses[fixture.ServerProcessNodeID],
|
||||
)),
|
||||
|
||||
uncontainedServerID: uncontainedServerNode,
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerContainerNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
|
||||
RenderedContainerImages = report.Nodes{
|
||||
fixture.ClientContainerImageNodeID: containerImage(fixture.ClientContainerImageNodeID, fixture.ServerContainerImageNodeID),
|
||||
fixture.ServerContainerImageNodeID: containerImage(fixture.ServerContainerImageNodeID),
|
||||
uncontainedServerID: pseudo(uncontainedServerID, render.OutgoingInternetID),
|
||||
// unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServerContainerImageNodeID),
|
||||
// unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServerContainerImageNodeID),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServerContainerImageNodeID),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.ClientContainerImageNodeID: containerImage(fixture.ClientContainerImageNodeID, fixture.ServerContainerImageNodeID).
|
||||
WithLatests(map[string]string{
|
||||
report.HostNodeID: fixture.ClientHostNodeID,
|
||||
docker.ImageID: fixture.ClientContainerImageID,
|
||||
docker.ImageName: fixture.ClientContainerImageName,
|
||||
}).
|
||||
WithCounters(map[string]int{
|
||||
report.Container: 1,
|
||||
}).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess2NodeID],
|
||||
RenderedContainers[fixture.ClientContainerNodeID],
|
||||
)),
|
||||
|
||||
RenderedPods = report.Nodes{
|
||||
fixture.ClientPodNodeID: pod(fixture.ClientPodNodeID, fixture.ServerPodNodeID),
|
||||
fixture.ServerPodNodeID: pod(fixture.ServerPodNodeID),
|
||||
uncontainedServerID: pseudo(uncontainedServerID, render.OutgoingInternetID),
|
||||
// unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServerPodNodeID),
|
||||
// unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServerPodNodeID),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServerPodNodeID),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.ServerContainerImageNodeID: containerImage(fixture.ServerContainerImageNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
RenderedProcesses[fixture.ServerProcessNodeID],
|
||||
RenderedContainers[fixture.ServerContainerNodeID],
|
||||
)),
|
||||
|
||||
uncontainedServerID: uncontainedServerNode,
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerContainerImageNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
|
||||
RenderedHosts = report.Nodes{
|
||||
fixture.ClientHostNodeID: host(fixture.ClientHostNodeID, fixture.ServerHostNodeID),
|
||||
fixture.ServerHostNodeID: host(fixture.ServerHostNodeID, render.OutgoingInternetID),
|
||||
unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServerHostNodeID),
|
||||
unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServerHostNodeID),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServerHostNodeID),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.ClientHostNodeID: hostNode(fixture.ClientHostNodeID, fixture.ServerHostNodeID).
|
||||
WithLatests(map[string]string{
|
||||
host.HostName: fixture.ClientHostName,
|
||||
}).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess2NodeID],
|
||||
RenderedContainers[fixture.ClientContainerNodeID],
|
||||
RenderedContainerImages[fixture.ClientContainerImageNodeID],
|
||||
//RenderedPods[fixture.ClientPodNodeID], #1142
|
||||
)),
|
||||
|
||||
fixture.ServerHostNodeID: hostNode(fixture.ServerHostNodeID, render.OutgoingInternetID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
RenderedEndpoints[fixture.NonContainerNodeID],
|
||||
RenderedProcesses[fixture.ServerProcessNodeID],
|
||||
RenderedProcesses[fixture.NonContainerProcessNodeID],
|
||||
RenderedContainers[fixture.ServerContainerNodeID],
|
||||
RenderedContainerImages[fixture.ServerContainerImageNodeID],
|
||||
//RenderedPods[fixture.ServerPodNodeID], #1142
|
||||
)),
|
||||
|
||||
UnknownPseudoNode1ID: unknownPseudoNode1(fixture.ServerHostNodeID),
|
||||
UnknownPseudoNode2ID: unknownPseudoNode2(fixture.ServerHostNodeID),
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerHostNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
|
||||
RenderedPods = report.Nodes{
|
||||
fixture.ClientPodNodeID: pod(fixture.ClientPodNodeID, fixture.ServerPodNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess2NodeID],
|
||||
RenderedContainers[fixture.ClientContainerNodeID],
|
||||
)),
|
||||
|
||||
fixture.ServerPodNodeID: pod(fixture.ServerPodNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
RenderedProcesses[fixture.ServerProcessNodeID],
|
||||
RenderedContainers[fixture.ServerContainerNodeID],
|
||||
)),
|
||||
|
||||
uncontainedServerID: uncontainedServerNode,
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServerPodNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
|
||||
RenderedPodServices = report.Nodes{
|
||||
fixture.ServiceNodeID: service(fixture.ServiceNodeID, fixture.ServiceNodeID),
|
||||
uncontainedServerID: pseudo(uncontainedServerID, render.OutgoingInternetID),
|
||||
// unknownPseudoNode1ID: pseudo(unknownPseudoNode1ID, fixture.ServiceID),
|
||||
// unknownPseudoNode2ID: pseudo(unknownPseudoNode2ID, fixture.ServiceID),
|
||||
render.IncomingInternetID: pseudo(render.IncomingInternetID, fixture.ServiceNodeID),
|
||||
render.OutgoingInternetID: pseudo(render.OutgoingInternetID),
|
||||
}.Prune()
|
||||
fixture.ServiceNodeID: service(fixture.ServiceNodeID, fixture.ServiceNodeID).
|
||||
WithChildren(report.MakeNodeSet(
|
||||
RenderedEndpoints[fixture.Client54001NodeID],
|
||||
RenderedEndpoints[fixture.Client54002NodeID],
|
||||
RenderedEndpoints[fixture.Server80NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess1NodeID],
|
||||
RenderedProcesses[fixture.ClientProcess2NodeID],
|
||||
RenderedProcesses[fixture.ServerProcessNodeID],
|
||||
RenderedContainers[fixture.ClientContainerNodeID],
|
||||
RenderedContainers[fixture.ServerContainerNodeID],
|
||||
RenderedPods[fixture.ClientPodNodeID],
|
||||
RenderedPods[fixture.ServerPodNodeID],
|
||||
)),
|
||||
|
||||
uncontainedServerID: uncontainedServerNode,
|
||||
render.IncomingInternetID: theIncomingInternetNode(fixture.ServiceNodeID),
|
||||
render.OutgoingInternetID: theOutgoingInternetNode,
|
||||
}
|
||||
)
|
||||
|
||||
func newu64(value uint64) *uint64 { return &value }
|
||||
|
||||
@@ -3,6 +3,7 @@ package render
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/weaveworks/scope/common/mtime"
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/probe/endpoint"
|
||||
"github.com/weaveworks/scope/probe/kubernetes"
|
||||
@@ -47,7 +48,7 @@ func ColorConnected(r Renderer) Renderer {
|
||||
|
||||
output := input.Copy()
|
||||
for id := range connected {
|
||||
output[id] = output[id].WithLatests(map[string]string{IsConnected: "true"})
|
||||
output[id] = output[id].WithLatest(IsConnected, mtime.Now(), "true")
|
||||
}
|
||||
return output
|
||||
},
|
||||
|
||||
@@ -28,11 +28,9 @@ const (
|
||||
|
||||
ipsKey = "ips"
|
||||
|
||||
AmazonECSContainerNameLabel = "com.amazonaws.ecs.container-name"
|
||||
KubernetesContainerNameLabel = "io.kubernetes.container.name"
|
||||
|
||||
// Topology for pseudo-nodes so we can differentiate them at the end
|
||||
// Topology for pseudo-nodes and IPs so we can differentiate them at the end
|
||||
Pseudo = "pseudo"
|
||||
IP = "IP"
|
||||
)
|
||||
|
||||
// MapFunc is anything which can take an arbitrary Node and
|
||||
@@ -59,31 +57,6 @@ func theInternetNode(m report.Node) report.Node {
|
||||
return NewDerivedPseudoNode(OutgoingInternetID, m)
|
||||
}
|
||||
|
||||
// GetRenderableContainerName obtains a user-friendly container name, to render in the UI
|
||||
func GetRenderableContainerName(nmd report.Node) (string, bool) {
|
||||
for _, key := range []string{
|
||||
// Amazon's ecs-agent produces huge Docker container names, destructively
|
||||
// derived from mangling Container Definition names in Task
|
||||
// Definitions.
|
||||
//
|
||||
// However, the ecs-agent provides a label containing the original Container
|
||||
// Definition name.
|
||||
docker.LabelPrefix + AmazonECSContainerNameLabel,
|
||||
// Kubernetes also mangles its Docker container names and provides a
|
||||
// label with the original container name. However, note that this label
|
||||
// is only provided by Kubernetes versions >= 1.2 (see
|
||||
// https://github.com/kubernetes/kubernetes/pull/17234/ )
|
||||
docker.LabelPrefix + KubernetesContainerNameLabel,
|
||||
docker.ContainerName,
|
||||
docker.ContainerHostname,
|
||||
} {
|
||||
if label, ok := nmd.Latest.Lookup(key); ok {
|
||||
return label, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// MapEndpoint2IP maps endpoint nodes to their IP address, for joining
|
||||
// with container nodes. We drop endpoint nodes with pids, as they
|
||||
// will be joined to containers through the process topology, and we
|
||||
@@ -110,8 +83,8 @@ func MapEndpoint2IP(m report.Node, local report.Networks) report.Nodes {
|
||||
id := report.MakeScopedEndpointNodeID(scope, addr, "")
|
||||
idWithPort := report.MakeScopedEndpointNodeID(scope, addr, port)
|
||||
return report.Nodes{
|
||||
id: NewDerivedNode(id, m).WithTopology("IP"),
|
||||
idWithPort: NewDerivedNode(idWithPort, m).WithTopology("IP"),
|
||||
id: NewDerivedNode(id, m).WithTopology(IP),
|
||||
idWithPort: NewDerivedNode(idWithPort, m).WithTopology(IP),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +108,7 @@ func MapContainer2IP(m report.Node, _ report.Networks) report.Nodes {
|
||||
}
|
||||
id := report.MakeScopedEndpointNodeID(scope, addr, "")
|
||||
result[id] = NewDerivedNode(id, m).
|
||||
WithTopology("IP").
|
||||
WithTopology(IP).
|
||||
WithLatests(map[string]string{docker.ContainerID: containerID}).
|
||||
WithCounters(map[string]int{ipsKey: 1})
|
||||
|
||||
@@ -150,7 +123,7 @@ func MapContainer2IP(m report.Node, _ report.Networks) report.Nodes {
|
||||
ip, port := mapping[1], mapping[2]
|
||||
id := report.MakeScopedEndpointNodeID("", ip, port)
|
||||
result[id] = NewDerivedNode(id, m).
|
||||
WithTopology("IP").
|
||||
WithTopology(IP).
|
||||
WithLatests(map[string]string{docker.ContainerID: containerID}).
|
||||
WithCounters(map[string]int{ipsKey: 1})
|
||||
|
||||
@@ -226,43 +199,18 @@ func MapEndpoint2Process(n report.Node, local report.Networks) report.Nodes {
|
||||
return MapEndpoint2Pseudo(n, local)
|
||||
}
|
||||
|
||||
pid, ok := n.Latest.LookupEntry(process.PID)
|
||||
pid, timestamp, ok := n.Latest.LookupEntry(process.PID)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
id := report.MakeProcessNodeID(report.ExtractHostID(n), pid.Value)
|
||||
id := report.MakeProcessNodeID(report.ExtractHostID(n), pid)
|
||||
node := NewDerivedNode(id, n).WithTopology(report.Process)
|
||||
node.Latest = node.Latest.Set(process.PID, pid.Timestamp, pid.Value)
|
||||
node.Latest = node.Latest.Set(process.PID, timestamp, pid)
|
||||
node.Counters = node.Counters.Add(n.Topology, 1)
|
||||
return report.Nodes{id: node}
|
||||
}
|
||||
|
||||
// MapTo re-indexes a set of nodes by some key from Latest, changing the topology
|
||||
// TODO(paulbellamy): not sure this works, or is general enough
|
||||
func MapTo(topology, key string) func(report.Node, report.Networks) report.Nodes {
|
||||
return func(n report.Node, local report.Networks) report.Nodes {
|
||||
// Pass through pseudo nodes
|
||||
if n.Topology == Pseudo {
|
||||
fmt.Printf("[DEBUG] MapTo skipping %s %s", n.Topology, n.ID)
|
||||
return report.Nodes{n.ID: n}
|
||||
}
|
||||
|
||||
// Throw away any nodes not having this key
|
||||
entry, ok := n.Latest.LookupEntry(key)
|
||||
if !ok {
|
||||
fmt.Printf("[DEBUG] MapTo skipping %s %s: no key %s", n.Topology, n.ID, key)
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
node := NewDerivedNode(entry.Value, n).WithTopology(topology)
|
||||
node.Latest = node.Latest.Set(key, entry.Timestamp, entry.Value)
|
||||
node.Counters = node.Counters.Add(n.Topology, 1)
|
||||
fmt.Printf("[DEBUG] MapTo %s %s -> %s %s", n.Topology, n.ID, node.Topology, node.ID)
|
||||
return report.Nodes{entry.Value: node}
|
||||
}
|
||||
}
|
||||
|
||||
// MapProcess2Container maps process Nodes to container
|
||||
// Nodes.
|
||||
//
|
||||
@@ -313,15 +261,15 @@ func MapProcess2Name(n report.Node, _ report.Networks) report.Nodes {
|
||||
return report.Nodes{n.ID: n}
|
||||
}
|
||||
|
||||
name, ok := n.Latest.LookupEntry(process.Name)
|
||||
name, timestamp, ok := n.Latest.LookupEntry(process.Name)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
node := NewDerivedNode(name.Value, n).WithTopology(report.Process)
|
||||
node.Latest = node.Latest.Set(process.Name, name.Timestamp, name.Value)
|
||||
node := NewDerivedNode(name, n).WithTopology(report.Process)
|
||||
node.Latest = node.Latest.Set(process.Name, timestamp, name)
|
||||
node.Counters = node.Counters.Add(n.Topology, 1)
|
||||
return report.Nodes{name.Value: node}
|
||||
return report.Nodes{name: node}
|
||||
}
|
||||
|
||||
// MapContainer2ContainerImage maps container Nodes to container
|
||||
@@ -343,15 +291,15 @@ func MapContainer2ContainerImage(n report.Node, _ report.Networks) report.Nodes
|
||||
|
||||
// Otherwise, if some some reason the container doesn't have a image_id
|
||||
// (maybe slightly out of sync reports), just drop it
|
||||
imageID, ok := n.Latest.LookupEntry(docker.ImageID)
|
||||
imageID, timestamp, ok := n.Latest.LookupEntry(docker.ImageID)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
// Add container id key to the counters, which will later be counted to produce the minor label
|
||||
id := report.MakeContainerImageNodeID(imageID.Value)
|
||||
id := report.MakeContainerImageNodeID(imageID)
|
||||
result := NewDerivedNode(id, n).WithTopology(report.ContainerImage)
|
||||
result.Latest = result.Latest.Set(docker.ImageID, imageID.Timestamp, imageID.Value)
|
||||
result.Latest = result.Latest.Set(docker.ImageID, timestamp, imageID)
|
||||
result.Counters = result.Counters.Add(n.Topology, 1)
|
||||
return report.Nodes{id: result}
|
||||
}
|
||||
@@ -382,13 +330,13 @@ func MapX2Host(n report.Node, _ report.Networks) report.Nodes {
|
||||
if n.Topology == Pseudo {
|
||||
return report.Nodes{}
|
||||
}
|
||||
hostNodeID, ok := n.Latest.LookupEntry(report.HostNodeID)
|
||||
hostNodeID, timestamp, ok := n.Latest.LookupEntry(report.HostNodeID)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
id := report.MakeHostNodeID(report.ExtractHostID(n))
|
||||
result := NewDerivedNode(id, n).WithTopology(report.Host)
|
||||
result.Latest = result.Latest.Set(report.HostNodeID, hostNodeID.Timestamp, hostNodeID.Value)
|
||||
result.Latest = result.Latest.Set(report.HostNodeID, timestamp, hostNodeID)
|
||||
result.Counters = result.Counters.Add(n.Topology, 1)
|
||||
return report.Nodes{id: result}
|
||||
}
|
||||
@@ -397,14 +345,14 @@ func MapX2Host(n report.Node, _ report.Networks) report.Nodes {
|
||||
// host nodes or pseudo nodes.
|
||||
func MapEndpoint2Host(n report.Node, local report.Networks) report.Nodes {
|
||||
// Nodes without a hostid are treated as pseudo nodes
|
||||
hostNodeID, ok := n.Latest.LookupEntry(report.HostNodeID)
|
||||
hostNodeID, timestamp, ok := n.Latest.LookupEntry(report.HostNodeID)
|
||||
if !ok {
|
||||
return MapEndpoint2Pseudo(n, local)
|
||||
}
|
||||
|
||||
id := report.MakeHostNodeID(report.ExtractHostID(n))
|
||||
result := NewDerivedNode(id, n).WithTopology(report.Host)
|
||||
result.Latest = result.Latest.Set(report.HostNodeID, hostNodeID.Timestamp, hostNodeID.Value)
|
||||
result.Latest = result.Latest.Set(report.HostNodeID, timestamp, hostNodeID)
|
||||
result.Counters = result.Counters.Add(n.Topology, 1)
|
||||
return report.Nodes{id: result}
|
||||
}
|
||||
@@ -497,15 +445,15 @@ func MapContainer2Hostname(n report.Node, _ report.Networks) report.Nodes {
|
||||
|
||||
// Otherwise, if some some reason the container doesn't have a hostname
|
||||
// (maybe slightly out of sync reports), just drop it
|
||||
id, ok := n.Latest.LookupEntry(docker.ContainerHostname)
|
||||
id, timestamp, ok := n.Latest.LookupEntry(docker.ContainerHostname)
|
||||
if !ok {
|
||||
return report.Nodes{}
|
||||
}
|
||||
|
||||
node := NewDerivedNode(id.Value, n)
|
||||
node := NewDerivedNode(id, n)
|
||||
node.Latest = node.Latest.
|
||||
Set(docker.ContainerHostname, id.Timestamp, id.Value).
|
||||
Set(docker.ContainerHostname, timestamp, id).
|
||||
Delete(docker.ContainerName) // TODO(paulbellamy): total hack to render these by hostname instead.
|
||||
node.Counters = node.Counters.Add(n.Topology, 1)
|
||||
return report.Nodes{id.Value: node}
|
||||
return report.Nodes{id: node}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package render_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
@@ -10,7 +9,6 @@ import (
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/test"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -68,21 +66,18 @@ var (
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
want = (report.Nodes{
|
||||
render.IncomingInternetID: report.MakeNode().
|
||||
WithID(render.IncomingInternetID).
|
||||
WithTopology(render.Pseudo).
|
||||
WithAdjacent(report.MakeContainerNodeID(containerID)),
|
||||
report.MakeContainerNodeID(containerID): report.MakeNode().
|
||||
WithID(report.MakeContainerNodeID(containerID)).
|
||||
WithTopology(report.Container),
|
||||
})
|
||||
)
|
||||
|
||||
func TestShortLivedInternetNodeConnections(t *testing.T) {
|
||||
have := render.ContainerWithImageNameRenderer.Render(rpt).Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
|
||||
// Conntracked-only connections from the internet should be assigned to the internet pseudonode
|
||||
internet, ok := have[render.IncomingInternetID]
|
||||
if !ok {
|
||||
t.Fatal("Expected output to have an incoming internet node")
|
||||
}
|
||||
|
||||
if !internet.Adjacency.Contains(report.MakeContainerNodeID(containerID)) {
|
||||
t.Errorf("Expected internet node to have adjacency to %s, but only had %v", report.MakeContainerNodeID(containerID), internet.Adjacency)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,18 +34,18 @@ func (r processWithContainerNameRenderer) Render(rpt report.Report) report.Nodes
|
||||
outputs := report.Nodes{}
|
||||
for id, p := range processes {
|
||||
outputs[id] = p
|
||||
containerIDEntry, ok := p.Latest.LookupEntry(docker.ContainerID)
|
||||
containerID, timestamp, ok := p.Latest.LookupEntry(docker.ContainerID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
container, ok := containers[report.MakeContainerNodeID(containerIDEntry.Value)]
|
||||
container, ok := containers[report.MakeContainerNodeID(containerID)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
output := p.Copy()
|
||||
output.Latest = output.Latest.Set(docker.ContainerID, containerIDEntry.Timestamp, containerIDEntry.Value)
|
||||
if entry, ok := container.Latest.LookupEntry(docker.ContainerName); ok {
|
||||
output.Latest = output.Latest.Set(docker.ContainerName, entry.Timestamp, entry.Value)
|
||||
output.Latest = output.Latest.Set(docker.ContainerID, timestamp, containerID)
|
||||
if containerName, timestamp, ok := container.Latest.LookupEntry(docker.ContainerName); ok {
|
||||
output.Latest = output.Latest.Set(docker.ContainerName, timestamp, containerName)
|
||||
}
|
||||
outputs[id] = output
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
func TestEndpointRenderer(t *testing.T) {
|
||||
have := render.EndpointRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedEndpoints
|
||||
want := expected.RenderedEndpoints.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func TestEndpointRenderer(t *testing.T) {
|
||||
|
||||
func TestProcessRenderer(t *testing.T) {
|
||||
have := render.ProcessRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedProcesses
|
||||
want := expected.RenderedProcesses.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func TestProcessRenderer(t *testing.T) {
|
||||
|
||||
func TestProcessNameRenderer(t *testing.T) {
|
||||
have := render.ProcessNameRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedProcessNames
|
||||
want := expected.RenderedProcessNames.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -39,7 +39,7 @@ func TestProcessNameRenderer(t *testing.T) {
|
||||
|
||||
func TestContainerRenderer(t *testing.T) {
|
||||
have := render.ContainerRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedContainers
|
||||
want := expected.RenderedContainers.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func TestContainerFilterRenderer(t *testing.T) {
|
||||
docker.LabelPrefix + "works.weave.role": "system",
|
||||
})
|
||||
have := render.FilterSystem(render.ContainerRenderer).Render(input).Prune()
|
||||
want := expected.RenderedContainers.Copy()
|
||||
want := expected.RenderedContainers.Copy().Prune()
|
||||
delete(want, fixture.ClientContainerNodeID)
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
@@ -84,7 +84,7 @@ func TestContainerWithHostIPsRenderer(t *testing.T) {
|
||||
|
||||
func TestContainerImageRenderer(t *testing.T) {
|
||||
have := render.ContainerImageRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedContainerImages
|
||||
want := expected.RenderedContainerImages.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func TestContainerImageRenderer(t *testing.T) {
|
||||
|
||||
func TestHostRenderer(t *testing.T) {
|
||||
have := render.HostRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedHosts
|
||||
want := expected.RenderedHosts.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -100,7 +100,7 @@ func TestHostRenderer(t *testing.T) {
|
||||
|
||||
func TestPodRenderer(t *testing.T) {
|
||||
have := render.PodRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedPods
|
||||
want := expected.RenderedPods.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func TestPodFilterRenderer(t *testing.T) {
|
||||
docker.LabelPrefix + "io.kubernetes.pod.name": "kube-system/foo",
|
||||
})
|
||||
have := render.FilterSystem(render.PodRenderer).Render(input).Prune()
|
||||
want := expected.RenderedPods.Copy()
|
||||
want := expected.RenderedPods.Copy().Prune()
|
||||
delete(want, fixture.ClientPodNodeID)
|
||||
delete(want, fixture.ClientContainerNodeID)
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
@@ -129,7 +129,7 @@ func TestPodFilterRenderer(t *testing.T) {
|
||||
|
||||
func TestPodServiceRenderer(t *testing.T) {
|
||||
have := render.PodServiceRenderer.Render(fixture.Report).Prune()
|
||||
want := expected.RenderedPodServices
|
||||
want := expected.RenderedPodServices.Prune()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
|
||||
@@ -86,26 +86,21 @@ func (m LatestMap) Merge(other LatestMap) LatestMap {
|
||||
|
||||
// Lookup the value for the given key.
|
||||
func (m LatestMap) Lookup(key string) (string, bool) {
|
||||
if m.Map == nil {
|
||||
return "", false
|
||||
}
|
||||
value, ok := m.Map.Lookup(key)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return value.(LatestEntry).Value, true
|
||||
v, _, ok := m.LookupEntry(key)
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// LookupEntry returns the raw entry for the given key.
|
||||
func (m LatestMap) LookupEntry(key string) (LatestEntry, bool) {
|
||||
func (m LatestMap) LookupEntry(key string) (string, time.Time, bool) {
|
||||
if m.Map == nil {
|
||||
return LatestEntry{}, false
|
||||
return "", time.Time{}, false
|
||||
}
|
||||
value, ok := m.Map.Lookup(key)
|
||||
if !ok {
|
||||
return LatestEntry{}, false
|
||||
return "", time.Time{}, false
|
||||
}
|
||||
return value.(LatestEntry), true
|
||||
e := value.(LatestEntry)
|
||||
return e.Value, e.Timestamp, true
|
||||
}
|
||||
|
||||
// Set the value for the given key.
|
||||
|
||||
@@ -33,11 +33,11 @@ func TestLatestMapLookupEntry(t *testing.T) {
|
||||
now := time.Now()
|
||||
entry := LatestEntry{Timestamp: now, Value: "Bar"}
|
||||
have := EmptyLatestMap.Set("foo", entry.Timestamp, entry.Value)
|
||||
if got, ok := have.LookupEntry("foo"); !ok || got != entry {
|
||||
t.Errorf("got: %#v != expected %#v", got, entry)
|
||||
if got, timestamp, ok := have.LookupEntry("foo"); !ok || got != entry.Value || !timestamp.Equal(entry.Timestamp) {
|
||||
t.Errorf("got: %#v %v != expected %#v", got, timestamp, entry)
|
||||
}
|
||||
if got, ok := have.LookupEntry("not found"); ok {
|
||||
t.Errorf("found unexpected entry for %q: %#v", "not found", got)
|
||||
if got, timestamp, ok := have.LookupEntry("not found"); ok {
|
||||
t.Errorf("found unexpected entry for %q: %#v %v", "not found", got, timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,8 +219,13 @@ func (n Node) Merge(other Node) Node {
|
||||
// for rendering nodes and edges stripped away. Specifically, that means
|
||||
// cutting out parts of the Node.
|
||||
func (n Node) Prune() Node {
|
||||
prunedChildren := MakeNodeSet()
|
||||
n.Children.ForEach(func(child Node) {
|
||||
prunedChildren = prunedChildren.Add(child.Prune())
|
||||
})
|
||||
return MakeNode().
|
||||
WithID(n.ID).
|
||||
WithTopology(n.Topology).
|
||||
WithAdjacent(n.Adjacency.Copy()...)
|
||||
WithAdjacent(n.Adjacency.Copy()...).
|
||||
WithChildren(prunedChildren)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/probe/kubernetes"
|
||||
"github.com/weaveworks/scope/probe/process"
|
||||
"github.com/weaveworks/scope/render"
|
||||
"github.com/weaveworks/scope/render/detailed"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -121,7 +121,7 @@ var (
|
||||
// Node 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.MakeNode().WithID(Client54001NodeID).WithLatests(map[string]string{
|
||||
Client54001NodeID: report.MakeNode().WithID(Client54001NodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: ClientIP,
|
||||
endpoint.Port: ClientPort54001,
|
||||
process.PID: Client1PID,
|
||||
@@ -132,7 +132,7 @@ var (
|
||||
EgressByteCount: newu64(100),
|
||||
}),
|
||||
|
||||
Client54002NodeID: report.MakeNode().WithID(Client54002NodeID).WithLatests(map[string]string{
|
||||
Client54002NodeID: report.MakeNode().WithID(Client54002NodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: ClientIP,
|
||||
endpoint.Port: ClientPort54002,
|
||||
process.PID: Client2PID,
|
||||
@@ -143,7 +143,7 @@ var (
|
||||
EgressByteCount: newu64(200),
|
||||
}),
|
||||
|
||||
Server80NodeID: report.MakeNode().WithID(Server80NodeID).WithLatests(map[string]string{
|
||||
Server80NodeID: report.MakeNode().WithID(Server80NodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: ServerIP,
|
||||
endpoint.Port: ServerPort,
|
||||
process.PID: ServerPID,
|
||||
@@ -151,7 +151,7 @@ var (
|
||||
endpoint.Procspied: True,
|
||||
}),
|
||||
|
||||
NonContainerNodeID: report.MakeNode().WithID(NonContainerNodeID).WithLatests(map[string]string{
|
||||
NonContainerNodeID: report.MakeNode().WithID(NonContainerNodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: ServerIP,
|
||||
endpoint.Port: NonContainerClientPort,
|
||||
process.PID: NonContainerPID,
|
||||
@@ -160,7 +160,7 @@ var (
|
||||
}).WithAdjacent(GoogleEndpointNodeID),
|
||||
|
||||
// Probe pseudo nodes
|
||||
UnknownClient1NodeID: report.MakeNode().WithID(UnknownClient1NodeID).WithLatests(map[string]string{
|
||||
UnknownClient1NodeID: report.MakeNode().WithID(UnknownClient1NodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: UnknownClient1IP,
|
||||
endpoint.Port: UnknownClient1Port,
|
||||
endpoint.Procspied: True,
|
||||
@@ -169,7 +169,7 @@ var (
|
||||
EgressByteCount: newu64(300),
|
||||
}),
|
||||
|
||||
UnknownClient2NodeID: report.MakeNode().WithID(UnknownClient2NodeID).WithLatests(map[string]string{
|
||||
UnknownClient2NodeID: report.MakeNode().WithID(UnknownClient2NodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: UnknownClient2IP,
|
||||
endpoint.Port: UnknownClient2Port,
|
||||
endpoint.Procspied: True,
|
||||
@@ -178,7 +178,7 @@ var (
|
||||
EgressByteCount: newu64(400),
|
||||
}),
|
||||
|
||||
UnknownClient3NodeID: report.MakeNode().WithID(UnknownClient3NodeID).WithLatests(map[string]string{
|
||||
UnknownClient3NodeID: report.MakeNode().WithID(UnknownClient3NodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: UnknownClient3IP,
|
||||
endpoint.Port: UnknownClient3Port,
|
||||
endpoint.Procspied: True,
|
||||
@@ -187,7 +187,7 @@ var (
|
||||
EgressByteCount: newu64(500),
|
||||
}),
|
||||
|
||||
RandomClientNodeID: report.MakeNode().WithID(RandomClientNodeID).WithLatests(map[string]string{
|
||||
RandomClientNodeID: report.MakeNode().WithID(RandomClientNodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: RandomClientIP,
|
||||
endpoint.Port: RandomClientPort,
|
||||
endpoint.Procspied: True,
|
||||
@@ -196,7 +196,7 @@ var (
|
||||
EgressByteCount: newu64(600),
|
||||
}),
|
||||
|
||||
GoogleEndpointNodeID: report.MakeNode().WithID(GoogleEndpointNodeID).WithLatests(map[string]string{
|
||||
GoogleEndpointNodeID: report.MakeNode().WithID(GoogleEndpointNodeID).WithTopology(report.Endpoint).WithLatests(map[string]string{
|
||||
endpoint.Addr: GoogleIP,
|
||||
endpoint.Port: GooglePort,
|
||||
endpoint.Procspied: True,
|
||||
@@ -267,17 +267,17 @@ var (
|
||||
docker.MemoryUsage: ClientContainerMemoryMetric,
|
||||
}),
|
||||
ServerContainerNodeID: report.MakeNodeWith(map[string]string{
|
||||
docker.ContainerID: ServerContainerID,
|
||||
docker.ContainerName: "task-name-5-server-aceb93e2f2b797caba01",
|
||||
docker.ContainerState: docker.StateRunning,
|
||||
docker.ImageID: ServerContainerImageID,
|
||||
report.HostNodeID: ServerHostNodeID,
|
||||
docker.LabelPrefix + render.AmazonECSContainerNameLabel: "server",
|
||||
docker.LabelPrefix + "foo1": "bar1",
|
||||
docker.LabelPrefix + "foo2": "bar2",
|
||||
docker.LabelPrefix + "io.kubernetes.pod.name": ServerPodID,
|
||||
kubernetes.PodID: ServerPodID,
|
||||
kubernetes.Namespace: KubernetesNamespace,
|
||||
docker.ContainerID: ServerContainerID,
|
||||
docker.ContainerName: "task-name-5-server-aceb93e2f2b797caba01",
|
||||
docker.ContainerState: docker.StateRunning,
|
||||
docker.ImageID: ServerContainerImageID,
|
||||
report.HostNodeID: ServerHostNodeID,
|
||||
docker.LabelPrefix + detailed.AmazonECSContainerNameLabel: "server",
|
||||
docker.LabelPrefix + "foo1": "bar1",
|
||||
docker.LabelPrefix + "foo2": "bar2",
|
||||
docker.LabelPrefix + "io.kubernetes.pod.name": ServerPodID,
|
||||
kubernetes.PodID: ServerPodID,
|
||||
kubernetes.Namespace: KubernetesNamespace,
|
||||
}).WithID(ServerContainerNodeID).WithTopology(report.Container).WithParents(report.EmptySets.
|
||||
Add("host", report.MakeStringSet(ServerHostNodeID)).
|
||||
Add("container_image", report.MakeStringSet(ServerContainerImageNodeID)).
|
||||
|
||||
Reference in New Issue
Block a user