mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 02:30:45 +00:00
Merge pull request #1327 from weaveworks/1213-group-summariser
Add explicit group node summariser instead of doing it in the other summaries
This commit is contained in:
@@ -68,6 +68,14 @@ func TestAppClientPublish(t *testing.T) {
|
||||
// marshalling->unmarshaling is not idempotent due to `json:"omitempty"`
|
||||
// tags, transforming empty slices into nils. So, we make DeepEqual
|
||||
// happy by setting empty `json:"omitempty"` entries to nil
|
||||
rpt.Endpoint = report.MakeTopology()
|
||||
rpt.Process = report.MakeTopology()
|
||||
rpt.Container = report.MakeTopology()
|
||||
rpt.ContainerImage = report.MakeTopology()
|
||||
rpt.Pod = report.MakeTopology()
|
||||
rpt.Service = report.MakeTopology()
|
||||
rpt.Host = report.MakeTopology()
|
||||
rpt.Overlay = report.MakeTopology()
|
||||
rpt.Endpoint.Controls = nil
|
||||
rpt.Process.Controls = nil
|
||||
rpt.Container.Controls = nil
|
||||
|
||||
@@ -80,14 +80,6 @@ func TestProbe(t *testing.T) {
|
||||
want := report.MakeReport()
|
||||
node := report.MakeNodeWith("a", map[string]string{"b": "c"})
|
||||
node.Metrics = nil // omitempty
|
||||
want.Endpoint.AddNode(node)
|
||||
want.Probes[probeID] = report.Probe{
|
||||
ID: probeID,
|
||||
LastSeen: now,
|
||||
}
|
||||
|
||||
pub := mockPublisher{make(chan report.Report)}
|
||||
|
||||
// omitempty
|
||||
want.Endpoint.Controls = nil
|
||||
want.Process.Controls = nil
|
||||
@@ -98,6 +90,14 @@ func TestProbe(t *testing.T) {
|
||||
want.Host.Controls = nil
|
||||
want.Overlay.Controls = nil
|
||||
|
||||
want.Endpoint.AddNode(node)
|
||||
want.Probes[probeID] = report.Probe{
|
||||
ID: probeID,
|
||||
LastSeen: now,
|
||||
}
|
||||
|
||||
pub := mockPublisher{make(chan report.Report)}
|
||||
|
||||
p := New(probeID, 10*time.Millisecond, 100*time.Millisecond, pub)
|
||||
p.AddReporter(mockReporter{want})
|
||||
p.Start()
|
||||
|
||||
@@ -15,12 +15,6 @@ import (
|
||||
|
||||
// Shapes that are allowed
|
||||
const (
|
||||
Circle = "circle"
|
||||
Square = "square"
|
||||
Heptagon = "heptagon"
|
||||
Hexagon = "hexagon"
|
||||
Cloud = "cloud"
|
||||
|
||||
ImageNameNone = "<none>"
|
||||
|
||||
// Keys we use to render container names
|
||||
@@ -89,6 +83,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), r, n)
|
||||
}
|
||||
return NodeSummary{}, false
|
||||
}
|
||||
|
||||
@@ -127,9 +124,10 @@ func (n NodeSummary) Copy() NodeSummary {
|
||||
}
|
||||
|
||||
func baseNodeSummary(r report.Report, n report.Node) NodeSummary {
|
||||
t, _ := r.Topology(n.Topology)
|
||||
return NodeSummary{
|
||||
ID: n.ID,
|
||||
Shape: Circle,
|
||||
Shape: t.GetShape(),
|
||||
Linkable: true,
|
||||
Metadata: NodeMetadata(r, n),
|
||||
Metrics: NodeMetrics(r, n),
|
||||
@@ -142,30 +140,30 @@ 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 = report.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.Shape = Square
|
||||
base.Stack = true
|
||||
base.LabelMinor = report.ExtractHostID(n)
|
||||
base.Shape = report.Square
|
||||
base.Stack = true
|
||||
return base, true
|
||||
}
|
||||
|
||||
// try rendering it as an unmanaged node
|
||||
if strings.HasPrefix(n.ID, render.MakePseudoNodeID(render.UnmanagedID)) {
|
||||
base.Label = render.UnmanagedMajor
|
||||
base.Shape = Square
|
||||
base.Shape = report.Square
|
||||
base.Stack = true
|
||||
base.LabelMinor = report.ExtractHostID(n)
|
||||
return base, true
|
||||
@@ -174,6 +172,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 = report.Circle
|
||||
return base, true
|
||||
}
|
||||
|
||||
@@ -183,25 +182,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 +200,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 +218,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 +227,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 +240,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 +255,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 +282,36 @@ 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, r report.Report, 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
|
||||
|
||||
t, ok := r.Topology(parts[1])
|
||||
if ok && t.Label != "" {
|
||||
if count, ok := n.Counters.Lookup(parts[1]); ok {
|
||||
if count == 1 {
|
||||
base.LabelMinor = fmt.Sprintf("%d %s", count, t.Label)
|
||||
} else {
|
||||
base.LabelMinor = fmt.Sprintf("%d %s", count, t.LabelPlural)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.Shape = Circle
|
||||
base.Shape = t.GetShape()
|
||||
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.
|
||||
|
||||
@@ -30,13 +30,7 @@ type MetadataTemplate struct {
|
||||
|
||||
// Copy returns a value-copy of the template
|
||||
func (t MetadataTemplate) Copy() MetadataTemplate {
|
||||
return MetadataTemplate{
|
||||
ID: t.ID,
|
||||
Label: t.Label,
|
||||
Truncate: t.Truncate,
|
||||
Priority: t.Priority,
|
||||
From: t.From,
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// MetadataRows returns the rows for a node
|
||||
|
||||
@@ -20,6 +20,13 @@ const (
|
||||
Host = "host"
|
||||
Overlay = "overlay"
|
||||
|
||||
// Shapes used for different nodes
|
||||
Circle = "circle"
|
||||
Square = "square"
|
||||
Heptagon = "heptagon"
|
||||
Hexagon = "hexagon"
|
||||
Cloud = "cloud"
|
||||
|
||||
// Used when counting the number of containers
|
||||
ContainersKey = "containers"
|
||||
)
|
||||
@@ -96,19 +103,39 @@ type Report struct {
|
||||
// MakeReport makes a clean report, ready to Merge() other reports into.
|
||||
func MakeReport() Report {
|
||||
return Report{
|
||||
Endpoint: MakeTopology(),
|
||||
Process: MakeTopology(),
|
||||
Container: MakeTopology(),
|
||||
ContainerImage: MakeTopology(),
|
||||
Host: MakeTopology(),
|
||||
Pod: MakeTopology(),
|
||||
Service: MakeTopology(),
|
||||
Overlay: MakeTopology(),
|
||||
Sampling: Sampling{},
|
||||
Window: 0,
|
||||
Plugins: xfer.MakePluginSpecs(),
|
||||
ID: fmt.Sprintf("%d", rand.Int63()),
|
||||
Probes: Probes{},
|
||||
Endpoint: MakeTopology(),
|
||||
|
||||
Process: MakeTopology().
|
||||
WithShape(Square).
|
||||
WithLabel("process", "processes"),
|
||||
|
||||
Container: MakeTopology().
|
||||
WithShape(Hexagon).
|
||||
WithLabel("container", "containers"),
|
||||
|
||||
ContainerImage: MakeTopology().
|
||||
WithShape(Hexagon).
|
||||
WithLabel("image", "images"),
|
||||
|
||||
Host: MakeTopology().
|
||||
WithShape(Circle).
|
||||
WithLabel("host", "hosts"),
|
||||
|
||||
Pod: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithLabel("pod", "pods"),
|
||||
|
||||
Service: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithLabel("service", "services"),
|
||||
|
||||
Overlay: MakeTopology(),
|
||||
|
||||
Sampling: Sampling{},
|
||||
Window: 0,
|
||||
Plugins: xfer.MakePluginSpecs(),
|
||||
ID: fmt.Sprintf("%d", rand.Int63()),
|
||||
Probes: Probes{},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,13 +60,9 @@ type TableTemplate struct {
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
// Copy returns a copy of the TableTemplate
|
||||
// Copy returns a value-copy of the TableTemplate
|
||||
func (t TableTemplate) Copy() TableTemplate {
|
||||
return TableTemplate{
|
||||
ID: t.ID,
|
||||
Label: t.Label,
|
||||
Prefix: t.Prefix,
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Merge other into t, returning a fresh copy. Does fieldwise max -
|
||||
|
||||
@@ -10,6 +10,9 @@ import (
|
||||
// EdgeMetadatas and Nodes respectively. Edges are directional, and embedded
|
||||
// in the Node struct.
|
||||
type Topology struct {
|
||||
Shape string `json:"shape,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
LabelPlural string `json:"label_plural,omitempty"`
|
||||
Nodes `json:"nodes"`
|
||||
Controls `json:"controls,omitempty"`
|
||||
MetadataTemplates `json:"metadata_templates,omitempty"`
|
||||
@@ -29,6 +32,9 @@ func MakeTopology() Topology {
|
||||
// returning a new topology.
|
||||
func (t Topology) WithMetadataTemplates(other MetadataTemplates) Topology {
|
||||
return Topology{
|
||||
Shape: t.Shape,
|
||||
Label: t.Label,
|
||||
LabelPlural: t.LabelPlural,
|
||||
Nodes: t.Nodes.Copy(),
|
||||
Controls: t.Controls.Copy(),
|
||||
MetadataTemplates: t.MetadataTemplates.Merge(other),
|
||||
@@ -41,6 +47,9 @@ func (t Topology) WithMetadataTemplates(other MetadataTemplates) Topology {
|
||||
// returning a new topology.
|
||||
func (t Topology) WithMetricTemplates(other MetricTemplates) Topology {
|
||||
return Topology{
|
||||
Shape: t.Shape,
|
||||
Label: t.Label,
|
||||
LabelPlural: t.LabelPlural,
|
||||
Nodes: t.Nodes.Copy(),
|
||||
Controls: t.Controls.Copy(),
|
||||
MetadataTemplates: t.MetadataTemplates.Copy(),
|
||||
@@ -53,6 +62,9 @@ func (t Topology) WithMetricTemplates(other MetricTemplates) Topology {
|
||||
// returning a new topology.
|
||||
func (t Topology) WithTableTemplates(other TableTemplates) Topology {
|
||||
return Topology{
|
||||
Shape: t.Shape,
|
||||
Label: t.Label,
|
||||
LabelPlural: t.LabelPlural,
|
||||
Nodes: t.Nodes.Copy(),
|
||||
Controls: t.Controls.Copy(),
|
||||
MetadataTemplates: t.MetadataTemplates.Copy(),
|
||||
@@ -61,6 +73,34 @@ func (t Topology) WithTableTemplates(other TableTemplates) Topology {
|
||||
}
|
||||
}
|
||||
|
||||
// WithShape sets the shape of nodes from this topology, returning a new topology.
|
||||
func (t Topology) WithShape(shape string) Topology {
|
||||
return Topology{
|
||||
Shape: shape,
|
||||
Label: t.Label,
|
||||
LabelPlural: t.LabelPlural,
|
||||
Nodes: t.Nodes.Copy(),
|
||||
Controls: t.Controls.Copy(),
|
||||
MetadataTemplates: t.MetadataTemplates.Copy(),
|
||||
MetricTemplates: t.MetricTemplates.Copy(),
|
||||
TableTemplates: t.TableTemplates.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithLabel sets the label terminology of this topology, returning a new topology.
|
||||
func (t Topology) WithLabel(label, labelPlural string) Topology {
|
||||
return Topology{
|
||||
Shape: t.Shape,
|
||||
Label: label,
|
||||
LabelPlural: labelPlural,
|
||||
Nodes: t.Nodes.Copy(),
|
||||
Controls: t.Controls.Copy(),
|
||||
MetadataTemplates: t.MetadataTemplates.Copy(),
|
||||
MetricTemplates: t.MetricTemplates.Copy(),
|
||||
TableTemplates: t.TableTemplates.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// AddNode adds node to the topology under key nodeID; if a
|
||||
// node already exists for this key, nmd is merged with that node.
|
||||
// The same topology is returned to enable chaining.
|
||||
@@ -74,9 +114,20 @@ func (t Topology) AddNode(node Node) Topology {
|
||||
return t
|
||||
}
|
||||
|
||||
// GetShape returns the current topology shape, or the default if there isn't one.
|
||||
func (t Topology) GetShape() string {
|
||||
if t.Shape == "" {
|
||||
return Circle
|
||||
}
|
||||
return t.Shape
|
||||
}
|
||||
|
||||
// Copy returns a value copy of the Topology.
|
||||
func (t Topology) Copy() Topology {
|
||||
return Topology{
|
||||
Shape: t.Shape,
|
||||
Label: t.Label,
|
||||
LabelPlural: t.LabelPlural,
|
||||
Nodes: t.Nodes.Copy(),
|
||||
Controls: t.Controls.Copy(),
|
||||
MetadataTemplates: t.MetadataTemplates.Copy(),
|
||||
@@ -88,7 +139,18 @@ func (t Topology) Copy() Topology {
|
||||
// Merge merges the other object into this one, and returns the result object.
|
||||
// The original is not modified.
|
||||
func (t Topology) Merge(other Topology) Topology {
|
||||
shape := t.Shape
|
||||
if shape == "" {
|
||||
shape = other.Shape
|
||||
}
|
||||
label, labelPlural := t.Label, t.LabelPlural
|
||||
if label == "" {
|
||||
label, labelPlural = other.Label, other.LabelPlural
|
||||
}
|
||||
return Topology{
|
||||
Shape: shape,
|
||||
Label: label,
|
||||
LabelPlural: labelPlural,
|
||||
Nodes: t.Nodes.Merge(other.Nodes),
|
||||
Controls: t.Controls.Merge(other.Controls),
|
||||
MetadataTemplates: t.MetadataTemplates.Merge(other.MetadataTemplates),
|
||||
|
||||
@@ -248,7 +248,7 @@ var (
|
||||
},
|
||||
MetadataTemplates: process.MetadataTemplates,
|
||||
MetricTemplates: process.MetricTemplates,
|
||||
},
|
||||
}.WithShape(report.Square).WithLabel("process", "processes"),
|
||||
Container: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
ClientContainerNodeID: report.MakeNodeWith(
|
||||
@@ -299,7 +299,7 @@ var (
|
||||
},
|
||||
MetadataTemplates: docker.ContainerMetadataTemplates,
|
||||
MetricTemplates: docker.ContainerMetricTemplates,
|
||||
},
|
||||
}.WithShape(report.Hexagon).WithLabel("container", "containers"),
|
||||
ContainerImage: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
ClientContainerImageNodeID: report.MakeNodeWith(ClientContainerImageNodeID, map[string]string{
|
||||
@@ -322,7 +322,7 @@ var (
|
||||
).WithTopology(report.ContainerImage),
|
||||
},
|
||||
MetadataTemplates: docker.ContainerImageMetadataTemplates,
|
||||
},
|
||||
}.WithShape(report.Hexagon).WithLabel("image", "images"),
|
||||
Host: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
ClientHostNodeID: report.MakeNodeWith(
|
||||
@@ -356,7 +356,7 @@ var (
|
||||
},
|
||||
MetadataTemplates: host.MetadataTemplates,
|
||||
MetricTemplates: host.MetricTemplates,
|
||||
},
|
||||
}.WithShape(report.Circle).WithLabel("host", "hosts"),
|
||||
Pod: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
ClientPodNodeID: report.MakeNodeWith(
|
||||
@@ -388,7 +388,7 @@ var (
|
||||
),
|
||||
},
|
||||
MetadataTemplates: kubernetes.PodMetadataTemplates,
|
||||
},
|
||||
}.WithShape(report.Heptagon).WithLabel("pod", "pods"),
|
||||
Service: report.Topology{
|
||||
Nodes: report.Nodes{
|
||||
ServiceNodeID: report.MakeNodeWith(
|
||||
@@ -400,7 +400,7 @@ var (
|
||||
}).
|
||||
WithTopology(report.Service),
|
||||
},
|
||||
},
|
||||
}.WithShape(report.Heptagon).WithLabel("service", "services"),
|
||||
Sampling: report.Sampling{
|
||||
Count: 1024,
|
||||
Total: 4096,
|
||||
|
||||
Reference in New Issue
Block a user