Expressions renderer

This commit is contained in:
Peter Bourgon
2015-09-01 10:20:23 +02:00
parent fbc5ef2c8e
commit 3f852c6822
11 changed files with 201 additions and 69 deletions
+14 -16
View File
@@ -2,7 +2,6 @@ package dsl
import (
"fmt"
"log"
"math/rand"
"net"
"regexp"
@@ -10,7 +9,6 @@ import (
"github.com/weaveworks/scope/probe/endpoint"
"github.com/weaveworks/scope/probe/host"
"github.com/weaveworks/scope/render"
"github.com/weaveworks/scope/report"
)
@@ -51,7 +49,7 @@ func selectAll(tpy report.Topology) []string {
for id := range tpy.NodeMetadatas {
out = append(out, id)
}
log.Printf("select ALL: %d", len(out))
//log.Printf("select ALL: %d", len(out))
return out
}
@@ -73,7 +71,7 @@ func selectConnected(tpy report.Topology) []string {
out = append(out, id)
}
}
log.Printf("select CONNECTED: %d", len(out))
//log.Printf("select CONNECTED: %d", len(out))
return out
}
@@ -82,7 +80,7 @@ func selectNonlocal(tpy report.Topology) []string {
for _, md := range tpy.NodeMetadatas {
for k, v := range md.Metadata {
if k == host.LocalNetworks {
local = append(local, render.ParseNetworks(v)...)
local = append(local, report.ParseNetworks(v)...)
}
}
}
@@ -107,14 +105,14 @@ func selectNonlocal(tpy report.Topology) []string {
}
}
}
log.Printf("select NONLOCAL: %d", len(out))
//log.Printf("select NONLOCAL: %d", len(out))
return out
}
func selectLike(s string) selector {
re, err := regexp.Compile(s)
if err != nil {
log.Printf("select LIKE %q: %v", s, err)
//log.Printf("select LIKE %q: %v", s, err)
re = regexp.MustCompile("")
}
return func(tpy report.Topology) []string {
@@ -124,7 +122,7 @@ func selectLike(s string) selector {
out = append(out, id)
}
}
log.Printf("select LIKE %q: %d", s, len(out))
//log.Printf("select LIKE %q: %d", s, len(out))
return out
}
}
@@ -146,7 +144,7 @@ func selectWith(s string) selector {
}
}
}
log.Printf("select WITH %q: %d", s, len(out))
//log.Printf("select WITH %q: %d", s, len(out))
return out
}
}
@@ -164,7 +162,7 @@ func selectNot(s selector) selector {
}
out = append(out, id)
}
log.Printf("select NOT: %d", len(out))
//log.Printf("select NOT: %d", len(out))
return out
}
}
@@ -175,7 +173,7 @@ func transformHighlight(tpy report.Topology, ids []string) report.Topology {
for _, id := range ids {
tpy.NodeMetadatas[id] = tpy.NodeMetadatas[id].Merge(report.MakeNodeMetadataWith(map[string]string{highlightKey: "true"}))
}
log.Printf("transform HIGHLIGHT %d: OK", len(ids))
//log.Printf("transform HIGHLIGHT %d: OK", len(ids))
return tpy
}
@@ -192,7 +190,7 @@ func transformRemove(tpy report.Topology, ids []string) report.Topology {
cp(out, tpy, id)
}
clean(out, toRemove)
log.Printf("transform REMOVE %d: in %d, out %d", len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
//log.Printf("transform REMOVE %d: in %d, out %d", len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
return out
}
@@ -204,7 +202,7 @@ func transformShowOnly(tpy report.Topology, ids []string) report.Topology {
}
cp(out, tpy, id)
}
log.Printf("transform SHOWONLY %d: in %d, out %d", len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
//log.Printf("transform SHOWONLY %d: in %d, out %d", len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
return out
}
@@ -222,7 +220,7 @@ func transformMerge(tpy report.Topology, ids []string) report.Topology {
cp(out, tpy, id)
}
}
log.Printf("transform MERGE %d: in %d, out %d", len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
//log.Printf("transform MERGE %d: in %d, out %d", len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
return out
}
@@ -269,7 +267,7 @@ func transformGroupBy(s string) transformer {
}
}
log.Printf("transform GROUPBY %v %d: in %d, out %d", keys, len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
//log.Printf("transform GROUPBY %v %d: in %d, out %d", keys, len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
return out
}
}
@@ -310,7 +308,7 @@ func transformJoin(key string) transformer {
out.NodeMetadatas[id] = md // write
}
log.Printf("transform JOIN %v %d: in %d, out %d", key, len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
//log.Printf("transform JOIN %v %d: in %d, out %d", key, len(ids), len(tpy.NodeMetadatas), len(out.NodeMetadatas))
return out
}
}
+2 -2
View File
@@ -21,8 +21,8 @@ var fixture = report.Topology{
"c": report.MakeNodeMetadataWith(map[string]string{"is-a-or-b-or-c": "true"}),
},
EdgeMetadatas: map[string]report.EdgeMetadata{
report.MakeEdgeID("a", "c"): report.EdgeMetadata{EgressPacketCount: newu64(1)},
report.MakeEdgeID("b", "c"): report.EdgeMetadata{EgressPacketCount: newu64(2)},
report.MakeEdgeID("a", "c"): {EgressPacketCount: newu64(1)},
report.MakeEdgeID("b", "c"): {EgressPacketCount: newu64(2)},
},
}
-1
View File
@@ -97,7 +97,6 @@ func ParseExpressions(strs ...string) Expressions {
log.Printf("%s: %v", str, err)
continue
}
log.Printf("%s: OK", str)
exprs = append(exprs, expr)
}
return exprs
+85
View File
@@ -1,8 +1,11 @@
package render
import (
"fmt"
"log"
"strings"
"github.com/weaveworks/scope/render/dsl"
"github.com/weaveworks/scope/report"
)
@@ -354,3 +357,85 @@ func (f Filter) Render(rpt report.Report) RenderableNodes {
}
return output
}
// ExpressionRenderer is a Renderer that's based on a set of DSL expressions.
func ExpressionRenderer(exprStrs ...string) Renderer {
return expressionRenderer{dsl.ParseExpressions(exprStrs...)}
}
type expressionRenderer struct {
exprs dsl.Expressions
}
func (r expressionRenderer) Render(rpt report.Report) RenderableNodes {
// Flatten all the topologies.
tpy := report.MakeTopology()
for _, t := range rpt.Topologies() {
if err := conflict(tpy, t); err != nil {
log.Printf("conflict in node IDs: %v", err) // oh well...
}
tpy = tpy.Merge(t)
}
// Evaluate expressions.
tpy = r.exprs.Eval(tpy)
// Convert to RenderableNodes.
return tpy2rns(tpy)
}
func (r expressionRenderer) EdgeMetadata(rpt report.Report, localID, remoteID string) report.EdgeMetadata {
return report.EdgeMetadata{} // TODO(pb)
}
func tpy2rns(tpy report.Topology) RenderableNodes {
out := RenderableNodes{}
// First, get the nodes.
for id, md := range tpy.NodeMetadatas {
var (
major = "" // TODO(pb)
minor = "" // TODO(pb)
rank = "" // TODO(pb)
)
out[id] = NewRenderableNode(id, major, minor, rank, md)
}
// Then, inject the adjacencies.
for adjacencyID, dstIDs := range tpy.Adjacency {
srcID, ok := report.ParseAdjacencyID(adjacencyID)
if !ok {
log.Printf("invalid adjacency ID %q", adjacencyID)
continue
}
node := out[srcID]
node.Adjacency = dstIDs
out[srcID] = node
}
// TODO(pb): we have no way to track origins at the moment. We should have
// a separate NodeMetadata.Sets field, and push origin IDs there when we
// MERGE or GROUPBY.
// TODO(pb): EdgeMetadata
return out
}
func conflict(a, b report.Topology) error {
var errs []string
for id := range a.NodeMetadatas {
if _, ok := b.NodeMetadatas[id]; ok {
errs = append(errs, id)
}
}
for id := range b.NodeMetadatas {
if _, ok := a.NodeMetadatas[id]; ok {
errs = append(errs, id)
}
}
if len(errs) > 0 {
return fmt.Errorf(strings.Join(errs, ", "))
}
return nil
}
+16 -22
View File
@@ -13,33 +13,27 @@ import (
// used to determine which nodes in the report are "remote", i.e. outside of
// our infrastructure.
func LocalNetworks(r report.Report) report.Networks {
result := report.Networks{}
var (
result = report.Networks{}
networks = map[string]struct{}{}
)
for _, md := range r.Host.NodeMetadatas {
val, ok := md.Metadata[host.LocalNetworks]
if !ok {
continue
}
result = append(result, ParseNetworks(val)...)
for _, s := range strings.Fields(val) {
_, ipNet, err := net.ParseCIDR(s)
if err != nil {
continue
}
_, ok := networks[ipNet.String()]
if !ok {
result = append(result, ipNet)
networks[ipNet.String()] = struct{}{}
}
}
}
return result
}
// ParseNetworks converts a string of space-separated CIDRs to a
// report.Networks.
func ParseNetworks(v string) report.Networks {
var (
nets = report.Networks{}
set = map[string]struct{}{}
)
for _, s := range strings.Fields(v) {
_, ipNet, err := net.ParseCIDR(s)
if err != nil {
continue
}
if _, ok := set[ipNet.String()]; !ok {
nets = append(nets, ipNet)
set[ipNet.String()] = struct{}{}
}
}
return nets
}
-25
View File
@@ -1,7 +1,6 @@
package render_test
import (
"fmt"
"net"
"reflect"
"testing"
@@ -33,30 +32,6 @@ func TestReportLocalNetworks(t *testing.T) {
}
}
func TestParseNetworks(t *testing.T) {
var (
hugenetStr = "1.0.0.0/8"
bignetStr = "10.1.0.1/16"
smallnetStr = "5.6.7.8/32"
hugenet = mustParseCIDR(hugenetStr)
bignet = mustParseCIDR(bignetStr)
smallnet = mustParseCIDR(smallnetStr)
)
for _, tc := range []struct {
input string
want report.Networks
}{
{"", report.Networks{}},
{fmt.Sprintf("%s", bignetStr), report.Networks([]*net.IPNet{bignet})},
{fmt.Sprintf("%s %s", bignetStr, bignetStr), report.Networks([]*net.IPNet{bignet})},
{fmt.Sprintf("%s foo %s oops %s", hugenetStr, smallnetStr, hugenetStr), report.Networks([]*net.IPNet{hugenet, smallnet})},
} {
if want, have := tc.want, render.ParseNetworks(tc.input); !reflect.DeepEqual(want, have) {
t.Error(test.Diff(want, have))
}
}
}
func mustParseCIDR(s string) *net.IPNet {
_, ipNet, err := net.ParseCIDR(s)
if err != nil {