From 8c4bbdae8c292627c3c6ad0fc7734188c574e7ce Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Tue, 18 Aug 2015 12:47:44 +0000 Subject: [PATCH 1/2] Show how many containers have been grouped together under an image --- render/expected/expected.go | 10 +++---- render/mapping.go | 54 ++++++++++++++++++++++++++++++++++++- render/topologies.go | 34 +++++++++++++---------- 3 files changed, 78 insertions(+), 20 deletions(-) diff --git a/render/expected/expected.go b/render/expected/expected.go index 8928bbdc0..d627e0096 100644 --- a/render/expected/expected.go +++ b/render/expected/expected.go @@ -124,7 +124,7 @@ var ( "curl": { ID: "curl", LabelMajor: "curl", - LabelMinor: "", + LabelMinor: "2 processes", Rank: "curl", Pseudo: false, Adjacency: report.MakeIDList("apache"), @@ -144,7 +144,7 @@ var ( "apache": { ID: "apache", LabelMajor: "apache", - LabelMinor: "", + LabelMinor: "1 process", Rank: "apache", Pseudo: false, Adjacency: report.MakeIDList( @@ -167,7 +167,7 @@ var ( "bash": { ID: "bash", LabelMajor: "bash", - LabelMinor: "", + LabelMinor: "1 process", Rank: "bash", Pseudo: false, Origins: report.MakeIDList( @@ -243,7 +243,7 @@ var ( test.ClientContainerImageName: { ID: test.ClientContainerImageName, LabelMajor: test.ClientContainerImageName, - LabelMinor: "", + LabelMinor: "1 container", Rank: test.ClientContainerImageName, Pseudo: false, Adjacency: report.MakeIDList(test.ServerContainerImageName), @@ -265,7 +265,7 @@ var ( test.ServerContainerImageName: { ID: test.ServerContainerImageName, LabelMajor: test.ServerContainerImageName, - LabelMinor: "", + LabelMinor: "1 container", Rank: test.ServerContainerImageName, Pseudo: false, Adjacency: report.MakeIDList(test.ClientContainerImageName, render.TheInternetID), diff --git a/render/mapping.go b/render/mapping.go index 66da21d6d..faec5173e 100644 --- a/render/mapping.go +++ b/render/mapping.go @@ -19,6 +19,9 @@ const ( TheInternetID = "theinternet" TheInternetMajor = "The Internet" + + containersPrefix = "container-" + processesPrefix = "process-" ) // LeafMapFunc is anything which can take an arbitrary NodeMetadata, which is @@ -249,9 +252,37 @@ func MapProcess2Name(n RenderableNode) (RenderableNode, bool) { node := newDerivedNode(name, n) node.LabelMajor = name node.Rank = name + node.NodeMetadata.Metadata[processesPrefix+n.ID] = "" return node, true } +func countPrefix(prefix string, n RenderableNode) int { + count := 0 + for key := range n.NodeMetadata.Metadata { + if strings.HasPrefix(key, prefix) { + count++ + } + } + return count +} + +// MapCountProcessName maps 1:1 process name nodes, counting +// the number of processes grouped together and putting +// that info in the minor label. +func MapCountProcessName(n RenderableNode) (RenderableNode, bool) { + if n.Pseudo { + return n, true + } + + processes := countPrefix(processesPrefix, n) + if processes == 1 { + n.LabelMinor = "1 process" + } else { + n.LabelMinor = fmt.Sprintf("%d processes", processes) + } + return n, true +} + // MapContainer2ContainerImage maps container RenderableNodes to container // image RenderableNodes. // @@ -276,7 +307,10 @@ func MapContainer2ContainerImage(n RenderableNode) (RenderableNode, bool) { return n, false } - return newDerivedNode(id, n), true + // Add container- key to NMD, which will later be counted to produce the minor label + result := newDerivedNode(id, n) + result.NodeMetadata.Metadata[containersPrefix+n.ID] = "" + return result, true } // MapContainerImage2Name maps container images RenderableNodes to @@ -303,9 +337,27 @@ func MapContainerImage2Name(n RenderableNode) (RenderableNode, bool) { node := newDerivedNode(name, n) node.LabelMajor = name node.Rank = name + node.NodeMetadata = n.NodeMetadata.Copy() // Propagate NMD for container counting. return node, true } +// MapCountContainers maps 1:1 container image nodes, counting +// the number of containers grouped together and putting +// that info in the minor label. +func MapCountContainers(n RenderableNode) (RenderableNode, bool) { + if n.Pseudo { + return n, true + } + + containers := countPrefix(containersPrefix, n) + if containers == 1 { + n.LabelMinor = "1 container" + } else { + n.LabelMinor = fmt.Sprintf("%d container(s)", containers) + } + return n, true +} + // MapAddress2Host maps address RenderableNodes to host RenderableNodes. // // Otherthan pseudo nodes, we can assume all nodes have a HostID diff --git a/render/topologies.go b/render/topologies.go index 1a139c7f3..77530e599 100644 --- a/render/topologies.go +++ b/render/topologies.go @@ -28,8 +28,11 @@ var ProcessRenderer = MakeReduce( // ProcessRenderer is a Renderer which produces a renderable process // name graph by munging the progess graph. var ProcessNameRenderer = Map{ - MapFunc: MapProcess2Name, - Renderer: ProcessRenderer, + MapFunc: MapCountProcessName, + Renderer: Map{ + MapFunc: MapProcess2Name, + Renderer: ProcessRenderer, + }, } // ContainerRenderer is a Renderer which produces a renderable container @@ -49,18 +52,21 @@ var ContainerRenderer = MakeReduce( // ContainerImageRenderer is a Renderer which produces a renderable container // image graph by merging the container graph and the container image topology. var ContainerImageRenderer = Map{ - MapFunc: MapContainerImage2Name, - Renderer: MakeReduce( - Map{ - MapFunc: MapContainer2ContainerImage, - Renderer: ContainerRenderer, - }, - LeafMap{ - Selector: report.SelectContainerImage, - Mapper: MapContainerImageIdentity, - Pseudo: PanicPseudoNode, - }, - ), + MapFunc: MapCountContainers, + Renderer: Map{ + MapFunc: MapContainerImage2Name, + Renderer: MakeReduce( + Map{ + MapFunc: MapContainer2ContainerImage, + Renderer: ContainerRenderer, + }, + LeafMap{ + Selector: report.SelectContainerImage, + Mapper: MapContainerImageIdentity, + Pseudo: PanicPseudoNode, + }, + ), + }, } // AddressRenderer is a Renderer which produces a renderable address From 7508df7e5bdc4a600ebc0508a19260a142950e4a Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Wed, 19 Aug 2015 14:24:21 +0000 Subject: [PATCH 2/2] Add NodeMetadata.Counters with appropriate merge semantics --- app/api_topology_test.go | 3 +++ render/mapping.go | 22 ++++++---------------- report/merge.go | 3 +++ report/topology.go | 5 +++++ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/api_topology_test.go b/app/api_topology_test.go index 0cc249faf..5f74babad 100644 --- a/app/api_topology_test.go +++ b/app/api_topology_test.go @@ -22,6 +22,9 @@ func fixNodeMetadatas(nodes render.RenderableNodes) render.RenderableNodes { if node.NodeMetadata.Metadata == nil { node.NodeMetadata.Metadata = map[string]string{} } + if node.NodeMetadata.Counters == nil { + node.NodeMetadata.Counters = map[string]int{} + } result[id] = node } return result diff --git a/render/mapping.go b/render/mapping.go index faec5173e..7c76fedaa 100644 --- a/render/mapping.go +++ b/render/mapping.go @@ -20,8 +20,8 @@ const ( TheInternetID = "theinternet" TheInternetMajor = "The Internet" - containersPrefix = "container-" - processesPrefix = "process-" + containersKey = "containers" + processesKey = "processes" ) // LeafMapFunc is anything which can take an arbitrary NodeMetadata, which is @@ -252,20 +252,10 @@ func MapProcess2Name(n RenderableNode) (RenderableNode, bool) { node := newDerivedNode(name, n) node.LabelMajor = name node.Rank = name - node.NodeMetadata.Metadata[processesPrefix+n.ID] = "" + node.NodeMetadata.Counters[processesKey] = 1 return node, true } -func countPrefix(prefix string, n RenderableNode) int { - count := 0 - for key := range n.NodeMetadata.Metadata { - if strings.HasPrefix(key, prefix) { - count++ - } - } - return count -} - // MapCountProcessName maps 1:1 process name nodes, counting // the number of processes grouped together and putting // that info in the minor label. @@ -274,7 +264,7 @@ func MapCountProcessName(n RenderableNode) (RenderableNode, bool) { return n, true } - processes := countPrefix(processesPrefix, n) + processes := n.NodeMetadata.Counters[processesKey] if processes == 1 { n.LabelMinor = "1 process" } else { @@ -309,7 +299,7 @@ func MapContainer2ContainerImage(n RenderableNode) (RenderableNode, bool) { // Add container- key to NMD, which will later be counted to produce the minor label result := newDerivedNode(id, n) - result.NodeMetadata.Metadata[containersPrefix+n.ID] = "" + result.NodeMetadata.Counters[containersKey] = 1 return result, true } @@ -349,7 +339,7 @@ func MapCountContainers(n RenderableNode) (RenderableNode, bool) { return n, true } - containers := countPrefix(containersPrefix, n) + containers := n.NodeMetadata.Counters[containersKey] if containers == 1 { n.LabelMinor = "1 container" } else { diff --git a/report/merge.go b/report/merge.go index 406abe6ce..223ffa433 100644 --- a/report/merge.go +++ b/report/merge.go @@ -48,6 +48,9 @@ func (nm NodeMetadata) Merge(other NodeMetadata) NodeMetadata { for k, v := range other.Metadata { nm.Metadata[k] = v // other takes precedence } + for k, v := range other.Counters { + nm.Counters[k] = nm.Counters[k] + v + } return nm } diff --git a/report/topology.go b/report/topology.go index 2ca9b3e0a..8ad4b1393 100644 --- a/report/topology.go +++ b/report/topology.go @@ -42,6 +42,7 @@ type EdgeMetadata struct { // about a given node in a given topology. type NodeMetadata struct { Metadata map[string]string + Counters map[string]int } // MakeNodeMetadata creates a new NodeMetadata with no initial metadata. @@ -53,6 +54,7 @@ func MakeNodeMetadata() NodeMetadata { func MakeNodeMetadataWith(m map[string]string) NodeMetadata { return NodeMetadata{ Metadata: m, + Counters: map[string]int{}, } } @@ -62,6 +64,9 @@ func (nm NodeMetadata) Copy() NodeMetadata { for k, v := range nm.Metadata { cp.Metadata[k] = v } + for k, v := range nm.Counters { + cp.Counters[k] = v + } return cp }