Skip to content

Commit

Permalink
Add /api/probes endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
tomwilkie committed Apr 12, 2016
1 parent b68a2b6 commit 281ba58
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 4 deletions.
18 changes: 18 additions & 0 deletions app/api_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"net/http"

"golang.org/x/net/context"

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

// Raw report handler
Expand All @@ -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)
}
}
2 changes: 2 additions & 0 deletions app/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion probe/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -17,6 +18,7 @@ const (

// Probe sits there, generating and publishing reports.
type Probe struct {
id string
spyInterval, publishInterval time.Duration
publisher *appclient.ReportPublisher

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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
}

Expand Down
14 changes: 12 additions & 2 deletions probe/probe_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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()
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion prog/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
43 changes: 43 additions & 0 deletions report/probes.go
Original file line number Diff line number Diff line change
@@ -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,
}
}
6 changes: 6 additions & 0 deletions report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -97,6 +100,7 @@ func MakeReport() Report {
Sampling: Sampling{},
Window: 0,
ID: fmt.Sprintf("%d", rand.Int63()),
Probes: Probes{},
}
}

Expand All @@ -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(),
}
}

Expand All @@ -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
}
Expand Down

0 comments on commit 281ba58

Please sign in to comment.