Add /api/probes endpoint

This commit is contained in:
Tom Wilkie
2016-04-12 15:09:56 +01:00
parent b68a2b6112
commit 281ba58845
7 changed files with 90 additions and 4 deletions

View File

@@ -4,6 +4,8 @@ import (
"net/http"
"golang.org/x/net/context"
"github.com/weaveworks/scope/report"
)
// Raw report handler
@@ -17,3 +19,19 @@ func makeRawReportHandler(rep Reporter) CtxHandlerFunc {
respondWith(w, http.StatusOK, report)
}
}
// Probe handler
func makeProbeHandler(rep Reporter) CtxHandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
rpt, err := rep.Report(ctx)
if err != nil {
respondWith(w, http.StatusInternalServerError, err.Error())
return
}
result := []report.Probe{}
for _, p := range rpt.Probes {
result = append(result, p)
}
respondWith(w, http.StatusOK, result)
}
}

View File

@@ -95,6 +95,8 @@ func RegisterTopologyRoutes(router *mux.Router, r Reporter) {
gzipHandler(requestContextDecorator(topologyRegistry.captureRendererWithoutFilters(r, handleNode))))
get.HandleFunc("/api/report",
gzipHandler(requestContextDecorator(makeRawReportHandler(r))))
get.HandleFunc("/api/probes",
gzipHandler(requestContextDecorator(makeProbeHandler(r))))
}
// RegisterReportPostHandler registers the handler for report submission

View File

@@ -7,6 +7,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/armon/go-metrics"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/probe/appclient"
"github.com/weaveworks/scope/report"
)
@@ -17,6 +18,7 @@ const (
// Probe sits there, generating and publishing reports.
type Probe struct {
id string
spyInterval, publishInterval time.Duration
publisher *appclient.ReportPublisher
@@ -52,8 +54,9 @@ type Ticker interface {
}
// New makes a new Probe.
func New(spyInterval, publishInterval time.Duration, publisher appclient.Publisher) *Probe {
func New(id string, spyInterval, publishInterval time.Duration, publisher appclient.Publisher) *Probe {
result := &Probe{
id: id,
spyInterval: spyInterval,
publishInterval: publishInterval,
publisher: appclient.NewReportPublisher(publisher),
@@ -150,6 +153,10 @@ func (p *Probe) report() report.Report {
for i := 0; i < cap(reports); i++ {
result = result.Merge(<-reports)
}
result.Probes[p.id] = report.Probe{
ID: p.id,
LastSeen: mtime.Now(),
}
return result
}

View File

@@ -7,6 +7,7 @@ import (
"time"
"github.com/ugorji/go/codec"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
"github.com/weaveworks/scope/test/reflect"
@@ -18,7 +19,7 @@ func TestApply(t *testing.T) {
endpointNode = report.MakeNodeWith(map[string]string{"5": "6"})
)
p := New(0, 0, nil)
p := New("", 0, 0, nil)
p.AddTagger(NewTopologyTagger())
r := report.MakeReport()
@@ -71,11 +72,20 @@ func TestProbe(t *testing.T) {
// marshalling->unmarshaling is not idempotent due to `json:"omitempty"`
// tags, transforming empty slices into nils. So, we make DeepEqual
// happy by setting empty `json:"omitempty"` entries to nil
const probeID = "probeid"
now := time.Now()
mtime.NowForce(now)
defer mtime.NowReset()
want := report.MakeReport()
node := report.MakeNodeWith(map[string]string{"b": "c"})
node.Metrics = nil // omitempty
want.Endpoint.AddNode("a", node)
want.Probes[probeID] = report.Probe{
ID: probeID,
LastSeen: now,
}
pub := mockPublisher{make(chan report.Report)}
// omitempty
@@ -88,7 +98,7 @@ func TestProbe(t *testing.T) {
want.Host.Controls = nil
want.Overlay.Controls = nil
p := New(10*time.Millisecond, 100*time.Millisecond, pub)
p := New(probeID, 10*time.Millisecond, 100*time.Millisecond, pub)
p.AddReporter(mockReporter{want})
p.Start()
defer p.Stop()

View File

@@ -138,7 +138,7 @@ func probeMain() {
endpointReporter := endpoint.NewReporter(hostID, hostName, *spyProcs, *useConntrack, scanner)
defer endpointReporter.Stop()
p := probe.New(*spyInterval, *publishInterval, clients)
p := probe.New(probeID, *spyInterval, *publishInterval, clients)
p.AddTicker(processCache)
hostReporter := host.NewReporter(hostID, hostName, probeID, clients)
defer hostReporter.Stop()

43
report/probes.go Normal file
View File

@@ -0,0 +1,43 @@
package report
import (
"time"
)
// Probes contains details of the probe(s) which generated a report.
type Probes map[string]Probe
// Copy produces a copy of the Probes
func (ps Probes) Copy() Probes {
result := Probes{}
for id, probe := range ps {
result[id] = probe.Copy()
}
return result
}
// Merge two sets of Probes, keeping the records with the latest LastSeen
func (ps Probes) Merge(other Probes) Probes {
result := ps.Copy()
for id, probe := range other {
o, ok := result[id]
if !ok || o.LastSeen.Before(probe.LastSeen) {
result[id] = probe
}
}
return result
}
// Probe is the details for a single probe that generated a report.
type Probe struct {
ID string `json:"id"`
LastSeen time.Time `json:"lastSeen"`
}
// Copy produces a copy of the Probe
func (p Probe) Copy() Probe {
return Probe{
ID: p.ID,
LastSeen: p.LastSeen,
}
}

View File

@@ -81,6 +81,9 @@ type Report struct {
// must be equal, but we don't require that equal reports have
// the same id.
ID string `deepequal:"skip"`
// Probes is the details of the probes who reported this report
Probes Probes
}
// MakeReport makes a clean report, ready to Merge() other reports into.
@@ -97,6 +100,7 @@ func MakeReport() Report {
Sampling: Sampling{},
Window: 0,
ID: fmt.Sprintf("%d", rand.Int63()),
Probes: Probes{},
}
}
@@ -114,6 +118,7 @@ func (r Report) Copy() Report {
Sampling: r.Sampling,
Window: r.Window,
ID: fmt.Sprintf("%d", rand.Int63()),
Probes: r.Probes.Copy(),
}
}
@@ -130,6 +135,7 @@ func (r Report) Merge(other Report) Report {
cp.Service = r.Service.Merge(other.Service)
cp.Overlay = r.Overlay.Merge(other.Overlay)
cp.Sampling = r.Sampling.Merge(other.Sampling)
cp.Probes = r.Probes.Merge(other.Probes)
cp.Window += other.Window
return cp
}