From e8b79478b1807b8f8828c51e989d83c5ae7d6d89 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Mon, 13 Jul 2020 23:33:32 -0400 Subject: Initial commit --- main.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 main.go (limited to 'main.go') diff --git a/main.go b/main.go new file mode 100644 index 0000000..434b936 --- /dev/null +++ b/main.go @@ -0,0 +1,95 @@ +package main + +import ( + "context" + "fmt" + "io" + "log" + "net/http" + "strings" + + "github.com/kelseyhightower/envconfig" + "golang.org/x/sync/errgroup" + + "bnbl.io/csp_exporter/collector" + "bnbl.io/csp_exporter/csp" +) + +type config struct { + CollectorBindAddr string `envconfig:"COLLECTOR_BIND_ADDR" required:"true"` + PromBindAddr string `envconfig:"PROM_BIND_ADDR" default:":9477"` +} + +func main() { + var cfg config + if err := envconfig.Process("", &cfg); err != nil { + log.Fatalf("could not read configuration from environment: %v", err) + } + + coll, err := collector.NewCollector() + if err != nil { + log.Fatalf("could not create collector: %v", err) + } + + cspHandler := http.NewServeMux() + cspHandler.HandleFunc("/report/csp/", func(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + w.WriteHeader(http.StatusBadRequest) + return + } + if r.Header.Get("content-type") != "application/csp-report" { + w.WriteHeader(http.StatusBadRequest) + return + } + + app := strings.TrimPrefix(r.URL.EscapedPath(), "/report/csp/") + if app == "" { + w.WriteHeader(http.StatusNotFound) + return + } + + report, err := csp.ReadReport(r.Body) + if err == io.EOF { + w.WriteHeader(http.StatusBadRequest) + return + } else if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + coll.Collect(app, report) + }) + + g, ctx := errgroup.WithContext(context.Background()) + + // start metrics server + g.Go(func() error { + h := http.NewServeMux() + h.Handle("/metrics", coll.Handler()) + srv := &http.Server{Addr: cfg.PromBindAddr, Handler: h} + go func() { + <-ctx.Done() + if err := srv.Shutdown(ctx); err != nil { + log.Printf("shutdown metrics server: %v", err) + } + }() + return fmt.Errorf("metrics server: %v", srv.ListenAndServe()) + }) + + // start CSP collector server + g.Go(func() error { + srv := &http.Server{Addr: cfg.CollectorBindAddr, Handler: cspHandler} + go func() { + <-ctx.Done() + if err := srv.Shutdown(ctx); err != nil { + log.Printf("shutdown collector server: %v", err) + } + }() + return fmt.Errorf("collector server: %v", srv.ListenAndServe()) + }) + + if err := g.Wait(); err != nil { + log.Fatal(err) + } +} -- cgit v1.2.3