Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move RenderableNode and DetailedNode into render/ #242

Merged
merged 1 commit into from
Jun 16, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/api_topologies.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"net/http"

"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/render"
)

// APITopologyDesc is returned in a list by the /api/topology handler.
Expand Down Expand Up @@ -52,7 +52,7 @@ func makeTopologyList(rep Reporter) func(w http.ResponseWriter, r *http.Request)
}
}

func stats(r report.RenderableNodes) *topologyStats {
func stats(r render.RenderableNodes) *topologyStats {
var (
nodes int
realNodes int
Expand Down
8 changes: 4 additions & 4 deletions app/api_topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ const (

// APITopology is returned by the /api/topology/{name} handler.
type APITopology struct {
Nodes report.RenderableNodes `json:"nodes"`
Nodes render.RenderableNodes `json:"nodes"`
}

// APINode is returned by the /api/topology/{name}/{id} handler.
type APINode struct {
Node report.DetailedNode `json:"node"`
Node render.DetailedNode `json:"node"`
}

// APIEdge is returned by the /api/topology/*/*/* handlers.
Expand Down Expand Up @@ -67,7 +67,7 @@ func handleNode(rep Reporter, t topologyView, w http.ResponseWriter, r *http.Req
http.NotFound(w, r)
return
}
respondWith(w, http.StatusOK, APINode{Node: report.MakeDetailedNode(rpt, node)})
respondWith(w, http.StatusOK, APINode{Node: render.MakeDetailedNode(rpt, node)})
}

// Individual edges.
Expand Down Expand Up @@ -112,7 +112,7 @@ func handleWebsocket(
}(conn)

var (
previousTopo report.RenderableNodes
previousTopo render.RenderableNodes
tick = time.Tick(loop)
)
for {
Expand Down
2 changes: 1 addition & 1 deletion experimental/graphviz/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func handleHTML(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "</body></html>\n")
}

func dot(w io.Writer, m map[string]report.RenderableNode) {
func dot(w io.Writer, m map[string]render.RenderableNode) {
fmt.Fprintf(w, "digraph G {\n")
fmt.Fprintf(w, "\tgraph [ overlap=false ];\n")
fmt.Fprintf(w, "\tnode [ shape=circle, style=filled ];\n")
Expand Down
49 changes: 38 additions & 11 deletions report/detailed_node.go → render/detailed_node.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
package report
package render

import (
"reflect"
"strconv"

"github.com/weaveworks/scope/report"
)

// DetailedNode is the data type that's yielded to the JavaScript layer when
// we want deep information about an individual node.
type DetailedNode struct {
ID string `json:"id"`
LabelMajor string `json:"label_major"`
LabelMinor string `json:"label_minor,omitempty"`
Pseudo bool `json:"pseudo,omitempty"`
Tables []Table `json:"tables"`
}

// Table is a dataset associated with a node. It will be displayed in the
// detail panel when a user clicks on a node.
type Table struct {
Title string `json:"title"` // e.g. Bandwidth
Numeric bool `json:"numeric"` // should the major column be right-aligned?
Rows []Row `json:"rows"`
}

// Row is a single entry in a Table dataset.
type Row struct {
Key string `json:"key"` // e.g. Ingress
ValueMajor string `json:"value_major"` // e.g. 25
ValueMinor string `json:"value_minor,omitempty"` // e.g. KB/s
}

// MakeDetailedNode transforms a renderable node to a detailed node. It uses
// aggregate metadata, plus the set of origin node IDs, to produce tables.
func MakeDetailedNode(r Report, n RenderableNode) DetailedNode {
func MakeDetailedNode(r report.Report, n RenderableNode) DetailedNode {
tables := []Table{}
{
rows := []Row{}
if val, ok := n.Metadata[KeyMaxConnCountTCP]; ok {
if val, ok := n.Metadata[report.KeyMaxConnCountTCP]; ok {
rows = append(rows, Row{"TCP connections", strconv.FormatInt(int64(val), 10), ""})
}
if val, ok := n.Metadata[KeyBytesIngress]; ok {
if val, ok := n.Metadata[report.KeyBytesIngress]; ok {
rows = append(rows, Row{"Bytes ingress", strconv.FormatInt(int64(val), 10), ""})
}
if val, ok := n.Metadata[KeyBytesEgress]; ok {
if val, ok := n.Metadata[report.KeyBytesEgress]; ok {
rows = append(rows, Row{"Bytes egress", strconv.FormatInt(int64(val), 10), ""})
}
if len(rows) > 0 {
Expand Down Expand Up @@ -53,7 +80,7 @@ outer:

// OriginTable produces a table (to be consumed directly by the UI) based on
// an origin ID, which is (optimistically) a node ID in one of our topologies.
func OriginTable(r Report, originID string) (Table, bool) {
func OriginTable(r report.Report, originID string) (Table, bool) {
if nmd, ok := r.Endpoint.NodeMetadatas[originID]; ok {
return endpointOriginTable(nmd)
}
Expand All @@ -72,7 +99,7 @@ func OriginTable(r Report, originID string) (Table, bool) {
return Table{}, false
}

func endpointOriginTable(nmd NodeMetadata) (Table, bool) {
func endpointOriginTable(nmd report.NodeMetadata) (Table, bool) {
rows := []Row{}
for _, tuple := range []struct{ key, human string }{
{"endpoint", "Endpoint"},
Expand All @@ -91,7 +118,7 @@ func endpointOriginTable(nmd NodeMetadata) (Table, bool) {
}, len(rows) > 0
}

func addressOriginTable(nmd NodeMetadata) (Table, bool) {
func addressOriginTable(nmd report.NodeMetadata) (Table, bool) {
rows := []Row{}
if val, ok := nmd["address"]; ok {
rows = append(rows, Row{"Address", val, ""})
Expand All @@ -106,7 +133,7 @@ func addressOriginTable(nmd NodeMetadata) (Table, bool) {
}, len(rows) > 0
}

func processOriginTable(nmd NodeMetadata) (Table, bool) {
func processOriginTable(nmd report.NodeMetadata) (Table, bool) {
rows := []Row{}
if val, ok := nmd["comm"]; ok {
rows = append(rows, Row{"Name (comm)", val, ""})
Expand All @@ -124,7 +151,7 @@ func processOriginTable(nmd NodeMetadata) (Table, bool) {
}, len(rows) > 0
}

func containerOriginTable(nmd NodeMetadata) (Table, bool) {
func containerOriginTable(nmd report.NodeMetadata) (Table, bool) {
rows := []Row{}
for _, tuple := range []struct{ key, human string }{
{"docker_container_id", "Container ID"},
Expand All @@ -143,7 +170,7 @@ func containerOriginTable(nmd NodeMetadata) (Table, bool) {
}, len(rows) > 0
}

func hostOriginTable(nmd NodeMetadata) (Table, bool) {
func hostOriginTable(nmd report.NodeMetadata) (Table, bool) {
rows := []Row{}
if val, ok := nmd["host_name"]; ok {
rows = append(rows, Row{"Host name", val, ""})
Expand Down
23 changes: 14 additions & 9 deletions report/detailed_node_test.go → render/detailed_node_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package report_test
package render_test

import (
"reflect"
"testing"

"github.com/weaveworks/scope/render"
"github.com/weaveworks/scope/report"
)

Expand All @@ -12,41 +13,45 @@ func TestMakeDetailedNode(t *testing.T) {
}

func TestOriginTable(t *testing.T) {
if _, ok := report.OriginTable(reportFixture, "not-found"); ok {
if _, ok := render.OriginTable(rpt, "not-found"); ok {
t.Errorf("unknown origin ID gave unexpected success")
}
for originID, want := range map[string]report.Table{
client54001EndpointNodeID: {
for originID, want := range map[string]render.Table{
client54001NodeID: {
Title: "Origin Endpoint",
Numeric: false,
Rows: []report.Row{{"Host name", clientHostName, ""}},
Rows: []render.Row{
{"Host name", clientHostName, ""},
{"PID", "10001", ""},
{"Process name", "curl", ""},
},
},
clientAddressNodeID: {
Title: "Origin Address",
Numeric: false,
Rows: []report.Row{
Rows: []render.Row{
{"Host name", clientHostName, ""},
},
},
report.MakeProcessNodeID(clientHostID, "4242"): {
Title: "Origin Process",
Numeric: false,
Rows: []report.Row{
Rows: []render.Row{
{"Name (comm)", "curl", ""},
{"PID", "4242", ""},
},
},
serverHostNodeID: {
Title: "Origin Host",
Numeric: false,
Rows: []report.Row{
Rows: []render.Row{
{"Host name", serverHostName, ""},
{"Load", "0.01 0.01 0.01", ""},
{"Operating system", "Linux", ""},
},
},
} {
have, ok := report.OriginTable(reportFixture, originID)
have, ok := render.OriginTable(rpt, originID)
if !ok {
t.Errorf("%q: not OK", originID)
continue
Expand Down
32 changes: 16 additions & 16 deletions render/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (

const humanTheInternet = "the Internet"

func newRenderableNode(id, major, minor, rank string) report.RenderableNode {
return report.RenderableNode{
func newRenderableNode(id, major, minor, rank string) RenderableNode {
return RenderableNode{
ID: id,
LabelMajor: major,
LabelMinor: minor,
Expand All @@ -20,8 +20,8 @@ func newRenderableNode(id, major, minor, rank string) report.RenderableNode {
}
}

func newPseudoNode(id, major, minor string) report.RenderableNode {
return report.RenderableNode{
func newPseudoNode(id, major, minor string) RenderableNode {
return RenderableNode{
ID: id,
LabelMajor: major,
LabelMinor: minor,
Expand All @@ -41,18 +41,18 @@ func newPseudoNode(id, major, minor string) report.RenderableNode {
//
// If the final output parameter is false, the node shall be omitted from the
// rendered topology.
type MapFunc func(report.NodeMetadata) (report.RenderableNode, bool)
type MapFunc func(report.NodeMetadata) (RenderableNode, bool)

// PseudoFunc creates RenderableNode representing pseudo nodes given the dstNodeID.
// The srcNode renderable node is essentially from MapFunc, representing one of
// the rendered nodes this pseudo node refers to. srcNodeID and dstNodeID are
// node IDs prior to mapping.
type PseudoFunc func(srcNodeID string, srcNode report.RenderableNode, dstNodeID string) (report.RenderableNode, bool)
type PseudoFunc func(srcNodeID string, srcNode RenderableNode, dstNodeID string) (RenderableNode, bool)

// ProcessPID takes a node NodeMetadata from topology, and returns a
// representation with the ID based on the process PID and the labels based on
// the process name.
func ProcessPID(m report.NodeMetadata) (report.RenderableNode, bool) {
func ProcessPID(m report.NodeMetadata) (RenderableNode, bool) {
var (
identifier = fmt.Sprintf("%s:%s:%s", "pid", m["domain"], m["pid"])
minor = fmt.Sprintf("%s (%s)", m["domain"], m["pid"])
Expand All @@ -65,7 +65,7 @@ func ProcessPID(m report.NodeMetadata) (report.RenderableNode, bool) {
// ProcessName takes a node NodeMetadata from a topology, and returns a
// representation with the ID based on the process name (grouping all
// processes with the same name together).
func ProcessName(m report.NodeMetadata) (report.RenderableNode, bool) {
func ProcessName(m report.NodeMetadata) (RenderableNode, bool) {
show := m["pid"] != "" && m["name"] != ""
return newRenderableNode(m["name"], m["name"], "", m["name"]), show
}
Expand All @@ -74,7 +74,7 @@ func ProcessName(m report.NodeMetadata) (report.RenderableNode, bool) {
// in. We consider container and image IDs to be globally unique, and so don't
// scope them further by e.g. host. If no container metadata is found, nodes are
// grouped into the Uncontained node.
func MapEndpoint2Container(m report.NodeMetadata) (report.RenderableNode, bool) {
func MapEndpoint2Container(m report.NodeMetadata) (RenderableNode, bool) {
var id, major, minor, rank string
if m["docker_container_id"] == "" {
id, major, minor, rank = "uncontained", "Uncontained", "", "uncontained"
Expand All @@ -86,7 +86,7 @@ func MapEndpoint2Container(m report.NodeMetadata) (report.RenderableNode, bool)
}

// MapContainerIdentity maps container topology node to container mapped nodes.
func MapContainerIdentity(m report.NodeMetadata) (report.RenderableNode, bool) {
func MapContainerIdentity(m report.NodeMetadata) (RenderableNode, bool) {
var id, major, minor, rank string
if m["docker_container_id"] == "" {
id, major, minor, rank = "uncontained", "Uncontained", "", "uncontained"
Expand All @@ -100,7 +100,7 @@ func MapContainerIdentity(m report.NodeMetadata) (report.RenderableNode, bool) {
// ProcessContainerImage maps topology nodes to the container images they run
// on. If no container metadata is found, nodes are grouped into the
// Uncontained node.
func ProcessContainerImage(m report.NodeMetadata) (report.RenderableNode, bool) {
func ProcessContainerImage(m report.NodeMetadata) (RenderableNode, bool) {
var id, major, minor, rank string
if m["docker_image_id"] == "" {
id, major, minor, rank = "uncontained", "Uncontained", "", "uncontained"
Expand All @@ -114,7 +114,7 @@ func ProcessContainerImage(m report.NodeMetadata) (report.RenderableNode, bool)
// NetworkHostname takes a node NodeMetadata and returns a representation
// based on the hostname. Major label is the hostname, the minor label is the
// domain, if any.
func NetworkHostname(m report.NodeMetadata) (report.RenderableNode, bool) {
func NetworkHostname(m report.NodeMetadata) (RenderableNode, bool) {
var (
name = m["name"]
domain = ""
Expand All @@ -130,7 +130,7 @@ func NetworkHostname(m report.NodeMetadata) (report.RenderableNode, bool) {

// GenericPseudoNode contains heuristics for building sensible pseudo nodes.
// It should go away.
func GenericPseudoNode(src string, srcMapped report.RenderableNode, dst string) (report.RenderableNode, bool) {
func GenericPseudoNode(src string, srcMapped RenderableNode, dst string) (RenderableNode, bool) {
var maj, min, outputID string

if dst == report.TheInternet {
Expand All @@ -151,7 +151,7 @@ func GenericPseudoNode(src string, srcMapped report.RenderableNode, dst string)

// GenericGroupedPseudoNode contains heuristics for building sensible pseudo nodes.
// It should go away.
func GenericGroupedPseudoNode(src string, srcMapped report.RenderableNode, dst string) (report.RenderableNode, bool) {
func GenericGroupedPseudoNode(src string, srcMapped RenderableNode, dst string) (RenderableNode, bool) {
var maj, min, outputID string

if dst == report.TheInternet {
Expand All @@ -169,11 +169,11 @@ func GenericGroupedPseudoNode(src string, srcMapped report.RenderableNode, dst s
}

// InternetOnlyPseudoNode never creates a pseudo node, unless it's the Internet.
func InternetOnlyPseudoNode(_ string, _ report.RenderableNode, dst string) (report.RenderableNode, bool) {
func InternetOnlyPseudoNode(_ string, _ RenderableNode, dst string) (RenderableNode, bool) {
if dst == report.TheInternet {
return newPseudoNode(report.TheInternet, humanTheInternet, ""), true
}
return report.RenderableNode{}, false
return RenderableNode{}, false
}

// trySplitAddr is basically ParseArbitraryNodeID, since its callsites
Expand Down
Loading