From bcddfd82c39284523d4bb4e9963263879931dadb Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Mon, 11 Jul 2016 10:57:58 +0100 Subject: [PATCH] Added file collector, to serve a static report from file --- app/api_report_test.go | 3 +- app/benchmark_internal_test.go | 18 +++-------- app/collector.go | 58 ++++++++++++++++++++++++++++++++++ app/mock_reporter_test.go | 16 ---------- prog/app.go | 5 ++- prog/main.go | 2 +- 6 files changed, 69 insertions(+), 33 deletions(-) delete mode 100644 app/mock_reporter_test.go diff --git a/app/api_report_test.go b/app/api_report_test.go index 6d6933db9..97d2fcc56 100644 --- a/app/api_report_test.go +++ b/app/api_report_test.go @@ -9,11 +9,12 @@ import ( "github.com/weaveworks/scope/app" "github.com/weaveworks/scope/report" + "github.com/weaveworks/scope/test/fixture" ) func topologyServer() *httptest.Server { router := mux.NewRouter().SkipClean(true) - app.RegisterTopologyRoutes(router, StaticReport{}) + app.RegisterTopologyRoutes(router, app.StaticCollector(fixture.Report)) return httptest.NewServer(router) } diff --git a/app/benchmark_internal_test.go b/app/benchmark_internal_test.go index 8acb0feb2..fe6a47970 100644 --- a/app/benchmark_internal_test.go +++ b/app/benchmark_internal_test.go @@ -2,25 +2,17 @@ package app import ( "flag" - "io/ioutil" "net/http" "net/url" "testing" - "github.com/ugorji/go/codec" + "golang.org/x/net/context" "github.com/weaveworks/scope/render" "github.com/weaveworks/scope/report" "github.com/weaveworks/scope/test/fixture" ) -// StaticReport is used as a fixture in tests. It emulates an xfer.Collector. -type StaticReporter struct{ r report.Report } - -func (s StaticReporter) Report() report.Report { return s.r } -func (s StaticReporter) WaitOn(chan struct{}) {} -func (s StaticReporter) UnWait(chan struct{}) {} - var ( benchReportFile = flag.String("bench-report-file", "", "json report file to use for benchmarking (relative to this package)") ) @@ -30,14 +22,12 @@ func loadReport() (report.Report, error) { return fixture.Report, nil } - b, err := ioutil.ReadFile(*benchReportFile) + c, err := NewFileCollector(*benchReportFile) if err != nil { return fixture.Report, err } - rpt := report.MakeReport() - decoder := codec.NewDecoderBytes(b, &codec.JsonHandle{}) - err = decoder.Decode(&rpt) - return rpt, err + + return c.Report(context.Background()) } func BenchmarkTopologyList(b *testing.B) { diff --git a/app/collector.go b/app/collector.go index a33e11cff..2e46a4171 100644 --- a/app/collector.go +++ b/app/collector.go @@ -1,9 +1,14 @@ package app import ( + "fmt" + "os" + "path/filepath" + "strings" "sync" "time" + "github.com/ugorji/go/codec" "golang.org/x/net/context" "github.com/weaveworks/scope/common/mtime" @@ -131,3 +136,56 @@ func (c *collector) clean() { c.reports = cleanedReports c.timestamps = cleanedTimestamps } + +// StaticCollector always returns the given report. +type StaticCollector report.Report + +// Report returns a merged report over all added reports. It implements +// Reporter. +func (c StaticCollector) Report(context.Context) (report.Report, error) { return report.Report(c), nil } + +// Add adds a report to the collector's internal state. It implements Adder. +func (c StaticCollector) Add(context.Context, report.Report) error { return nil } + +// WaitOn lets other conponents wait on a new report being received. It +// implements Reporter. +func (c StaticCollector) WaitOn(context.Context, chan struct{}) {} + +// UnWait lets other conponents stop waiting on a new report being received. It +// implements Reporter. +func (c StaticCollector) UnWait(context.Context, chan struct{}) {} + +// NewFileCollector reads and json parses the given path, returning a collector +// which always returns that report. +func NewFileCollector(path string) (Collector, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + var ( + rpt report.Report + handle codec.Handle + gzipped bool + ) + fileType := filepath.Ext(path) + if fileType == ".gz" { + gzipped = true + fileType = filepath.Ext(strings.TrimSuffix(path, fileType)) + } + switch fileType { + case ".json": + handle = &codec.JsonHandle{} + case ".msgpack": + handle = &codec.MsgpackHandle{} + default: + return nil, fmt.Errorf("Unsupported file extension: %v", fileType) + } + + if err := rpt.ReadBinary(f, gzipped, handle); err != nil { + return nil, err + } + + return StaticCollector(rpt), nil +} diff --git a/app/mock_reporter_test.go b/app/mock_reporter_test.go deleted file mode 100644 index 9903357e5..000000000 --- a/app/mock_reporter_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package app_test - -import ( - "github.com/weaveworks/scope/report" - "github.com/weaveworks/scope/test/fixture" - - "golang.org/x/net/context" -) - -// StaticReport is used as a fixture in tests. It emulates an xfer.Collector. -type StaticReport struct{} - -func (s StaticReport) Report(context.Context) (report.Report, error) { return fixture.Report, nil } -func (s StaticReport) Add(context.Context, report.Report) error { return nil } -func (s StaticReport) WaitOn(context.Context, chan struct{}) {} -func (s StaticReport) UnWait(context.Context, chan struct{}) {} diff --git a/prog/app.go b/prog/app.go index f786a3883..124e0c095 100644 --- a/prog/app.go +++ b/prog/app.go @@ -90,7 +90,10 @@ func collectorFactory(userIDer multitenant.UserIDer, collectorURL, s3URL, natsHo return nil, err } - if parsed.Scheme == "dynamodb" { + switch parsed.Scheme { + case "file": + return app.NewFileCollector(parsed.Path) + case "dynamodb": s3, err := url.Parse(s3URL) if err != nil { return nil, fmt.Errorf("Valid URL for s3 required: %v", err) diff --git a/prog/main.go b/prog/main.go index 71ba4b976..7e9aed1f6 100644 --- a/prog/main.go +++ b/prog/main.go @@ -186,7 +186,7 @@ func main() { flag.StringVar(&flags.app.containerName, "app.container.name", app.DefaultContainerName, "Name of this container (to lookup container ID)") flag.StringVar(&flags.app.dockerEndpoint, "app.docker", app.DefaultDockerEndpoint, "Location of docker endpoint (to lookup container ID)") - flag.StringVar(&flags.app.collectorURL, "app.collector", "local", "Collector to use (local of dynamodb)") + flag.StringVar(&flags.app.collectorURL, "app.collector", "local", "Collector to use (local, dynamodb, or file)") flag.StringVar(&flags.app.s3URL, "app.collector.s3", "local", "S3 URL to use (when collector is dynamodb)") flag.StringVar(&flags.app.controlRouterURL, "app.control.router", "local", "Control router to use (local or sqs)") flag.StringVar(&flags.app.pipeRouterURL, "app.pipe.router", "local", "Pipe router to use (local)")