diff --git a/render/mapping.go b/render/mapping.go index edc5d5acd..444591fc6 100644 --- a/render/mapping.go +++ b/render/mapping.go @@ -36,24 +36,24 @@ type PseudoFunc func(srcNodeID string, srcNode RenderableNode, dstNodeID string) // MapFunc is anything which can take an arbitrary RenderableNode and // return another RenderableNode. // -// As with LeadMapFunc, if the final output parameter is false, the node +// As with LeafMapFunc, if the final output parameter is false, the node // shall be omitted from the rendered topology. type MapFunc func(RenderableNode) (RenderableNode, bool) -// MapEndpointIdentity maps a endpoint topology node to endpoint RenderableNode node. -// As it is only ever run on endpoint topology nodes, we can safely assume the -// presences of certain keys. +// MapEndpointIdentity maps a endpoint topology node to endpoint RenderableNode +// node. As it is only ever run on endpoint topology nodes, we can safely +// assume the presence of certain keys. func MapEndpointIdentity(m report.NodeMetadata) (RenderableNode, bool) { var ( - id = fmt.Sprintf("endpoint:%s:%s:%s", getHostname(m), m["addr"], m["port"]) + id = fmt.Sprintf("endpoint:%s:%s:%s", report.ExtractHostID(m), m["addr"], m["port"]) major = fmt.Sprintf("%s:%s", m["addr"], m["port"]) pid, ok = m["pid"] - minor = getHostname(m) + minor = report.ExtractHostID(m) rank = major ) if ok { - minor = fmt.Sprintf("%s (%s)", getHostname(m), pid) + minor = fmt.Sprintf("%s (%s)", report.ExtractHostID(m), pid) } return NewRenderableNode(id, major, minor, rank, m), true @@ -61,26 +61,26 @@ func MapEndpointIdentity(m report.NodeMetadata) (RenderableNode, bool) { // MapProcessIdentity maps a process topology node to process RenderableNode node. // As it is only ever run on process topology nodes, we can safely assume the -// presences of certain keys. +// presence of certain keys. func MapProcessIdentity(m report.NodeMetadata) (RenderableNode, bool) { var ( - id = fmt.Sprintf("pid:%s:%s", getHostname(m), m["pid"]) + id = fmt.Sprintf("pid:%s:%s", report.ExtractHostID(m), m["pid"]) major = m["comm"] - minor = fmt.Sprintf("%s (%s)", getHostname(m), m["pid"]) + minor = fmt.Sprintf("%s (%s)", report.ExtractHostID(m), m["pid"]) rank = m["pid"] ) return NewRenderableNode(id, major, minor, rank, m), true } -// MapContainerIdentity maps a container topology node to container +// MapContainerIdentity maps a container topology node to a container // RenderableNode node. As it is only ever run on container topology // nodes, we can safely assume the presences of certain keys. func MapContainerIdentity(m report.NodeMetadata) (RenderableNode, bool) { var ( id = m["docker_container_id"] major = m["docker_container_name"] - minor = getHostname(m) + minor = report.ExtractHostID(m) rank = m["docker_image_id"] ) @@ -109,7 +109,7 @@ func MapEndpoint2Process(n RenderableNode) (RenderableNode, bool) { return RenderableNode{}, false } - id := fmt.Sprintf("pid:%s:%s", getHostname(n.NodeMetadata), pid) + id := fmt.Sprintf("pid:%s:%s", report.ExtractHostID(n.NodeMetadata), pid) return newDerivedNode(id, n), true } @@ -156,11 +156,6 @@ func MapProcess2Name(n RenderableNode) (RenderableNode, bool) { return node, true } -func getHostname(m report.NodeMetadata) string { - hostname, _, _ := report.ParseNodeID(m[report.HostNodeID]) - return hostname -} - // ProcessContainerImage maps topology nodes to the container images they run // on. If no container metadata is found, nodes are grouped into the // Uncontained node. diff --git a/render/render.go b/render/render.go index 7dce85d27..97d54ce03 100644 --- a/render/render.go +++ b/render/render.go @@ -6,25 +6,25 @@ import ( "github.com/weaveworks/scope/report" ) -// Renderer is something that can render a report to a set of RenderableNodes +// Renderer is something that can render a report to a set of RenderableNodes. type Renderer interface { Render(report.Report) RenderableNodes AggregateMetadata(rpt report.Report, localID, remoteID string) report.AggregateMetadata } // Reduce renderer is a Renderer which merges together the output of several -// other renderers +// other renderers. type Reduce []Renderer -// Map is a Renderer which produces a set of RendererNodes from the set of -// RendererNodes produces by another Renderer +// Map is a Renderer which produces a set of RenderableNodes from the set of +// RenderableNodes produced by another Renderer. type Map struct { MapFunc Renderer } -// LeafMap is a Renderer which produces a set of RendererNodes from a report.Topology -// by using a map functions and topology selector. +// LeafMap is a Renderer which produces a set of RenderableNodes from a report.Topology +// by using a map function and topology selector. type LeafMap struct { Selector report.TopologySelector Mapper LeafMapFunc @@ -36,12 +36,12 @@ type FilterUnconnected struct { Renderer } -// MakeReduce is the only sane way to produce a Reduce Renderer +// MakeReduce is the only sane way to produce a Reduce Renderer. func MakeReduce(renderers ...Renderer) Renderer { return Reduce(renderers) } -// Render produces a set of RenderableNodes given a Report +// Render produces a set of RenderableNodes given a Report. func (r Reduce) Render(rpt report.Report) RenderableNodes { result := RenderableNodes{} for _, renderer := range r { @@ -50,7 +50,7 @@ func (r Reduce) Render(rpt report.Report) RenderableNodes { return result } -// AggregateMetadata produces an AggregateMetadata for a given edge +// AggregateMetadata produces an AggregateMetadata for a given edge. func (r Reduce) AggregateMetadata(rpt report.Report, localID, remoteID string) report.AggregateMetadata { metadata := report.AggregateMetadata{} for _, renderer := range r { @@ -59,7 +59,7 @@ func (r Reduce) AggregateMetadata(rpt report.Report, localID, remoteID string) r return metadata } -// Render transforms a set of RendererNodes produces by another Renderer +// Render transforms a set of RenderableNodes produces by another Renderer. // using a map function func (m Map) Render(rpt report.Report) RenderableNodes { output, _ := m.render(rpt) @@ -89,14 +89,13 @@ func (m Map) render(rpt report.Report) (RenderableNodes, map[string]string) { } // Rewrite Adjacency for new node IDs. - // NB we don't do pseudo nodes here; we assumer the input graph - // we properly-connected, and if the map func dropped a node, + // NB we don't do pseudo nodes here; we assume the input graph + // is properly-connected, and if the map func dropped a node, // we drop links to it. for outNodeID, inAdjacency := range adjacencies { outAdjacency := report.MakeIDList() for _, inAdjacent := range inAdjacency { - outAdjacent, ok := mapped[inAdjacent] - if ok { + if outAdjacent, ok := mapped[inAdjacent]; ok { outAdjacency = outAdjacency.Add(outAdjacent) } } diff --git a/render/render_test.go b/render/render_test.go index 99752b61a..b0ff17399 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -48,63 +48,61 @@ func TestReduceEdge(t *testing.T) { } } -func TestMapRender(t *testing.T) { +func TestMapRender1(t *testing.T) { // 1. Check when we return false, the node gets filtered out - { - mapper := render.Map{ - MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) { - return render.RenderableNode{}, false - }, - Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ - "foo": {ID: "foo"}, - }}, - } - want := render.RenderableNodes{} - have := mapper.Render(report.MakeReport()) - if !reflect.DeepEqual(want, have) { - t.Errorf("want %+v, have %+v", want, have) - } + mapper := render.Map{ + MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) { + return render.RenderableNode{}, false + }, + Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ + "foo": {ID: "foo"}, + }}, } + want := render.RenderableNodes{} + have := mapper.Render(report.MakeReport()) + if !reflect.DeepEqual(want, have) { + t.Errorf("want %+v, have %+v", want, have) + } +} +func TestMapRender2(t *testing.T) { // 2. Check we can remap two nodes into one - { - mapper := render.Map{ - MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) { - return render.RenderableNode{ID: "bar"}, true - }, - Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ - "foo": {ID: "foo"}, - "baz": {ID: "baz"}, - }}, - } - want := render.RenderableNodes{ - "bar": render.RenderableNode{ID: "bar"}, - } - have := mapper.Render(report.MakeReport()) - if !reflect.DeepEqual(want, have) { - t.Errorf("want %+v, have %+v", want, have) - } + mapper := render.Map{ + MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) { + return render.RenderableNode{ID: "bar"}, true + }, + Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ + "foo": {ID: "foo"}, + "baz": {ID: "baz"}, + }}, } + want := render.RenderableNodes{ + "bar": render.RenderableNode{ID: "bar"}, + } + have := mapper.Render(report.MakeReport()) + if !reflect.DeepEqual(want, have) { + t.Errorf("want %+v, have %+v", want, have) + } +} +func TestMapRender3(t *testing.T) { // 3. Check we can remap adjacencies - { - mapper := render.Map{ - MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) { - return render.RenderableNode{ID: "_" + nodes.ID}, true - }, - Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ - "foo": {ID: "foo", Adjacency: report.MakeIDList("baz")}, - "baz": {ID: "baz", Adjacency: report.MakeIDList("foo")}, - }}, - } - want := render.RenderableNodes{ - "_foo": {ID: "_foo", Adjacency: report.MakeIDList("_baz")}, - "_baz": {ID: "_baz", Adjacency: report.MakeIDList("_foo")}, - } - have := mapper.Render(report.MakeReport()) - if !reflect.DeepEqual(want, have) { - t.Errorf("want %+v, have %+v", want, have) - } + mapper := render.Map{ + MapFunc: func(nodes render.RenderableNode) (render.RenderableNode, bool) { + return render.RenderableNode{ID: "_" + nodes.ID}, true + }, + Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{ + "foo": {ID: "foo", Adjacency: report.MakeIDList("baz")}, + "baz": {ID: "baz", Adjacency: report.MakeIDList("foo")}, + }}, + } + want := render.RenderableNodes{ + "_foo": {ID: "_foo", Adjacency: report.MakeIDList("_baz")}, + "_baz": {ID: "_baz", Adjacency: report.MakeIDList("_foo")}, + } + have := mapper.Render(report.MakeReport()) + if !reflect.DeepEqual(want, have) { + t.Errorf("want %+v, have %+v", want, have) } } diff --git a/report/id.go b/report/id.go index df7c300e1..f29a91905 100644 --- a/report/id.go +++ b/report/id.go @@ -97,6 +97,12 @@ func ParseNodeID(nodeID string) (hostID string, remainder string, ok bool) { return fields[0], fields[1], true } +// ExtractHostID extracts the host id from NodeMetadata +func ExtractHostID(m NodeMetadata) string { + hostid, _, _ := ParseNodeID(m[HostNodeID]) + return hostid +} + // MakePseudoNodeID produces a pseudo node ID from its composite parts. func MakePseudoNodeID(parts ...string) string { return strings.Join(append([]string{"pseudo"}, parts...), ScopeDelim)