Skip to content

Commit

Permalink
Add explicit group node summariser instead of doing it in the other s…
Browse files Browse the repository at this point in the history
…ummaires
  • Loading branch information
paulbellamy committed Apr 20, 2016
1 parent 5cedfad commit c17c7c7
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 73 deletions.
124 changes: 64 additions & 60 deletions render/detailed/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ const (
MarathonAppIDEnv = "MARATHON_APP_ID"
)

var (
shapesByTopology = map[string]string{
report.Host: Circle,
report.Process: Square,
report.Pod: Heptagon,
report.Service: Heptagon,
report.Container: Hexagon,
report.ContainerImage: Hexagon,
render.Pseudo: Cloud,
}
)

// NodeSummaryGroup is a topology-typed group of children for a Node.
type NodeSummaryGroup struct {
ID string `json:"id"`
Expand Down Expand Up @@ -89,6 +101,9 @@ func MakeNodeSummary(r report.Report, n report.Node) (NodeSummary, bool) {
if renderer, ok := renderers[n.Topology]; ok {
return renderer(baseNodeSummary(r, n), n)
}
if strings.HasPrefix(n.Topology, "group:") {
return groupNodeSummary(baseNodeSummary(r, n), n)
}
return NodeSummary{}, false
}

Expand Down Expand Up @@ -127,9 +142,13 @@ func (n NodeSummary) Copy() NodeSummary {
}

func baseNodeSummary(r report.Report, n report.Node) NodeSummary {
shape, ok := shapesByTopology[n.Topology]
if !ok {
shape = Circle
}
return NodeSummary{
ID: n.ID,
Shape: Circle,
Shape: shape,
Linkable: true,
Metadata: NodeMetadata(r, n),
Metrics: NodeMetrics(r, n),
Expand All @@ -142,14 +161,13 @@ func pseudoNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
base.Pseudo = true
base.Rank = n.ID

if template, ok := map[string]struct{ Label, LabelMinor, Shape string }{
render.TheInternetID: {render.InboundMajor, "", Cloud},
render.IncomingInternetID: {render.InboundMajor, render.InboundMinor, Cloud},
render.OutgoingInternetID: {render.OutboundMajor, render.OutboundMinor, Cloud},
if template, ok := map[string]struct{ Label, LabelMinor string }{
render.TheInternetID: {render.InboundMajor, ""},
render.IncomingInternetID: {render.InboundMajor, render.InboundMinor},
render.OutgoingInternetID: {render.OutboundMajor, render.OutboundMinor},
}[n.ID]; ok {
base.Label = template.Label
base.LabelMinor = template.LabelMinor
base.Shape = template.Shape
return base, true
}

Expand All @@ -165,6 +183,7 @@ func pseudoNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
// try rendering it as an endpoint
if addr, ok := n.Latest.Lookup(endpoint.Addr); ok {
base.Label = addr
base.Shape = Circle
return base, true
}

Expand All @@ -174,25 +193,15 @@ func pseudoNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
func processNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
base.Label, _ = n.Latest.Lookup(process.Name)
base.Rank, _ = n.Latest.Lookup(process.Name)
base.Shape = Square

if p, ok := n.Counters.Lookup(report.Process); ok {
base.Stack = true
if p == 1 {
base.LabelMinor = fmt.Sprintf("%d process", p)
} else {
base.LabelMinor = fmt.Sprintf("%d processes", p)
}
pid, ok := n.Latest.Lookup(process.PID)
if !ok {
return NodeSummary{}, false
}
if containerName, ok := n.Latest.Lookup(docker.ContainerName); ok {
base.LabelMinor = fmt.Sprintf("%s (%s:%s)", report.ExtractHostID(n), containerName, pid)
} else {
pid, ok := n.Latest.Lookup(process.PID)
if !ok {
return NodeSummary{}, false
}
if containerName, ok := n.Latest.Lookup(docker.ContainerName); ok {
base.LabelMinor = fmt.Sprintf("%s (%s:%s)", report.ExtractHostID(n), containerName, pid)
} else {
base.LabelMinor = fmt.Sprintf("%s (%s)", report.ExtractHostID(n), pid)
}
base.LabelMinor = fmt.Sprintf("%s (%s)", report.ExtractHostID(n), pid)
}

_, isConnected := n.Latest.Lookup(render.IsConnected)
Expand All @@ -202,23 +211,12 @@ func processNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {

func containerNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
base.Label = getRenderableContainerName(n)

if c, ok := n.Counters.Lookup(report.Container); ok {
base.Stack = true
if c == 1 {
base.LabelMinor = fmt.Sprintf("%d container", c)
} else {
base.LabelMinor = fmt.Sprintf("%d containers", c)
}
} else {
base.LabelMinor = report.ExtractHostID(n)
}
base.LabelMinor = report.ExtractHostID(n)

if imageName, ok := n.Latest.Lookup(docker.ImageName); ok {
base.Rank = render.ImageNameWithoutVersion(imageName)
}

base.Shape = Hexagon
return base, true
}

Expand All @@ -231,7 +229,6 @@ func containerImageNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bo
imageNameWithoutVersion := render.ImageNameWithoutVersion(imageName)
base.Label = imageNameWithoutVersion
base.Rank = imageNameWithoutVersion
base.Shape = Hexagon
base.Stack = true

if base.Label == ImageNameNone {
Expand All @@ -241,13 +238,7 @@ func containerImageNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bo
}
}

if i, ok := n.Counters.Lookup(report.ContainerImage); ok {
if i == 1 {
base.LabelMinor = fmt.Sprintf("%d image", i)
} else {
base.LabelMinor = fmt.Sprintf("%d images", i)
}
} else if c, ok := n.Counters.Lookup(report.Container); ok {
if c, ok := n.Counters.Lookup(report.Container); ok {
if c == 1 {
base.LabelMinor = fmt.Sprintf("%d container", c)
} else {
Expand All @@ -260,16 +251,8 @@ func containerImageNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bo
func podNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
base.Label, _ = n.Latest.Lookup(kubernetes.PodName)
base.Rank, _ = n.Latest.Lookup(kubernetes.PodID)
base.Shape = Heptagon

if p, ok := n.Counters.Lookup(report.Pod); ok {
base.Stack = true
if p == 1 {
base.LabelMinor = fmt.Sprintf("%d pod", p)
} else {
base.LabelMinor = fmt.Sprintf("%d pods", p)
}
} else if c, ok := n.Counters.Lookup(report.Container); ok {
if c, ok := n.Counters.Lookup(report.Container); ok {
if c == 1 {
base.LabelMinor = fmt.Sprintf("%d container", c)
} else {
Expand All @@ -283,7 +266,6 @@ func podNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
func serviceNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
base.Label, _ = n.Latest.Lookup(kubernetes.ServiceName)
base.Rank, _ = n.Latest.Lookup(kubernetes.ServiceID)
base.Shape = Heptagon
base.Stack = true

// Services are always just a group of pods, so there's no counting multiple
Expand Down Expand Up @@ -311,16 +293,38 @@ func hostNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
base.Label = hostname
}

if h, ok := n.Counters.Lookup(report.Host); ok {
base.Stack = true
if h == 1 {
base.LabelMinor = fmt.Sprintf("%d host", h)
} else {
base.LabelMinor = fmt.Sprintf("%d hosts", h)
return base, true
}

// groupNodeSummary renders the summary for a group node. n.Topology is
// expected to be of the form: group:container:hostname
func groupNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
parts := strings.Split(n.Topology, ":")
if len(parts) != 3 {
return NodeSummary{}, false
}

label, ok := n.Latest.Lookup(parts[2])
if !ok {
return NodeSummary{}, false
}
base.Label, base.Rank = label, label

if count, ok := n.Counters.Lookup(parts[1]); ok {
base.LabelMinor = fmt.Sprintf("%d %s", count, parts[1])
if count != 1 {
if strings.HasSuffix(parts[1], "s") {
base.LabelMinor += "es"
} else {
base.LabelMinor += "s"
}
}
}

base.Shape = Circle
if base.Shape, ok = shapesByTopology[parts[1]]; !ok {
base.Shape = Circle
}
base.Stack = true
return base, true
}

Expand Down
14 changes: 14 additions & 0 deletions render/detailed/summary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,20 @@ func TestMakeNodeSummary(t *testing.T) {
Adjacency: report.MakeIDList(fixture.ServerHostNodeID),
},
},
{
name: "group node rendering",
input: expected.RenderedProcessNames[fixture.ServerName],
ok: true,
want: detailed.NodeSummary{
ID: "apache",
Label: "apache",
LabelMinor: "1 process",
Rank: "apache",
Shape: "square",
Stack: true,
Linkable: true,
},
},
}
for _, testcase := range testcases {
have, ok := detailed.MakeNodeSummary(fixture.Report, testcase.input)
Expand Down
27 changes: 16 additions & 11 deletions render/expected/expected.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ var (
return n
}
}
pseudo = node(render.Pseudo)
endpoint = node(report.Endpoint)
processNode = node(report.Process)
container = node(report.Container)
containerImage = node(report.ContainerImage)
pod = node(report.Pod)
service = node(report.Service)
hostNode = node(report.Host)
pseudo = node(render.Pseudo)
endpoint = node(report.Endpoint)
processNode = node(report.Process)
processNameNode = node(render.MakeGroupNodeTopology(report.Process, process.Name))
container = node(report.Container)
containerImage = node(report.ContainerImage)
pod = node(report.Pod)
service = node(report.Service)
hostNode = node(report.Host)

UnknownPseudoNode1ID = render.MakePseudoNodeID(fixture.UnknownClient1IP)
UnknownPseudoNode2ID = render.MakePseudoNodeID(fixture.UnknownClient3IP)
Expand Down Expand Up @@ -111,21 +112,25 @@ var (
}

RenderedProcessNames = report.Nodes{
fixture.Client1Name: processNode(fixture.Client1Name, fixture.ServerName).
fixture.Client1Name: processNameNode(fixture.Client1Name, fixture.ServerName).
WithLatests(map[string]string{process.Name: fixture.Client1Name}).
WithCounters(map[string]int{report.Process: 2}).
WithChildren(report.MakeNodeSet(
RenderedEndpoints[fixture.Client54001NodeID],
RenderedEndpoints[fixture.Client54002NodeID],
RenderedProcesses[fixture.ClientProcess1NodeID],
RenderedProcesses[fixture.ClientProcess2NodeID],
)),

fixture.ServerName: processNode(fixture.ServerName).
fixture.ServerName: processNameNode(fixture.ServerName).
WithLatests(map[string]string{process.Name: fixture.ServerName}).
WithCounters(map[string]int{report.Process: 1}).
WithChildren(report.MakeNodeSet(
RenderedEndpoints[fixture.Server80NodeID],
RenderedProcesses[fixture.ServerProcessNodeID],
)),

fixture.NonContainerName: processNode(fixture.NonContainerName, render.OutgoingInternetID).
fixture.NonContainerName: processNameNode(fixture.NonContainerName, render.OutgoingInternetID).
WithChildren(report.MakeNodeSet(
RenderedEndpoints[fixture.NonContainerNodeID],
RenderedProcesses[fixture.NonContainerProcessNodeID],
Expand Down
5 changes: 5 additions & 0 deletions render/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ import (
func MakePseudoNodeID(parts ...string) string {
return strings.Join(append([]string{"pseudo"}, parts...), ":")
}

// MakeGroupNodeTopology joins the parts of a group topology into the topology of a group node
func MakeGroupNodeTopology(originalTopology, key string) string {
return strings.Join([]string{"group", originalTopology, key}, ":")
}
4 changes: 2 additions & 2 deletions render/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func MapProcess2Name(n report.Node, _ report.Networks) report.Nodes {
return report.Nodes{}
}

node := NewDerivedNode(name, n).WithTopology(report.Process)
node := NewDerivedNode(name, n).WithTopology(MakeGroupNodeTopology(n.Topology, process.Name))
node.Latest = node.Latest.Set(process.Name, timestamp, name)
node.Counters = node.Counters.Add(n.Topology, 1)
return report.Nodes{name: node}
Expand Down Expand Up @@ -445,7 +445,7 @@ func MapContainer2Hostname(n report.Node, _ report.Networks) report.Nodes {
return report.Nodes{}
}

node := NewDerivedNode(id, n)
node := NewDerivedNode(id, n).WithTopology(MakeGroupNodeTopology(n.Topology, docker.ContainerHostname))
node.Latest = node.Latest.
Set(docker.ContainerHostname, timestamp, id).
Delete(docker.ContainerName) // TODO(paulbellamy): total hack to render these by hostname instead.
Expand Down

0 comments on commit c17c7c7

Please sign in to comment.