mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
2
Makefile
2
Makefile
@@ -23,7 +23,7 @@ $(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) docker/*
|
||||
|
||||
$(APP_EXE): app/*.go render/*.go report/*.go xfer/*.go
|
||||
|
||||
$(PROBE_EXE): probe/*.go probe/docker/*.go probe/endpoint/*.go probe/host/*.go probe/process/*.go probe/tag/*.go report/*.go xfer/*.go
|
||||
$(PROBE_EXE): probe/*.go probe/docker/*.go probe/endpoint/*.go probe/host/*.go probe/process/*.go probe/overlay/*.go report/*.go xfer/*.go
|
||||
|
||||
$(APP_EXE) $(PROBE_EXE):
|
||||
go get -tags netgo ./$(@D)
|
||||
|
||||
@@ -53,9 +53,8 @@ func TestContainer(t *testing.T) {
|
||||
// Send some stats to the docker container
|
||||
stats := &client.Stats{}
|
||||
stats.MemoryStats.Usage = 12345
|
||||
err = json.NewEncoder(writer).Encode(&stats)
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
if err = json.NewEncoder(writer).Encode(&stats); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
runtime.Gosched() // wait for StartGatheringStats goroutine to receive the stats
|
||||
|
||||
|
||||
@@ -149,7 +149,6 @@ func applyNAT(rpt report.Report, scope string) error {
|
||||
func conntrackModulePresent() bool {
|
||||
f, err := os.Open(modules)
|
||||
if err != nil {
|
||||
log.Printf("conntrack error: %v", err)
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
@@ -8,11 +8,11 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/weaveworks/procspy"
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
type reporter struct {
|
||||
// Reporter generates Reports containing the Endpoint topology.
|
||||
type Reporter struct {
|
||||
hostID string
|
||||
hostName string
|
||||
includeProcesses bool
|
||||
@@ -33,10 +33,11 @@ var SpyDuration = prometheus.NewSummaryVec(
|
||||
|
||||
// NewReporter creates a new Reporter that invokes procspy.Connections to
|
||||
// generate a report.Report that contains every discovered (spied) connection
|
||||
// on the host machine, at the granularity of host and port. It optionally
|
||||
// enriches that topology with process (PID) information.
|
||||
func NewReporter(hostID, hostName string, includeProcesses bool) tag.Reporter {
|
||||
return &reporter{
|
||||
// on the host machine, at the granularity of host and port. That information
|
||||
// is stored in the Endpoint topology. It optionally enriches that topology
|
||||
// with process (PID) information.
|
||||
func NewReporter(hostID, hostName string, includeProcesses bool) *Reporter {
|
||||
return &Reporter{
|
||||
hostID: hostID,
|
||||
hostName: hostName,
|
||||
includeProcesses: includeProcesses,
|
||||
@@ -44,62 +45,63 @@ func NewReporter(hostID, hostName string, includeProcesses bool) tag.Reporter {
|
||||
}
|
||||
}
|
||||
|
||||
func (rep *reporter) Report() (report.Report, error) {
|
||||
// Report implements Reporter.
|
||||
func (r *Reporter) Report() (report.Report, error) {
|
||||
defer func(begin time.Time) {
|
||||
SpyDuration.WithLabelValues().Observe(float64(time.Since(begin)))
|
||||
}(time.Now())
|
||||
|
||||
r := report.MakeReport()
|
||||
conns, err := procspy.Connections(rep.includeProcesses)
|
||||
rpt := report.MakeReport()
|
||||
conns, err := procspy.Connections(r.includeProcesses)
|
||||
if err != nil {
|
||||
return r, err
|
||||
return rpt, err
|
||||
}
|
||||
|
||||
for conn := conns.Next(); conn != nil; conn = conns.Next() {
|
||||
rep.addConnection(&r, conn)
|
||||
r.addConnection(&rpt, conn)
|
||||
}
|
||||
|
||||
if rep.includeNAT {
|
||||
err = applyNAT(r, rep.hostID)
|
||||
if r.includeNAT {
|
||||
err = applyNAT(rpt, r.hostID)
|
||||
}
|
||||
|
||||
return r, err
|
||||
return rpt, err
|
||||
}
|
||||
|
||||
func (rep *reporter) addConnection(r *report.Report, c *procspy.Connection) {
|
||||
func (r *Reporter) addConnection(rpt *report.Report, c *procspy.Connection) {
|
||||
var (
|
||||
scopedLocal = report.MakeAddressNodeID(rep.hostID, c.LocalAddress.String())
|
||||
scopedRemote = report.MakeAddressNodeID(rep.hostID, c.RemoteAddress.String())
|
||||
scopedLocal = report.MakeAddressNodeID(r.hostID, c.LocalAddress.String())
|
||||
scopedRemote = report.MakeAddressNodeID(r.hostID, c.RemoteAddress.String())
|
||||
key = report.MakeAdjacencyID(scopedLocal)
|
||||
edgeKey = report.MakeEdgeID(scopedLocal, scopedRemote)
|
||||
)
|
||||
|
||||
r.Address.Adjacency[key] = r.Address.Adjacency[key].Add(scopedRemote)
|
||||
rpt.Address.Adjacency[key] = rpt.Address.Adjacency[key].Add(scopedRemote)
|
||||
|
||||
if _, ok := r.Address.NodeMetadatas[scopedLocal]; !ok {
|
||||
r.Address.NodeMetadatas[scopedLocal] = report.NodeMetadata{
|
||||
"name": rep.hostName,
|
||||
if _, ok := rpt.Address.NodeMetadatas[scopedLocal]; !ok {
|
||||
rpt.Address.NodeMetadatas[scopedLocal] = report.NodeMetadata{
|
||||
"name": r.hostName,
|
||||
"addr": c.LocalAddress.String(),
|
||||
}
|
||||
}
|
||||
|
||||
// Count the TCP connection.
|
||||
edgeMeta := r.Address.EdgeMetadatas[edgeKey]
|
||||
edgeMeta := rpt.Address.EdgeMetadatas[edgeKey]
|
||||
edgeMeta.WithConnCountTCP = true
|
||||
edgeMeta.MaxConnCountTCP++
|
||||
r.Address.EdgeMetadatas[edgeKey] = edgeMeta
|
||||
rpt.Address.EdgeMetadatas[edgeKey] = edgeMeta
|
||||
|
||||
if c.Proc.PID > 0 {
|
||||
var (
|
||||
scopedLocal = report.MakeEndpointNodeID(rep.hostID, c.LocalAddress.String(), strconv.Itoa(int(c.LocalPort)))
|
||||
scopedRemote = report.MakeEndpointNodeID(rep.hostID, c.RemoteAddress.String(), strconv.Itoa(int(c.RemotePort)))
|
||||
scopedLocal = report.MakeEndpointNodeID(r.hostID, c.LocalAddress.String(), strconv.Itoa(int(c.LocalPort)))
|
||||
scopedRemote = report.MakeEndpointNodeID(r.hostID, c.RemoteAddress.String(), strconv.Itoa(int(c.RemotePort)))
|
||||
key = report.MakeAdjacencyID(scopedLocal)
|
||||
edgeKey = report.MakeEdgeID(scopedLocal, scopedRemote)
|
||||
)
|
||||
|
||||
r.Endpoint.Adjacency[key] = r.Endpoint.Adjacency[key].Add(scopedRemote)
|
||||
rpt.Endpoint.Adjacency[key] = rpt.Endpoint.Adjacency[key].Add(scopedRemote)
|
||||
|
||||
if _, ok := r.Endpoint.NodeMetadatas[scopedLocal]; !ok {
|
||||
if _, ok := rpt.Endpoint.NodeMetadatas[scopedLocal]; !ok {
|
||||
// First hit establishes NodeMetadata for scoped local address + port
|
||||
md := report.NodeMetadata{
|
||||
"addr": c.LocalAddress.String(),
|
||||
@@ -107,12 +109,12 @@ func (rep *reporter) addConnection(r *report.Report, c *procspy.Connection) {
|
||||
"pid": fmt.Sprintf("%d", c.Proc.PID),
|
||||
}
|
||||
|
||||
r.Endpoint.NodeMetadatas[scopedLocal] = md
|
||||
rpt.Endpoint.NodeMetadatas[scopedLocal] = md
|
||||
}
|
||||
// Count the TCP connection.
|
||||
edgeMeta := r.Endpoint.EdgeMetadatas[edgeKey]
|
||||
edgeMeta := rpt.Endpoint.EdgeMetadatas[edgeKey]
|
||||
edgeMeta.WithConnCountTCP = true
|
||||
edgeMeta.MaxConnCountTCP++
|
||||
r.Endpoint.EdgeMetadatas[edgeKey] = edgeMeta
|
||||
rpt.Endpoint.EdgeMetadatas[edgeKey] = edgeMeta
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -33,21 +32,23 @@ var (
|
||||
Now = func() string { return time.Now().UTC().Format(time.RFC3339Nano) }
|
||||
)
|
||||
|
||||
type reporter struct {
|
||||
// Reporter generates Reports containing the host topology.
|
||||
type Reporter struct {
|
||||
hostID string
|
||||
hostName string
|
||||
}
|
||||
|
||||
// NewReporter returns a Reporter which produces a report containing host
|
||||
// topology for this host.
|
||||
func NewReporter(hostID, hostName string) tag.Reporter {
|
||||
return &reporter{
|
||||
func NewReporter(hostID, hostName string) *Reporter {
|
||||
return &Reporter{
|
||||
hostID: hostID,
|
||||
hostName: hostName,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reporter) Report() (report.Report, error) {
|
||||
// Report implements Reporter.
|
||||
func (r *Reporter) Report() (report.Report, error) {
|
||||
var (
|
||||
rep = report.MakeReport()
|
||||
localCIDRs []string
|
||||
|
||||
27
probe/host/tagger.go
Normal file
27
probe/host/tagger.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// Tagger tags each node in each topology of a report with the origin host
|
||||
// node ID of this (probe) host. Effectively, a foreign key linking every node
|
||||
// in every topology to an origin host node in the host topology.
|
||||
type Tagger struct{ hostNodeID string }
|
||||
|
||||
// NewTagger tags each node with a foreign key linking it to its origin host
|
||||
// in the host topology.
|
||||
func NewTagger(hostID string) Tagger {
|
||||
return Tagger{hostNodeID: report.MakeHostNodeID(hostID)}
|
||||
}
|
||||
|
||||
// Tag implements Tagger.
|
||||
func (t Tagger) Tag(r report.Report) (report.Report, error) {
|
||||
md := report.NodeMetadata{report.HostNodeID: t.hostNodeID}
|
||||
for _, topology := range r.Topologies() {
|
||||
for nodeID := range topology.NodeMetadatas {
|
||||
topology.NodeMetadatas[nodeID].Merge(md)
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
package tag_test
|
||||
package host_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/test"
|
||||
)
|
||||
|
||||
func TestOriginHostTagger(t *testing.T) {
|
||||
func TestTagger(t *testing.T) {
|
||||
var (
|
||||
hostID = "foo"
|
||||
endpointNodeID = report.MakeEndpointNodeID(hostID, "1.2.3.4", "56789") // hostID ignored
|
||||
@@ -18,9 +19,9 @@ func TestOriginHostTagger(t *testing.T) {
|
||||
r := report.MakeReport()
|
||||
r.Endpoint.NodeMetadatas[endpointNodeID] = nodeMetadata
|
||||
want := nodeMetadata.Merge(report.NodeMetadata{report.HostNodeID: report.MakeHostNodeID(hostID)})
|
||||
rpt, _ := tag.NewOriginHostTagger(hostID).Tag(r)
|
||||
rpt, _ := host.NewTagger(hostID).Tag(r)
|
||||
have := rpt.Endpoint.NodeMetadatas[endpointNodeID].Copy()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("\nwant %+v\nhave %+v", want, have)
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/probe/endpoint"
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/probe/overlay"
|
||||
"github.com/weaveworks/scope/probe/process"
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/xfer"
|
||||
)
|
||||
@@ -75,25 +75,13 @@ func main() {
|
||||
defer publisher.Close()
|
||||
|
||||
var (
|
||||
hostName = hostname()
|
||||
hostID = hostName // TODO: we should sanitize the hostname
|
||||
)
|
||||
|
||||
var (
|
||||
weaveTagger *tag.WeaveTagger
|
||||
hostName = hostname()
|
||||
hostID = hostName // TODO: we should sanitize the hostname
|
||||
taggers = []Tagger{newTopologyTagger(), host.NewTagger(hostID)}
|
||||
reporters = []Reporter{host.NewReporter(hostID, hostName), endpoint.NewReporter(hostID, hostName, *spyProcs)}
|
||||
processCache *process.CachingWalker
|
||||
)
|
||||
|
||||
taggers := []tag.Tagger{
|
||||
tag.NewTopologyTagger(),
|
||||
tag.NewOriginHostTagger(hostID),
|
||||
}
|
||||
|
||||
reporters := []tag.Reporter{
|
||||
host.NewReporter(hostID, hostName),
|
||||
endpoint.NewReporter(hostID, hostName, *spyProcs),
|
||||
}
|
||||
|
||||
// TODO provide an alternate implementation for Darwin.
|
||||
if runtime.GOOS == linux {
|
||||
processCache = process.NewCachingWalker(process.NewWalker(*procRoot))
|
||||
@@ -116,12 +104,12 @@ func main() {
|
||||
}
|
||||
|
||||
if *weaveRouterAddr != "" {
|
||||
var err error
|
||||
weaveTagger, err = tag.NewWeaveTagger(*weaveRouterAddr)
|
||||
weave, err := overlay.NewWeave(*weaveRouterAddr)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to start Weave tagger: %v", err)
|
||||
}
|
||||
taggers = append(taggers, weaveTagger)
|
||||
taggers = append(taggers, weave)
|
||||
reporters = append(reporters, weave)
|
||||
}
|
||||
|
||||
log.Printf("listening on %s", *listen)
|
||||
@@ -157,11 +145,7 @@ func main() {
|
||||
r.Merge(newReport)
|
||||
}
|
||||
|
||||
if weaveTagger != nil {
|
||||
r.Overlay.Merge(weaveTagger.OverlayTopology())
|
||||
}
|
||||
|
||||
r = tag.Apply(r, taggers)
|
||||
r = Apply(r, taggers)
|
||||
|
||||
case <-quit:
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package tag
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -21,39 +21,40 @@ const (
|
||||
WeavePeerNickName = "weave_peer_nick_name"
|
||||
)
|
||||
|
||||
// WeaveTagger represents a single Weave router, presumably on the same host
|
||||
// as the probe. It can produce an Overlay topology, and in theory can tag
|
||||
// existing topologies with foreign keys to overlay -- though I'm not sure
|
||||
// what that would look like in practice right now.
|
||||
type WeaveTagger struct {
|
||||
// Weave represents a single Weave router, presumably on the same host
|
||||
// as the probe. It is both a Reporter and a Tagger: it produces an Overlay
|
||||
// topology, and (in theory) can tag existing topologies with foreign keys to
|
||||
// overlay -- though I'm not sure what that would look like in practice right
|
||||
// now.
|
||||
type Weave struct {
|
||||
url string
|
||||
}
|
||||
|
||||
// NewWeaveTagger returns a new Weave tagger based on the Weave router at
|
||||
// NewWeave returns a new Weave tagger based on the Weave router at
|
||||
// address. The address should be an IP or FQDN, no port.
|
||||
func NewWeaveTagger(weaveRouterAddress string) (*WeaveTagger, error) {
|
||||
func NewWeave(weaveRouterAddress string) (*Weave, error) {
|
||||
s, err := sanitize("http://", 6784, "/status-json")(weaveRouterAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &WeaveTagger{s}, nil
|
||||
return &Weave{s}, nil
|
||||
}
|
||||
|
||||
// Tag implements Tagger.
|
||||
func (t WeaveTagger) Tag(r report.Report) (report.Report, error) {
|
||||
func (w Weave) Tag(r report.Report) (report.Report, error) {
|
||||
// The status-json endpoint doesn't return any link information, so
|
||||
// there's nothing to tag, yet.
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// OverlayTopology produces an overlay topology from the Weave router.
|
||||
func (t WeaveTagger) OverlayTopology() report.Topology {
|
||||
topology := report.NewTopology()
|
||||
// Report implements Reporter.
|
||||
func (w Weave) Report() (report.Report, error) {
|
||||
r := report.MakeReport()
|
||||
|
||||
resp, err := http.Get(t.url)
|
||||
resp, err := http.Get(w.url)
|
||||
if err != nil {
|
||||
log.Printf("Weave Tagger: %v", err)
|
||||
return topology
|
||||
return r, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -65,17 +66,16 @@ func (t WeaveTagger) OverlayTopology() report.Topology {
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
|
||||
log.Printf("Weave Tagger: %v", err)
|
||||
return topology
|
||||
return r, err
|
||||
}
|
||||
|
||||
for _, peer := range status.Peers {
|
||||
topology.NodeMetadatas[report.MakeOverlayNodeID(peer.Name)] = report.NodeMetadata{
|
||||
r.Overlay.NodeMetadatas[report.MakeOverlayNodeID(peer.Name)] = report.NodeMetadata{
|
||||
WeavePeerName: peer.Name,
|
||||
WeavePeerNickName: peer.NickName,
|
||||
}
|
||||
}
|
||||
|
||||
return topology
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func sanitize(scheme string, port int, path string) func(string) (string, error) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package tag_test
|
||||
package overlay_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -7,30 +7,35 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/probe/overlay"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/test"
|
||||
)
|
||||
|
||||
func TestWeaveTaggerOverlayTopology(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(mockWeaveRouter))
|
||||
defer s.Close()
|
||||
|
||||
w, err := tag.NewWeaveTagger(s.URL)
|
||||
w, err := overlay.NewWeave(s.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
have, err := w.Report()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := (report.Topology{
|
||||
Adjacency: report.Adjacency{},
|
||||
EdgeMetadatas: report.EdgeMetadatas{},
|
||||
NodeMetadatas: report.NodeMetadatas{
|
||||
report.MakeOverlayNodeID(mockWeavePeerName): {
|
||||
tag.WeavePeerName: mockWeavePeerName,
|
||||
tag.WeavePeerNickName: mockWeavePeerNickName,
|
||||
overlay.WeavePeerName: mockWeavePeerName,
|
||||
overlay.WeavePeerNickName: mockWeavePeerNickName,
|
||||
},
|
||||
},
|
||||
}), w.OverlayTopology(); !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("want\n\t%#v, have\n\t%#v", want, have)
|
||||
}), have.Overlay; !reflect.DeepEqual(want, have) {
|
||||
t.Error(test.Diff(want, have))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +51,6 @@ func mockWeaveRouter(w http.ResponseWriter, r *http.Request) {
|
||||
"NickName": mockWeavePeerNickName,
|
||||
}},
|
||||
}); err != nil {
|
||||
println(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package process
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -16,22 +15,22 @@ const (
|
||||
Threads = "threads"
|
||||
)
|
||||
|
||||
// Reporter generate Reports containing the Process topology
|
||||
type reporter struct {
|
||||
// Reporter generates Reports containing the Process topology.
|
||||
type Reporter struct {
|
||||
scope string
|
||||
walker Walker
|
||||
}
|
||||
|
||||
// NewReporter makes a new Reporter
|
||||
func NewReporter(walker Walker, scope string) tag.Reporter {
|
||||
return &reporter{
|
||||
// NewReporter makes a new Reporter.
|
||||
func NewReporter(walker Walker, scope string) *Reporter {
|
||||
return &Reporter{
|
||||
scope: scope,
|
||||
walker: walker,
|
||||
}
|
||||
}
|
||||
|
||||
// Report generates a Report containing the Process topology
|
||||
func (r *reporter) Report() (report.Report, error) {
|
||||
// Report implements Reporter.
|
||||
func (r *Reporter) Report() (report.Report, error) {
|
||||
result := report.MakeReport()
|
||||
processes, err := r.processTopology()
|
||||
if err != nil {
|
||||
@@ -41,7 +40,7 @@ func (r *reporter) Report() (report.Report, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *reporter) processTopology() (report.Topology, error) {
|
||||
func (r *Reporter) processTopology() (report.Topology, error) {
|
||||
t := report.NewTopology()
|
||||
err := r.walker.Walk(func(p *Process) {
|
||||
pidstr := strconv.Itoa(p.PID)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package tag
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
type originHostTagger struct{ hostNodeID string }
|
||||
|
||||
// NewOriginHostTagger tags each node with a foreign key linking it to its
|
||||
// origin host in the host topology.
|
||||
func NewOriginHostTagger(hostID string) Tagger {
|
||||
return &originHostTagger{hostNodeID: report.MakeHostNodeID(hostID)}
|
||||
}
|
||||
|
||||
func (t originHostTagger) Tag(r report.Report) (report.Report, error) {
|
||||
for _, topology := range r.Topologies() {
|
||||
md := report.NodeMetadata{report.HostNodeID: t.hostNodeID}
|
||||
for nodeID := range topology.NodeMetadatas {
|
||||
topology.NodeMetadatas[nodeID].Merge(md)
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package tag
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// Tagger tags nodes with value-add node metadata.
|
||||
type Tagger interface {
|
||||
Tag(r report.Report) (report.Report, error)
|
||||
}
|
||||
|
||||
// Reporter generates Reports.
|
||||
type Reporter interface {
|
||||
Report() (report.Report, error)
|
||||
}
|
||||
|
||||
// Apply tags the report with all the taggers.
|
||||
func Apply(r report.Report, taggers []Tagger) report.Report {
|
||||
var err error
|
||||
for _, tagger := range taggers {
|
||||
r, err = tagger.Tag(r)
|
||||
if err != nil {
|
||||
log.Printf("error applying tagger: %v", err)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package tag
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
type topologyTagger struct{}
|
||||
|
||||
// NewTopologyTagger tags each node with the topology that it comes from.
|
||||
func NewTopologyTagger() Tagger {
|
||||
return &topologyTagger{}
|
||||
}
|
||||
|
||||
func (topologyTagger) Tag(r report.Report) (report.Report, error) {
|
||||
for val, topology := range map[string]*report.Topology{
|
||||
"endpoint": &(r.Endpoint),
|
||||
"address": &(r.Address),
|
||||
"process": &(r.Process),
|
||||
"container": &(r.Container),
|
||||
"host": &(r.Host),
|
||||
} {
|
||||
md := report.NodeMetadata{"topology": val}
|
||||
for nodeID := range topology.NodeMetadatas {
|
||||
(*topology).NodeMetadatas[nodeID].Merge(md)
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package tag_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
func TestTagMissingID(t *testing.T) {
|
||||
const nodeID = "not-found"
|
||||
r := report.MakeReport()
|
||||
want := report.NodeMetadata{}
|
||||
rpt, _ := tag.NewTopologyTagger().Tag(r)
|
||||
have := rpt.Endpoint.NodeMetadatas[nodeID].Copy()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error("TopologyTagger erroneously tagged a missing node ID")
|
||||
}
|
||||
}
|
||||
59
probe/tag_report.go
Normal file
59
probe/tag_report.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
// Tagger tags nodes with value-add node metadata.
|
||||
type Tagger interface {
|
||||
Tag(r report.Report) (report.Report, error)
|
||||
}
|
||||
|
||||
// Reporter generates Reports.
|
||||
type Reporter interface {
|
||||
Report() (report.Report, error)
|
||||
}
|
||||
|
||||
// Apply tags the report with all the taggers.
|
||||
func Apply(r report.Report, taggers []Tagger) report.Report {
|
||||
var err error
|
||||
for _, tagger := range taggers {
|
||||
r, err = tagger.Tag(r)
|
||||
if err != nil {
|
||||
log.Printf("error applying tagger: %v", err)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Topology is the NodeMetadata key for the origin topology.
|
||||
const Topology = "topology"
|
||||
|
||||
type topologyTagger struct{}
|
||||
|
||||
// NewTopologyTagger tags each node with the topology that it comes from. It's
|
||||
// kind of a proof-of-concept tagger, useful primarily for debugging.
|
||||
func newTopologyTagger() Tagger {
|
||||
return &topologyTagger{}
|
||||
}
|
||||
|
||||
// Tag implements Tagger
|
||||
func (topologyTagger) Tag(r report.Report) (report.Report, error) {
|
||||
for val, topology := range map[string]*report.Topology{
|
||||
"endpoint": &(r.Endpoint),
|
||||
"address": &(r.Address),
|
||||
"process": &(r.Process),
|
||||
"container": &(r.Container),
|
||||
"container_image": &(r.ContainerImage),
|
||||
"host": &(r.Host),
|
||||
"overlay": &(r.Overlay),
|
||||
} {
|
||||
md := report.NodeMetadata{Topology: val}
|
||||
for nodeID := range topology.NodeMetadatas {
|
||||
(*topology).NodeMetadatas[nodeID].Merge(md)
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package tag_test
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/probe/tag"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -19,15 +18,15 @@ func TestApply(t *testing.T) {
|
||||
r := report.MakeReport()
|
||||
r.Endpoint.NodeMetadatas[endpointNodeID] = endpointNodeMetadata
|
||||
r.Address.NodeMetadatas[addressNodeID] = addressNodeMetadata
|
||||
r = tag.Apply(r, []tag.Tagger{tag.NewTopologyTagger()})
|
||||
r = Apply(r, []Tagger{newTopologyTagger()})
|
||||
|
||||
for _, tuple := range []struct {
|
||||
want report.NodeMetadata
|
||||
from report.Topology
|
||||
via string
|
||||
}{
|
||||
{copy(endpointNodeMetadata).Merge(report.NodeMetadata{"topology": "endpoint"}), r.Endpoint, endpointNodeID},
|
||||
{copy(addressNodeMetadata).Merge(report.NodeMetadata{"topology": "address"}), r.Address, addressNodeID},
|
||||
{endpointNodeMetadata.Copy().Merge(report.NodeMetadata{"topology": "endpoint"}), r.Endpoint, endpointNodeID},
|
||||
{addressNodeMetadata.Copy().Merge(report.NodeMetadata{"topology": "address"}), r.Address, addressNodeID},
|
||||
} {
|
||||
if want, have := tuple.want, tuple.from.NodeMetadatas[tuple.via]; !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("want %+v, have %+v", want, have)
|
||||
@@ -35,10 +34,13 @@ func TestApply(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func copy(input report.NodeMetadata) report.NodeMetadata {
|
||||
output := make(report.NodeMetadata, len(input))
|
||||
for k, v := range input {
|
||||
output[k] = v
|
||||
func TestTagMissingID(t *testing.T) {
|
||||
const nodeID = "not-found"
|
||||
r := report.MakeReport()
|
||||
want := report.NodeMetadata{}
|
||||
rpt, _ := newTopologyTagger().Tag(r)
|
||||
have := rpt.Endpoint.NodeMetadatas[nodeID].Copy()
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Error("TopologyTagger erroneously tagged a missing node ID")
|
||||
}
|
||||
return output
|
||||
}
|
||||
Reference in New Issue
Block a user