mirror of
https://github.com/weaveworks/scope.git
synced 2026-08-19 04:16:21 +00:00
Expressions renderer
This commit is contained in:
+14
-16
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user