From f03afc3c5ab29a06debe47359c71265eb1026202 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Mon, 1 Feb 2016 17:12:17 -0800 Subject: [PATCH] Backend for node shapes --- render/expected/expected.go | 44 ++++++++++++++++++ render/mapping.go | 63 ++++++++++++++++++++------ render/renderable_node.go | 18 ++++++++ render/short_lived_connections_test.go | 2 + 4 files changed, 112 insertions(+), 15 deletions(-) diff --git a/render/expected/expected.go b/render/expected/expected.go index b4946d7a93..b06079e7b7 100644 --- a/render/expected/expected.go +++ b/render/expected/expected.go @@ -10,6 +10,12 @@ import ( // Exported for testing. var ( + circle = "circle" + square = "square" + pentagon = "pentagon" + hexagon = "hexagon" + cloud = "cloud" + uncontainedServerID = render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostName) unknownPseudoNode1ID = render.MakePseudoNodeID("10.10.10.10", fixture.ServerIP, "80") unknownPseudoNode2ID = render.MakePseudoNodeID("10.10.10.11", fixture.ServerIP, "80") @@ -18,6 +24,7 @@ var ( ID: unknownPseudoNode1ID, LabelMajor: "10.10.10.10", Pseudo: true, + Shape: circle, Node: report.MakeNode().WithAdjacent(adjacent), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(70), @@ -30,6 +37,7 @@ var ( ID: unknownPseudoNode2ID, LabelMajor: "10.10.10.11", Pseudo: true, + Shape: circle, Node: report.MakeNode().WithAdjacent(adjacent), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(50), @@ -42,6 +50,7 @@ var ( ID: render.TheInternetID, LabelMajor: render.TheInternetMajor, Pseudo: true, + Shape: cloud, Node: report.MakeNode().WithAdjacent(adjacent), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(60), @@ -61,6 +70,7 @@ var ( LabelMinor: fmt.Sprintf("%s (%s)", fixture.ClientHostID, fixture.Client1PID), Rank: fixture.Client1Name, Pseudo: false, + Shape: square, Node: report.MakeNode().WithAdjacent(ServerProcessID), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(10), @@ -73,6 +83,7 @@ var ( LabelMinor: fmt.Sprintf("%s (%s)", fixture.ClientHostID, fixture.Client2PID), Rank: fixture.Client2Name, Pseudo: false, + Shape: square, Node: report.MakeNode().WithAdjacent(ServerProcessID), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(20), @@ -85,6 +96,7 @@ var ( LabelMinor: fmt.Sprintf("%s (%s)", fixture.ServerHostID, fixture.ServerPID), Rank: fixture.ServerName, Pseudo: false, + Shape: square, Node: report.MakeNode(), EdgeMetadata: report.EdgeMetadata{ IngressPacketCount: newu64(210), @@ -97,6 +109,7 @@ var ( LabelMinor: fmt.Sprintf("%s (%s)", fixture.ServerHostID, fixture.NonContainerPID), Rank: fixture.NonContainerName, Pseudo: false, + Shape: square, Node: report.MakeNode().WithAdjacent(render.TheInternetID), EdgeMetadata: report.EdgeMetadata{}, }, @@ -116,6 +129,8 @@ var ( LabelMinor: "2 processes", Rank: fixture.Client1Name, Pseudo: false, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID], fixture.Report.Process.Nodes[fixture.ClientProcess2NodeID], @@ -132,6 +147,8 @@ var ( LabelMinor: "1 process", Rank: fixture.ServerName, Pseudo: false, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ServerProcessNodeID], ), @@ -147,6 +164,8 @@ var ( LabelMinor: "1 process", Rank: fixture.NonContainerName, Pseudo: false, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.NonContainerProcessNodeID], ), @@ -168,6 +187,7 @@ var ( LabelMinor: fixture.ClientHostName, Rank: fixture.ClientContainerImageName, Pseudo: false, + Shape: hexagon, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID], fixture.Report.Process.Nodes[fixture.ClientProcess2NodeID], @@ -185,6 +205,7 @@ var ( LabelMinor: fixture.ServerHostName, Rank: fixture.ServerContainerImageName, Pseudo: false, + Shape: hexagon, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ServerProcessNodeID], ), @@ -201,6 +222,8 @@ var ( LabelMinor: fixture.ServerHostName, Rank: "", Pseudo: true, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.NonContainerProcessNodeID], ), @@ -220,6 +243,8 @@ var ( LabelMinor: "1 container", Rank: fixture.ClientContainerImageName, Pseudo: false, + Shape: hexagon, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID], fixture.Report.Process.Nodes[fixture.ClientProcess2NodeID], @@ -237,6 +262,8 @@ var ( LabelMinor: "1 container", Rank: fixture.ServerContainerImageName, Pseudo: false, + Shape: hexagon, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ServerProcessNodeID], fixture.Report.Container.Nodes[fixture.ServerContainerNodeID], @@ -253,6 +280,8 @@ var ( LabelMinor: fixture.ServerHostName, Rank: "", Pseudo: true, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.NonContainerProcessNodeID], ), @@ -274,6 +303,7 @@ var ( LabelMinor: "hostname.com", // after first . Rank: "hostname.com", Pseudo: false, + Shape: circle, Children: report.MakeNodeSet( fixture.Report.Container.Nodes[fixture.ServerContainerNodeID], fixture.Report.Container.Nodes[fixture.ServerProcessNodeID], @@ -291,6 +321,7 @@ var ( LabelMinor: "hostname.com", // after first . Rank: "hostname.com", Pseudo: false, + Shape: circle, Children: report.MakeNodeSet( fixture.Report.Container.Nodes[fixture.ClientContainerNodeID], fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID], @@ -307,6 +338,7 @@ var ( ID: pseudoHostID1, LabelMajor: fixture.UnknownClient1IP, Pseudo: true, + Shape: circle, Node: report.MakeNode().WithAdjacent(ServerHostRenderedID), EdgeMetadata: report.EdgeMetadata{}, Children: report.MakeNodeSet( @@ -318,6 +350,7 @@ var ( ID: pseudoHostID2, LabelMajor: fixture.UnknownClient3IP, Pseudo: true, + Shape: circle, Node: report.MakeNode().WithAdjacent(ServerHostRenderedID), EdgeMetadata: report.EdgeMetadata{}, }, @@ -325,6 +358,7 @@ var ( ID: render.TheInternetID, LabelMajor: render.TheInternetMajor, Pseudo: true, + Shape: cloud, Node: report.MakeNode().WithAdjacent(ServerHostRenderedID), EdgeMetadata: report.EdgeMetadata{}, }, @@ -340,6 +374,7 @@ var ( LabelMinor: "1 container", Rank: "ping/pong-a", Pseudo: false, + Shape: pentagon, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID], fixture.Report.Process.Nodes[fixture.ClientProcess2NodeID], @@ -359,6 +394,7 @@ var ( LabelMinor: "1 container", Rank: "ping/pong-b", Pseudo: false, + Shape: pentagon, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ServerProcessNodeID], fixture.Report.Container.Nodes[fixture.ServerContainerNodeID], @@ -377,6 +413,8 @@ var ( LabelMinor: fixture.ServerHostName, Rank: "", Pseudo: true, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.NonContainerProcessNodeID], ), @@ -387,6 +425,7 @@ var ( ID: render.TheInternetID, LabelMajor: render.TheInternetMajor, Pseudo: true, + Shape: cloud, Node: report.MakeNode().WithAdjacent(ServerPodRenderedID), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(60), @@ -404,6 +443,8 @@ var ( LabelMinor: "2 pods", Rank: fixture.ServiceID, Pseudo: false, + Shape: pentagon, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID], fixture.Report.Process.Nodes[fixture.ClientProcess2NodeID], @@ -429,6 +470,8 @@ var ( LabelMinor: fixture.ServerHostName, Rank: "", Pseudo: true, + Shape: square, + Stack: true, Children: report.MakeNodeSet( fixture.Report.Process.Nodes[fixture.NonContainerProcessNodeID], ), @@ -439,6 +482,7 @@ var ( ID: render.TheInternetID, LabelMajor: render.TheInternetMajor, Pseudo: true, + Shape: cloud, Node: report.MakeNode().WithAdjacent(ServiceRenderedID), EdgeMetadata: report.EdgeMetadata{ EgressPacketCount: newu64(60), diff --git a/render/mapping.go b/render/mapping.go index 3c4f0ad526..bee94dba5a 100644 --- a/render/mapping.go +++ b/render/mapping.go @@ -38,6 +38,12 @@ const ( // If the output is empty, the node shall be omitted from the rendered topology. type MapFunc func(RenderableNode, report.Networks) RenderableNodes +func theInternetNode(m RenderableNode) RenderableNode { + r := newDerivedPseudoNode(TheInternetID, TheInternetMajor, m) + r.Shape = Cloud + return r +} + // MapEndpointIdentity maps an endpoint topology node to a single endpoint // renderable node. As it is only ever run on endpoint topology nodes, we // expect that certain keys are present. @@ -63,7 +69,7 @@ func MapEndpointIdentity(m RenderableNode, local report.Networks) RenderableNode // If the dstNodeAddr is not in a network local to this report, we emit an // internet node if ip := net.ParseIP(addr); ip != nil && !local.Contains(ip) { - return RenderableNodes{TheInternetID: newDerivedPseudoNode(TheInternetID, TheInternetMajor, m)} + return RenderableNodes{TheInternetID: theInternetNode(m)} } // We are a 'client' pseudo node if the port is in the ephemeral port range. @@ -116,7 +122,9 @@ func MapProcessIdentity(m RenderableNode, _ report.Networks) RenderableNodes { rank, _ = m.Latest.Lookup(process.Name) ) - return RenderableNodes{id: NewRenderableNodeWith(id, major, minor, rank, m)} + node := NewRenderableNodeWith(id, major, minor, rank, m) + node.Shape = Square + return RenderableNodes{id: node} } // MapContainerIdentity maps a container topology node to a container @@ -137,6 +145,7 @@ func MapContainerIdentity(m RenderableNode, _ report.Networks) RenderableNodes { node := NewRenderableNodeWith(id, major, minor, rank, m) node.ControlNode = m.ID + node.Shape = Hexagon return RenderableNodes{id: node} } @@ -179,7 +188,10 @@ func MapContainerImageIdentity(m RenderableNode, _ report.Networks) RenderableNo rank = imageID ) - return RenderableNodes{id: NewRenderableNodeWith(id, major, "", rank, m)} + node := NewRenderableNodeWith(id, major, "", rank, m) + node.Shape = Hexagon + node.Stack = true + return RenderableNodes{id: node} } // MapPodIdentity maps a pod topology node to pod renderable node. As it is @@ -197,7 +209,9 @@ func MapPodIdentity(m RenderableNode, _ report.Networks) RenderableNodes { rank, _ = m.Latest.Lookup(kubernetes.PodID) ) - return RenderableNodes{id: NewRenderableNodeWith(id, major, "", rank, m)} + node := NewRenderableNodeWith(id, major, "", rank, m) + node.Shape = Pentagon + return RenderableNodes{id: node} } // MapServiceIdentity maps a service topology node to service renderable node. As it is @@ -215,7 +229,10 @@ func MapServiceIdentity(m RenderableNode, _ report.Networks) RenderableNodes { rank, _ = m.Latest.Lookup(kubernetes.ServiceID) ) - return RenderableNodes{id: NewRenderableNodeWith(id, major, "", rank, m)} + node := NewRenderableNodeWith(id, major, "", rank, m) + node.Shape = Pentagon + node.Stack = true + return RenderableNodes{id: node} } // MapAddressIdentity maps an address topology node to an address renderable @@ -241,7 +258,7 @@ func MapAddressIdentity(m RenderableNode, local report.Networks) RenderableNodes // If the addr is not in a network local to this report, we emit an // internet node if !local.Contains(net.ParseIP(addr)) { - return RenderableNodes{TheInternetID: newDerivedPseudoNode(TheInternetID, TheInternetMajor, m)} + return RenderableNodes{TheInternetID: theInternetNode(m)} } // Otherwise generate a pseudo node for every @@ -280,7 +297,9 @@ func MapHostIdentity(m RenderableNode, _ report.Networks) RenderableNodes { major = hostname } - return RenderableNodes{id: NewRenderableNodeWith(id, major, minor, rank, m)} + node := NewRenderableNodeWith(id, major, minor, rank, m) + node.Shape = Circle + return RenderableNodes{id: node} } // MapEndpoint2IP maps endpoint nodes to their IP address, for joining @@ -298,7 +317,7 @@ func MapEndpoint2IP(m RenderableNode, local report.Networks) RenderableNodes { return RenderableNodes{} } if ip := net.ParseIP(addr); ip != nil && !local.Contains(ip) { - return RenderableNodes{TheInternetID: newDerivedPseudoNode(TheInternetID, TheInternetMajor, m)} + return RenderableNodes{TheInternetID: theInternetNode(m)} } // We don't always know what port a container is listening on, and @@ -375,8 +394,9 @@ func MapIP2Container(n RenderableNode, _ report.Networks) RenderableNodes { } id := MakeContainerID(containerID) - - return RenderableNodes{id: NewDerivedNode(id, n.WithParents(report.EmptySets))} + node := NewDerivedNode(id, n.WithParents(report.EmptySets)) + node.Shape = Hexagon + return RenderableNodes{id: node} } // MapEndpoint2Process maps endpoint RenderableNodes to process @@ -401,7 +421,9 @@ func MapEndpoint2Process(n RenderableNode, _ report.Networks) RenderableNodes { } id := MakeProcessID(report.ExtractHostID(n.Node), pid) - return RenderableNodes{id: NewDerivedNode(id, n.WithParents(report.EmptySets))} + node := NewDerivedNode(id, n.WithParents(report.EmptySets)) + node.Shape = Square + return RenderableNodes{id: node} } // MapProcess2Container maps process RenderableNodes to container @@ -439,10 +461,13 @@ func MapProcess2Container(n RenderableNode, _ report.Networks) RenderableNodes { if containerID, ok := n.Node.Latest.Lookup(docker.ContainerID); ok { id = MakeContainerID(containerID) node = NewDerivedNode(id, n) + node.Shape = Hexagon } else { id = MakePseudoNodeID(UncontainedID, hostID) node = newDerivedPseudoNode(id, UncontainedMajor, n) node.LabelMinor = hostID + node.Shape = Square + node.Stack = true } node.Children = node.Children.Add(n.Node) @@ -472,6 +497,8 @@ func MapProcess2Name(n RenderableNode, _ report.Networks) RenderableNodes { node.Node.Topology = "process_name" node.Node.ID = name node.Children = node.Children.Add(n.Node) + node.Shape = Square + node.Stack = true return RenderableNodes{name: node} } @@ -526,6 +553,8 @@ func MapContainer2ContainerImage(n RenderableNode, _ report.Networks) Renderable result.Node.Topology = "container_image" result.Node.ID = report.MakeContainerImageNodeID(imageID) + result.Shape = Hexagon + result.Stack = true return RenderableNodes{id: result} } @@ -558,6 +587,8 @@ func MapPod2Service(n RenderableNode, _ report.Networks) RenderableNodes { n := NewDerivedNode(id, n.WithParents(report.EmptySets)) n.Node.Counters = n.Node.Counters.Add(podsKey, 1) n.Children = n.Children.Add(n.Node) + n.Shape = Pentagon + n.Stack = true result[id] = n } return result @@ -597,6 +628,8 @@ func MapContainerImage2Name(n RenderableNode, _ report.Networks) RenderableNodes node.LabelMajor = name node.Rank = name node.Node = n.Node.Copy() // Propagate NMD for container counting. + node.Shape = Hexagon + node.Stack = true return RenderableNodes{id: node} } @@ -621,6 +654,7 @@ func MapX2Host(n RenderableNode, _ report.Networks) RenderableNodes { id := MakeHostID(report.ExtractHostID(n.Node)) result := NewDerivedNode(id, n.WithParents(report.EmptySets)) result.Children = result.Children.Add(n.Node) + result.Shape = Circle return RenderableNodes{id: result} } @@ -666,7 +700,7 @@ func MapContainer2Pod(n RenderableNode, _ report.Networks) RenderableNodes { } result.Children = result.Children.Add(n.Node) - + result.Shape = Pentagon return RenderableNodes{id: result} } @@ -690,12 +724,11 @@ func MapContainer2Hostname(n RenderableNode, _ report.Networks) RenderableNodes // Add container id key to the counters, which will later be counted to produce the minor label result.Counters = result.Counters.Add(containersKey, 1) - result.Node.Topology = "container_hostname" result.Node.ID = id - result.Children = result.Children.Add(n.Node) - + result.Shape = Hexagon + result.Stack = true return RenderableNodes{id: result} } diff --git a/render/renderable_node.go b/render/renderable_node.go index e796571370..c35357cd8d 100644 --- a/render/renderable_node.go +++ b/render/renderable_node.go @@ -15,11 +15,22 @@ type RenderableNode struct { Pseudo bool `json:"pseudo,omitempty"` // sort-of a placeholder node, for rendering purposes Children report.NodeSet `json:"children,omitempty"` // Nodes which have been grouped into this one ControlNode string `json:"-"` // ID of node from which to show the controls in the UI + Shape string `json:"shape"` // Shape node should be rendered as + Stack bool `json:"stack"` // Should UI render this node as a stack? report.EdgeMetadata `json:"metadata"` // Numeric sums report.Node } +// Shapes that are allowed +const ( + Circle = "circle" + Square = "square" + Pentagon = "pentagon" + Hexagon = "hexagon" + Cloud = "cloud" +) + // NewRenderableNode makes a new RenderableNode func NewRenderableNode(id string) RenderableNode { return RenderableNode{ @@ -30,6 +41,7 @@ func NewRenderableNode(id string) RenderableNode { Pseudo: false, EdgeMetadata: report.EdgeMetadata{}, Node: report.MakeNode(), + Shape: Circle, } } @@ -44,6 +56,7 @@ func NewRenderableNodeWith(id, major, minor, rank string, node RenderableNode) R Children: node.Children.Copy(), EdgeMetadata: node.EdgeMetadata.Copy(), Node: node.Node.Copy(), + Shape: Circle, } } @@ -59,6 +72,7 @@ func NewDerivedNode(id string, node RenderableNode) RenderableNode { EdgeMetadata: node.EdgeMetadata.Copy(), Node: node.Node.Copy(), ControlNode: "", // Do not propagate ControlNode when making a derived node! + Shape: Circle, } } @@ -72,6 +86,7 @@ func newDerivedPseudoNode(id, major string, node RenderableNode) RenderableNode Children: node.Children.Copy(), EdgeMetadata: node.EdgeMetadata.Copy(), Node: node.Node.Copy(), + Shape: Circle, } } @@ -113,6 +128,7 @@ func (rn RenderableNode) Merge(other RenderableNode) RenderableNode { panic(result.ID) } + result.Stack = result.Stack || rn.Stack result.Children = rn.Children.Merge(other.Children) result.EdgeMetadata = rn.EdgeMetadata.Merge(other.EdgeMetadata) result.Node = rn.Node.Merge(other.Node) @@ -132,6 +148,8 @@ func (rn RenderableNode) Copy() RenderableNode { EdgeMetadata: rn.EdgeMetadata.Copy(), Node: rn.Node.Copy(), ControlNode: rn.ControlNode, + Shape: rn.Shape, + Stack: rn.Stack, } } diff --git a/render/short_lived_connections_test.go b/render/short_lived_connections_test.go index 1ac2f08fce..e3efd476b9 100644 --- a/render/short_lived_connections_test.go +++ b/render/short_lived_connections_test.go @@ -74,6 +74,7 @@ var ( ID: render.TheInternetID, LabelMajor: render.TheInternetMajor, Pseudo: true, + Shape: "cloud", Node: report.MakeNode().WithAdjacent(render.MakeContainerID(containerID)), }, render.MakeContainerID(containerID): { @@ -82,6 +83,7 @@ var ( LabelMinor: serverHostID, Rank: "", Pseudo: false, + Shape: "hexagon", Node: report.MakeNode(), ControlNode: containerNodeID, },