mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-21 22:36:39 +00:00
Add explicit group node summariser instead of doing it in the other summaires
This commit is contained in:
@@ -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: Circle,
|
||||
}
|
||||
)
|
||||
|
||||
// NodeSummaryGroup is a topology-typed group of children for a Node.
|
||||
type NodeSummaryGroup struct {
|
||||
ID string `json:"id"`
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
@@ -142,23 +161,23 @@ 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
|
||||
base.Shape = Cloud
|
||||
return base, true
|
||||
}
|
||||
|
||||
// try rendering it as an uncontained node
|
||||
if strings.HasPrefix(n.ID, render.MakePseudoNodeID(render.UncontainedID)) {
|
||||
base.Label = render.UncontainedMajor
|
||||
base.LabelMinor = report.ExtractHostID(n)
|
||||
base.Shape = Square
|
||||
base.Stack = true
|
||||
base.LabelMinor = report.ExtractHostID(n)
|
||||
return base, true
|
||||
}
|
||||
|
||||
@@ -174,6 +193,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
|
||||
}
|
||||
|
||||
@@ -183,25 +203,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)
|
||||
@@ -211,23 +221,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
|
||||
}
|
||||
|
||||
@@ -240,7 +239,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 {
|
||||
@@ -250,13 +248,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 {
|
||||
@@ -269,16 +261,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 {
|
||||
@@ -292,7 +276,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
|
||||
@@ -320,16 +303,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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -111,7 +112,9 @@ 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],
|
||||
@@ -119,13 +122,15 @@ var (
|
||||
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],
|
||||
|
||||
@@ -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}, ":")
|
||||
}
|
||||
|
||||
@@ -265,7 +265,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}
|
||||
@@ -461,7 +461,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.
|
||||
|
||||
Reference in New Issue
Block a user