From c725dcc520cc2f0eae4b1015315c6bc2ac8fb06f Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Mon, 30 Mar 2020 14:32:22 -0400 Subject: [PATCH 01/28] initial v1 api routes except AM Signed-off-by: Jacob Lisi --- pkg/api/api.go | 202 ++++++++++++++++++++++++++++++++++++++++++ pkg/ruler/api.go | 26 +++--- pkg/ruler/api_test.go | 4 +- 3 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 pkg/api/api.go diff --git a/pkg/api/api.go b/pkg/api/api.go new file mode 100644 index 00000000000..ccaf20ffe1c --- /dev/null +++ b/pkg/api/api.go @@ -0,0 +1,202 @@ +package api + +import ( + "errors" + "flag" + "net/http" + "regexp" + + "github.com/go-kit/kit/log" + "github.com/gorilla/mux" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/route" + "github.com/prometheus/prometheus/config" + "github.com/prometheus/prometheus/promql" + "github.com/prometheus/prometheus/storage" + v1 "github.com/prometheus/prometheus/web/api/v1" + "github.com/weaveworks/common/middleware" + "github.com/weaveworks/common/server" + "google.golang.org/grpc/health/grpc_health_v1" + + "github.com/cortexproject/cortex/pkg/alertmanager" + "github.com/cortexproject/cortex/pkg/chunk/purger" + "github.com/cortexproject/cortex/pkg/distributor" + "github.com/cortexproject/cortex/pkg/ingester" + "github.com/cortexproject/cortex/pkg/ingester/client" + "github.com/cortexproject/cortex/pkg/querier" + "github.com/cortexproject/cortex/pkg/ruler" + "github.com/cortexproject/cortex/pkg/util/push" +) + +type Config struct { + AlertmanagerHTTPPrefix string `yaml:"alertmanager_http_prefix"` + PrometheusHTTPPrefix string `yaml:"prometheus_http_prefix"` + + HTTPAuthMiddleware middleware.Func `yaml:"-"` +} + +// RegisterFlags adds the flags required to config this to the given FlagSet. +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + cfg.RegisterFlagsWithPrefix("", f) +} + +// RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet with the set prefix. +func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.StringVar(&cfg.AlertmanagerHTTPPrefix, prefix+"http.alertmanager-http-prefix", "/alertmanager", "Base path for data storage.") + f.StringVar(&cfg.PrometheusHTTPPrefix, prefix+"http.prometheus-http-prefix", "/prometheus", "Base path for data storage.") +} + +type API struct { + cfg Config + legacyPrefix string + + authMiddleware middleware.Func + server *server.Server + alertmanagerRouter *mux.Router + prometheusRouter *mux.Router + + reg prometheus.Registerer + logger log.Logger +} + +func New(cfg Config, s *server.Server, legacyPrefix string, logger log.Logger, reg prometheus.Registerer) (*API, error) { + api := &API{ + cfg: cfg, + legacyPrefix: legacyPrefix, + authMiddleware: cfg.HTTPAuthMiddleware, + alertmanagerRouter: s.HTTP.PathPrefix(cfg.AlertmanagerHTTPPrefix).Subrouter(), + prometheusRouter: s.HTTP.PathPrefix(cfg.PrometheusHTTPPrefix).Subrouter(), + server: s, + reg: reg, + logger: logger, + } + + if cfg.HTTPAuthMiddleware == nil { + api.authMiddleware = middleware.AuthenticateUser + } + + return api, nil +} + +func (a *API) registerRoute(path string, handler http.Handler, auth bool, methods ...string) { + if auth { + handler = a.authMiddleware.Wrap(handler) + } + if len(methods) == 0 { + a.server.HTTP.Path(path).Handler(handler) + return + } + a.server.HTTP.Path(path).Methods(methods...).Handler(handler) +} + +func (a *API) registerPrometheusRoute(path string, handler http.Handler, methods ...string) { + if len(methods) == 0 { + a.prometheusRouter.Path(path).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) + return + } + a.prometheusRouter.Path(path).Methods(methods...).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) +} + +func (a *API) registerAlertmanagerRoute(path string, handler http.Handler, methods ...string) { + if len(methods) == 0 { + a.alertmanagerRouter.Path(path).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) + return + } + a.alertmanagerRouter.Path(path).Methods(methods...).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) +} + +// Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. +// Requests to Querier sometimes doesn't have that (if they are fetched from Query-Frontend). +// Prometheus uses this when logging queries to QueryLogger, but Cortex doesn't call engine.SetQueryLogger to set one. +// +// Can be removed when (if) https://github.com/prometheus/prometheus/pull/6840 is merged. +func fakeRemoteAddr(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.RemoteAddr == "" { + r.RemoteAddr = "127.0.0.1:8888" + } + handler.ServeHTTP(w, r) + }) +} + +func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager) { + a.RegisterRoute("/alertmanager/status", am.GetStatusHandler(), false) + +} + +func (a *API) RegisterDistributor(d *distributor.Distributor, pushConfig distributor.Config) { + a.registerRoute("/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false) + a.registerRoute("/push", push.Handler(pushConfig, d.Push), true) + a.registerRoute("/ha-tracker", d.Replicas, false) +} + +func (a *API) RegisterIngester(i *ingester.Ingester, pushConfig distributor.Config) { + client.RegisterIngesterServer(a.server.GRPC, i) + grpc_health_v1.RegisterHealthServer(a.server.GRPC, i) + a.registerRoute("/flush", http.HandlerFunc(i.FlushHandler), false) + a.registerRoute("/shutdown", http.HandlerFunc(i.ShutdownHandler), false) + a.registerRoute("/push", push.Handler(pushConfig, i.Push), true) +} + +func (a *API) RegisterPurger(store *purger.DeleteStore) error { + var deleteRequestHandler *purger.DeleteRequestHandler + deleteRequestHandler, err := purger.NewDeleteRequestHandler(store) + if err != nil { + return err + } + + a.registerPrometheusRoute("/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), "PUT", "POST") + a.registerPrometheusRoute("/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), "GET") + return nil +} + +func (a *API) RegisterRing(component string, handler http.Handler) { + a.server.HTTP.Handle("/"+component+"/ring", handler) +} + +func (a *API) RegisterRuler(r *ruler.Ruler) { + a.registerPrometheusRoute("/api/v1/rules", http.HandlerFunc(r.PrometheusRules), "GET") + a.registerPrometheusRoute("/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), "GET") + a.registerRoute("/api/v1/rules", http.HandlerFunc(r.ListRules), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") + a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") +} + +func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine, distributor *distributor.Distributor) error { + api := v1.NewAPI( + engine, + queryable, + querier.DummyTargetRetriever{}, + querier.DummyAlertmanagerRetriever{}, + func() config.Config { return config.Config{} }, + map[string]string{}, // TODO: include configuration flags + func(f http.HandlerFunc) http.HandlerFunc { return f }, + func() v1.TSDBAdmin { return nil }, // Only needed for admin APIs. + false, // Disable admin APIs. + a.logger, + querier.DummyRulesRetriever{}, + 0, 0, 0, // Remote read samples and concurrency limit. + regexp.MustCompile(".*"), + func() (v1.RuntimeInfo, error) { return v1.RuntimeInfo{}, errors.New("not implemented") }, + &v1.PrometheusVersion{}, + ) + + promRouter := route.New().WithPrefix(a.cfg.PrometheusHTTPPrefix + "/api/v1") + api.Register(promRouter) + + a.registerPrometheusRoute("/api/v1/read", querier.RemoteReadHandler(queryable)) + a.registerPrometheusRoute("/api/v1/query", promRouter) + a.registerPrometheusRoute("/api/v1/query_range", promRouter) + a.registerPrometheusRoute("/api/v1/labels", promRouter) + a.registerPrometheusRoute("/api/v1/label/{name}/values", promRouter) + a.registerPrometheusRoute("/api/v1/series", promRouter) + a.registerPrometheusRoute("/api/v1/metadata", promRouter) + + a.registerRoute("/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) + a.registerRoute("/api/v1/chunks", querier.ChunksHandler(queryable), true) + + return nil +} diff --git a/pkg/ruler/api.go b/pkg/ruler/api.go index 0fbd0fa8225..f3020c6d60a 100644 --- a/pkg/ruler/api.go +++ b/pkg/ruler/api.go @@ -35,13 +35,13 @@ func (r *Ruler) RegisterRoutes(router *mux.Router, middleware middleware.Interfa name, method, path string handler http.HandlerFunc }{ - {"get_rules", "GET", "/api/v1/rules", r.rules}, - {"get_alerts", "GET", "/api/v1/alerts", r.alerts}, - {"list_rules", "GET", "/rules", r.listRules}, - {"list_rules_namespace", "GET", "/rules/{namespace}", r.listRules}, - {"get_rulegroup", "GET", "/rules/{namespace}/{groupName}", r.getRuleGroup}, - {"set_rulegroup", "POST", "/rules/{namespace}", r.createRuleGroup}, - {"delete_rulegroup", "DELETE", "/rules/{namespace}/{groupName}", r.deleteRuleGroup}, + {"get_rules", "GET", "/api/v1/rules", r.PrometheusRules}, + {"get_alerts", "GET", "/api/v1/alerts", r.PrometheusAlerts}, + {"list_rules", "GET", "/rules", r.ListRules}, + {"list_rules_namespace", "GET", "/rules/{namespace}", r.ListRules}, + {"get_rulegroup", "GET", "/rules/{namespace}/{groupName}", r.GetRuleGroup}, + {"set_rulegroup", "POST", "/rules/{namespace}", r.CreateRuleGroup}, + {"delete_rulegroup", "DELETE", "/rules/{namespace}/{groupName}", r.DeleteRuleGroup}, } { level.Debug(util.Logger).Log("msg", "ruler: registering route", "name", route.name, "method", route.method, "path", route.path) router.Handle(route.path, middleware.Wrap(route.handler)).Methods(route.method).Name(route.name) @@ -142,7 +142,7 @@ func respondError(logger log.Logger, w http.ResponseWriter, msg string) { } } -func (r *Ruler) rules(w http.ResponseWriter, req *http.Request) { +func (r *Ruler) PrometheusRules(w http.ResponseWriter, req *http.Request) { logger := util.WithContext(req.Context(), util.Logger) userID, ctx, err := user.ExtractOrgIDFromHTTPRequest(req) if err != nil || userID == "" { @@ -234,7 +234,7 @@ func (r *Ruler) rules(w http.ResponseWriter, req *http.Request) { } } -func (r *Ruler) alerts(w http.ResponseWriter, req *http.Request) { +func (r *Ruler) PrometheusAlerts(w http.ResponseWriter, req *http.Request) { logger := util.WithContext(req.Context(), util.Logger) userID, ctx, err := user.ExtractOrgIDFromHTTPRequest(req) if err != nil || userID == "" { @@ -412,7 +412,7 @@ func parseRequest(req *http.Request, requireNamespace, requireGroup bool) (strin return userID, namespace, group, nil } -func (r *Ruler) listRules(w http.ResponseWriter, req *http.Request) { +func (r *Ruler) ListRules(w http.ResponseWriter, req *http.Request) { logger := util.WithContext(req.Context(), util.Logger) userID, namespace, _, err := parseRequest(req, false, false) @@ -440,7 +440,7 @@ func (r *Ruler) listRules(w http.ResponseWriter, req *http.Request) { marshalAndSend(formatted, w, logger) } -func (r *Ruler) getRuleGroup(w http.ResponseWriter, req *http.Request) { +func (r *Ruler) GetRuleGroup(w http.ResponseWriter, req *http.Request) { logger := util.WithContext(req.Context(), util.Logger) userID, namespace, groupName, err := parseRequest(req, true, true) if err != nil { @@ -462,7 +462,7 @@ func (r *Ruler) getRuleGroup(w http.ResponseWriter, req *http.Request) { marshalAndSend(formatted, w, logger) } -func (r *Ruler) createRuleGroup(w http.ResponseWriter, req *http.Request) { +func (r *Ruler) CreateRuleGroup(w http.ResponseWriter, req *http.Request) { logger := util.WithContext(req.Context(), util.Logger) userID, namespace, _, err := parseRequest(req, true, false) if err != nil { @@ -509,7 +509,7 @@ func (r *Ruler) createRuleGroup(w http.ResponseWriter, req *http.Request) { respondAccepted(w, logger) } -func (r *Ruler) deleteRuleGroup(w http.ResponseWriter, req *http.Request) { +func (r *Ruler) DeleteRuleGroup(w http.ResponseWriter, req *http.Request) { logger := util.WithContext(req.Context(), util.Logger) userID, namespace, groupName, err := parseRequest(req, true, true) diff --git a/pkg/ruler/api_test.go b/pkg/ruler/api_test.go index 924faaf2baa..354268b1289 100644 --- a/pkg/ruler/api_test.go +++ b/pkg/ruler/api_test.go @@ -25,7 +25,7 @@ func TestRuler_rules(t *testing.T) { req := httptest.NewRequest("GET", "https://localhost:8080/api/prom/api/v1/rules", nil) req.Header.Add(user.OrgIDHeaderName, "user1") w := httptest.NewRecorder() - r.rules(w, req) + r.PrometheusRules(w, req) resp := w.Result() body, _ := ioutil.ReadAll(resp.Body) @@ -81,7 +81,7 @@ func TestRuler_alerts(t *testing.T) { req := httptest.NewRequest("GET", "https://localhost:8080/api/prom/api/v1/alerts", nil) req.Header.Add(user.OrgIDHeaderName, "user1") w := httptest.NewRecorder() - r.alerts(w, req) + r.PrometheusAlerts(w, req) resp := w.Result() body, _ := ioutil.ReadAll(resp.Body) From 480e92776e5e8a48dda709c55bbd52da19137393 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 12:42:13 -0400 Subject: [PATCH 02/28] all modules registered using API Signed-off-by: Jacob Lisi --- go.sum | 8 ++ pkg/api/api.go | 191 ++++++++++++++++++++-------- pkg/api/handlers.go | 63 +++++++++ pkg/chunk/purger/request_handler.go | 4 +- pkg/cortex/cortex.go | 16 ++- pkg/cortex/modules.go | 171 ++++++++++--------------- 6 files changed, 288 insertions(+), 165 deletions(-) create mode 100644 pkg/api/handlers.go diff --git a/go.sum b/go.sum index e33fcfc2759..804c9a8df72 100644 --- a/go.sum +++ b/go.sum @@ -141,6 +141,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190531201743-edce55837238 h1:uNljlOxtOHrPnRoPPx+JanqjAGZpNiqAGVBfGskd/pg= @@ -395,6 +396,8 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -510,6 +513,8 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.0.0/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -529,7 +534,9 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743 h1:143Bb8f8DuGWck/xpNUOckBVYfFbBTnLevfRZ1aVVqo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.0 h1:fAazJekOWnfBeQYwk9jEgIWWKmBxq4ev3WfsAnezgc4= github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -703,6 +710,7 @@ github.com/prometheus/prometheus v1.8.2-0.20200213233353-b90be6f32a33 h1:HBYrMJj github.com/prometheus/prometheus v1.8.2-0.20200213233353-b90be6f32a33/go.mod h1:fkIPPkuZnkXyopYHmXPxf9rgiPkVgZCN8w9o8+UgBlY= github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1 h1:+kGqA4dNN5hn7WwvKdzHl0rdN5AEkbNZd0VjRltAiZg= github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= diff --git a/pkg/api/api.go b/pkg/api/api.go index ccaf20ffe1c..69d5289c924 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -8,7 +8,6 @@ import ( "github.com/go-kit/kit/log" "github.com/gorilla/mux" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/route" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/promql" @@ -20,11 +19,15 @@ import ( "github.com/cortexproject/cortex/pkg/alertmanager" "github.com/cortexproject/cortex/pkg/chunk/purger" + "github.com/cortexproject/cortex/pkg/compactor" "github.com/cortexproject/cortex/pkg/distributor" "github.com/cortexproject/cortex/pkg/ingester" "github.com/cortexproject/cortex/pkg/ingester/client" "github.com/cortexproject/cortex/pkg/querier" + "github.com/cortexproject/cortex/pkg/querier/frontend" + "github.com/cortexproject/cortex/pkg/ring" "github.com/cortexproject/cortex/pkg/ruler" + "github.com/cortexproject/cortex/pkg/storegateway" "github.com/cortexproject/cortex/pkg/util/push" ) @@ -32,6 +35,9 @@ type Config struct { AlertmanagerHTTPPrefix string `yaml:"alertmanager_http_prefix"` PrometheusHTTPPrefix string `yaml:"prometheus_http_prefix"` + // The following configs are injected by the upstream caller. + ServerPrefix string `yaml:"-"` + LegacyHTTPPrefix string `yaml:"-"` HTTPAuthMiddleware middleware.Func `yaml:"-"` } @@ -47,30 +53,26 @@ func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { } type API struct { - cfg Config - legacyPrefix string - - authMiddleware middleware.Func - server *server.Server - alertmanagerRouter *mux.Router - prometheusRouter *mux.Router - - reg prometheus.Registerer - logger log.Logger + cfg Config + authMiddleware middleware.Func + server *server.Server + prometheusRouter *mux.Router + logger log.Logger } -func New(cfg Config, s *server.Server, legacyPrefix string, logger log.Logger, reg prometheus.Registerer) (*API, error) { +func New(cfg Config, s *server.Server, logger log.Logger) (*API, error) { + // Ensure the encoded path is used. Required for the rules API + s.HTTP.UseEncodedPath() + api := &API{ - cfg: cfg, - legacyPrefix: legacyPrefix, - authMiddleware: cfg.HTTPAuthMiddleware, - alertmanagerRouter: s.HTTP.PathPrefix(cfg.AlertmanagerHTTPPrefix).Subrouter(), - prometheusRouter: s.HTTP.PathPrefix(cfg.PrometheusHTTPPrefix).Subrouter(), - server: s, - reg: reg, - logger: logger, + cfg: cfg, + authMiddleware: cfg.HTTPAuthMiddleware, + prometheusRouter: s.HTTP.PathPrefix(cfg.PrometheusHTTPPrefix).Subrouter(), + server: s, + logger: logger, } + // If no authentication middleware is present in the config, use the middlewar if cfg.HTTPAuthMiddleware == nil { api.authMiddleware = middleware.AuthenticateUser } @@ -89,7 +91,10 @@ func (a *API) registerRoute(path string, handler http.Handler, auth bool, method a.server.HTTP.Path(path).Methods(methods...).Handler(handler) } +// Register the route under the prometheus component path as well as the provided legacy +// path func (a *API) registerPrometheusRoute(path string, handler http.Handler, methods ...string) { + a.registerRoute(a.cfg.LegacyHTTPPrefix+path, handler, true, methods...) if len(methods) == 0 { a.prometheusRouter.Path(path).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) return @@ -97,14 +102,6 @@ func (a *API) registerPrometheusRoute(path string, handler http.Handler, methods a.prometheusRouter.Path(path).Methods(methods...).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) } -func (a *API) registerAlertmanagerRoute(path string, handler http.Handler, methods ...string) { - if len(methods) == 0 { - a.alertmanagerRouter.Path(path).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) - return - } - a.alertmanagerRouter.Path(path).Methods(methods...).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) -} - // Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. // Requests to Querier sometimes doesn't have that (if they are fetched from Query-Frontend). // Prometheus uses this when logging queries to QueryLogger, but Cortex doesn't call engine.SetQueryLogger to set one. @@ -119,53 +116,112 @@ func fakeRemoteAddr(handler http.Handler) http.Handler { }) } -func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager) { - a.RegisterRoute("/alertmanager/status", am.GetStatusHandler(), false) +// RegisterAlertmanager registers endpoints associated with the alertmanager. It will only +// serve endpoints using the legacy http-prefix if it is not run as a single binary. +func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager, target bool) { + // Ensure this route is registered before the prefixed AM route + a.registerRoute("/multitenant-alertmanager/status", am.GetStatusHandler(), false) + // UI components lead to a large number of routes to support, utilize a path prefix instead + a.server.HTTP.PathPrefix(a.cfg.AlertmanagerHTTPPrefix).Handler(a.authMiddleware.Wrap(am)) + + // If the target is Alertmanager, enable the legacy behaviour. Otherwise only enable + // the component routed API. + if target { + a.registerRoute("/status", am.GetStatusHandler(), false) + a.server.HTTP.PathPrefix(a.cfg.LegacyHTTPPrefix).Handler(a.authMiddleware.Wrap(am)) + } +} + +// RegisterAPI registers the standard endpoints associated with a running Cortex. +func (a *API) RegisterAPI(cfg interface{}) { + a.registerRoute("/config", configHandler(cfg), false) + a.registerRoute("/", http.HandlerFunc(indexHandler), false) } +// RegisterDistributor registers the endpoints associated with the distributor. func (a *API) RegisterDistributor(d *distributor.Distributor, pushConfig distributor.Config) { + a.registerRoute("/api/v1/push", push.Handler(pushConfig, d.Push), true) + a.registerRoute("/distributor/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false) + a.registerRoute("/distributor/ha-tracker", d.Replicas, false) + + // Legacy Routes + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/push", push.Handler(pushConfig, d.Push), true) a.registerRoute("/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false) - a.registerRoute("/push", push.Handler(pushConfig, d.Push), true) a.registerRoute("/ha-tracker", d.Replicas, false) } +// RegisterIngester registers the ingesters HTTP and GRPC service func (a *API) RegisterIngester(i *ingester.Ingester, pushConfig distributor.Config) { client.RegisterIngesterServer(a.server.GRPC, i) grpc_health_v1.RegisterHealthServer(a.server.GRPC, i) + + a.registerRoute("/ingester/flush", http.HandlerFunc(i.FlushHandler), false) + a.registerRoute("/ingester/shutdown", http.HandlerFunc(i.ShutdownHandler), false) + a.registerRoute("/ingester/push", push.Handler(pushConfig, i.Push), true) // For testing and debugging. + + // Legacy Routes a.registerRoute("/flush", http.HandlerFunc(i.FlushHandler), false) a.registerRoute("/shutdown", http.HandlerFunc(i.ShutdownHandler), false) - a.registerRoute("/push", push.Handler(pushConfig, i.Push), true) + a.registerRoute("/push", push.Handler(pushConfig, i.Push), true) // For testing and debugging. } -func (a *API) RegisterPurger(store *purger.DeleteStore) error { - var deleteRequestHandler *purger.DeleteRequestHandler - deleteRequestHandler, err := purger.NewDeleteRequestHandler(store) - if err != nil { - return err - } +// RegisterPurger registers the endpoints associated with the Purger/DeleteStore. They do not exacty +// match the Prometheus API but mirror it closely enough to justify their routing under the Prometheus +// component/ +func (a *API) RegisterPurger(store *purger.DeleteStore) { + deleteRequestHandler := purger.NewDeleteRequestHandler(store) a.registerPrometheusRoute("/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), "PUT", "POST") a.registerPrometheusRoute("/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), "GET") - return nil } -func (a *API) RegisterRing(component string, handler http.Handler) { - a.server.HTTP.Handle("/"+component+"/ring", handler) +// RegisterRuler registers routes associated with the Ruler service. If the +// API is not enabled only the ring route is registered. +func (a *API) RegisterRuler(r *ruler.Ruler, apiEnabled bool) { + a.registerRoute("/ruler/ring", r, false) + + if apiEnabled { + a.registerPrometheusRoute("/api/v1/rules", http.HandlerFunc(r.PrometheusRules), "GET") + a.registerPrometheusRoute("/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), "GET") + + ruler.RegisterRulerServer(a.server.GRPC, r) + + a.registerRoute("/api/v1/rules", http.HandlerFunc(r.ListRules), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") + a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") + a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") + + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules", http.HandlerFunc(r.ListRules), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") + } +} + +// // RegisterRing registers the ring UI page associated with the distributor for writes. +func (a *API) RegisterRing(r *ring.Ring) { + a.registerRoute("/ring", r, false) +} + +// RegisterStoreGateway registers the ring UI page associated with the store-gateway. +func (a *API) RegisterStoreGateway(s *storegateway.StoreGateway) { + a.registerRoute("/store-gateway/ring", http.HandlerFunc(s.RingHandler), false) } -func (a *API) RegisterRuler(r *ruler.Ruler) { - a.registerPrometheusRoute("/api/v1/rules", http.HandlerFunc(r.PrometheusRules), "GET") - a.registerPrometheusRoute("/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), "GET") - a.registerRoute("/api/v1/rules", http.HandlerFunc(r.ListRules), true, "GET") - a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") - a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") - a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") - a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") - a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") +// RegisterCompactor registers the ring UI page associated with the compactor. +func (a *API) RegisterCompactor(c *compactor.Compactor) { + a.registerRoute("/compactor/ring", http.HandlerFunc(c.RingHandler), false) } -func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine, distributor *distributor.Distributor) error { +// RegisterQuerier registers the Prometheus routes supported by the +// Cortex querier service. Currently this can not be registered simultaneously +// with the QueryFrontend. +func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine, distributor *distributor.Distributor) { api := v1.NewAPI( engine, queryable, @@ -184,7 +240,7 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine &v1.PrometheusVersion{}, ) - promRouter := route.New().WithPrefix(a.cfg.PrometheusHTTPPrefix + "/api/v1") + promRouter := route.New().WithPrefix(a.cfg.ServerPrefix + a.cfg.PrometheusHTTPPrefix + "/api/v1") api.Register(promRouter) a.registerPrometheusRoute("/api/v1/read", querier.RemoteReadHandler(queryable)) @@ -195,8 +251,35 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine a.registerPrometheusRoute("/api/v1/series", promRouter) a.registerPrometheusRoute("/api/v1/metadata", promRouter) - a.registerRoute("/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) + a.registerRoute("/api/v1/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) a.registerRoute("/api/v1/chunks", querier.ChunksHandler(queryable), true) - return nil + // Legacy Routes + a.registerRoute("/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) + a.registerRoute("/chunks", querier.ChunksHandler(queryable), true) +} + +// RegisterQueryFrontend registers the Prometheus routes supported by the +// Cortex querier service. Currently this can not be registered simultaneously +// with the Querier. +func (a *API) RegisterQueryFrontend(f *frontend.Frontend) { + frontend.RegisterFrontendServer(a.server.GRPC, f) + + // Previously the frontend handled all calls to the provided prefix. Instead explicit + // routing is used since it will be required to enable the frontend to be run as part + // of a single binary in the future. + a.registerPrometheusRoute("/api/v1/read", f.Handler()) + a.registerPrometheusRoute("/api/v1/query", f.Handler()) + a.registerPrometheusRoute("/api/v1/query_range", f.Handler()) + a.registerPrometheusRoute("/api/v1/labels", f.Handler()) + a.registerPrometheusRoute("/api/v1/label/{name}/values", f.Handler()) + a.registerPrometheusRoute("/api/v1/series", f.Handler()) + a.registerPrometheusRoute("/api/v1/metadata", f.Handler()) +} + +// RegisterServiceMapHandler registers the Cortex structs service handler +// TODO: Refactor this code to be accomplished using the services.ServiceManager +// or a future module manager #2291 +func (a *API) RegisterServiceMapHandler(handler http.Handler) { + a.registerRoute("/services", handler, false) } diff --git a/pkg/api/handlers.go b/pkg/api/handlers.go new file mode 100644 index 00000000000..40d630a4189 --- /dev/null +++ b/pkg/api/handlers.go @@ -0,0 +1,63 @@ +package api + +import ( + "net/http" + + "github.com/cortexproject/cortex/pkg/util" + "github.com/go-kit/kit/log/level" + "gopkg.in/yaml.v2" +) + +// TODO: Update this content to be a template that is dynamic based on how Cortex is run. +const indexPageContent = ` + + + + + Cortex + + +

Cortex

+

Admin Endpoints:

+ + +

Dangerous:

+ + +` + +func indexHandler(w http.ResponseWriter, _ *http.Request) { + if _, err := w.Write([]byte(indexPageContent)); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +func configHandler(cfg interface{}) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + out, err := yaml.Marshal(cfg) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "text/yaml") + w.WriteHeader(http.StatusOK) + if _, err := w.Write(out); err != nil { + level.Error(util.Logger).Log("msg", "error writing response", "err", err) + } + } +} diff --git a/pkg/chunk/purger/request_handler.go b/pkg/chunk/purger/request_handler.go index 30a4035e3c2..0ec5bd35aac 100644 --- a/pkg/chunk/purger/request_handler.go +++ b/pkg/chunk/purger/request_handler.go @@ -18,12 +18,12 @@ type DeleteRequestHandler struct { } // NewDeleteRequestHandler creates a DeleteRequestHandler -func NewDeleteRequestHandler(deleteStore *DeleteStore) (*DeleteRequestHandler, error) { +func NewDeleteRequestHandler(deleteStore *DeleteStore) *DeleteRequestHandler { deleteMgr := DeleteRequestHandler{ deleteStore: deleteStore, } - return &deleteMgr, nil + return &deleteMgr } // AddDeleteRequestHandler handles addition of new delete request diff --git a/pkg/cortex/cortex.go b/pkg/cortex/cortex.go index 77427b50184..1c81bc7ecc9 100644 --- a/pkg/cortex/cortex.go +++ b/pkg/cortex/cortex.go @@ -23,6 +23,7 @@ import ( "gopkg.in/yaml.v2" "github.com/cortexproject/cortex/pkg/alertmanager" + "github.com/cortexproject/cortex/pkg/api" "github.com/cortexproject/cortex/pkg/chunk" "github.com/cortexproject/cortex/pkg/chunk/cache" "github.com/cortexproject/cortex/pkg/chunk/encoding" @@ -30,7 +31,8 @@ import ( "github.com/cortexproject/cortex/pkg/chunk/storage" chunk_util "github.com/cortexproject/cortex/pkg/chunk/util" "github.com/cortexproject/cortex/pkg/compactor" - "github.com/cortexproject/cortex/pkg/configs/api" + "github.com/cortexproject/cortex/pkg/configs" + configAPI "github.com/cortexproject/cortex/pkg/configs/api" "github.com/cortexproject/cortex/pkg/configs/db" "github.com/cortexproject/cortex/pkg/distributor" "github.com/cortexproject/cortex/pkg/flusher" @@ -43,6 +45,7 @@ import ( "github.com/cortexproject/cortex/pkg/ring/kv/memberlist" "github.com/cortexproject/cortex/pkg/ruler" "github.com/cortexproject/cortex/pkg/storage/tsdb" + "github.com/cortexproject/cortex/pkg/storegateway" "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/runtimeconfig" "github.com/cortexproject/cortex/pkg/util/services" @@ -73,6 +76,7 @@ type Config struct { PrintConfig bool `yaml:"-"` HTTPPrefix string `yaml:"http_prefix"` + API api.Config `yaml:"api"` Server server.Config `yaml:"server"` Distributor distributor.Config `yaml:"distributor"` Querier querier.Config `yaml:"querier"` @@ -111,6 +115,7 @@ func (c *Config) RegisterFlags(f *flag.FlagSet) { f.BoolVar(&c.PrintConfig, "print.config", false, "Print the config and exit.") f.StringVar(&c.HTTPPrefix, "http.prefix", "/api/prom", "HTTP path prefix for Cortex API.") + c.API.RegisterFlags(f) c.Server.RegisterFlags(f) c.Distributor.RegisterFlags(f) c.Querier.RegisterFlags(f) @@ -183,6 +188,7 @@ type Cortex struct { // set during initialization serviceMap map[ModuleName]services.Service + api *api.API server *server.Server ring *ring.Ring overrides *validation.Overrides @@ -198,7 +204,7 @@ type Cortex struct { dataPurger *purger.DataPurger ruler *ruler.Ruler - configAPI *api.API + configAPI *configAPI.API configDB db.DB alertmanager *alertmanager.MultitenantAlertmanager compactor *compactor.Compactor @@ -231,7 +237,8 @@ func New(cfg Config) (*Cortex, error) { } cortex.serviceMap = serviceMap - cortex.server.HTTP.Handle("/services", http.HandlerFunc(cortex.servicesHandler)) + cortex.api.RegisterServiceMapHandler(http.HandlerFunc(cortex.servicesHandler)) + return cortex, nil } @@ -255,7 +262,6 @@ func (t *Cortex) setupAuthMiddleware(cfg *Config) { } }, } - t.httpAuthMiddleware = middleware.AuthenticateUser } else { cfg.Server.GRPCMiddleware = []grpc.UnaryServerInterceptor{ fakeGRPCAuthUniaryMiddleware, @@ -263,7 +269,7 @@ func (t *Cortex) setupAuthMiddleware(cfg *Config) { cfg.Server.GRPCStreamMiddleware = []grpc.StreamServerInterceptor{ fakeGRPCAuthStreamMiddleware, } - t.httpAuthMiddleware = fakeHTTPAuthMiddleware + cfg.API.HTTPAuthMiddleware = fakeHTTPAuthMiddleware } } diff --git a/pkg/cortex/modules.go b/pkg/cortex/modules.go index 3afab273217..6354c637771 100644 --- a/pkg/cortex/modules.go +++ b/pkg/cortex/modules.go @@ -1,34 +1,31 @@ package cortex import ( - "errors" "fmt" - "net/http" "os" - "regexp" "strings" "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/route" - "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/promql" - v1 "github.com/prometheus/prometheus/web/api/v1" httpgrpc_server "github.com/weaveworks/common/httpgrpc/server" - "github.com/weaveworks/common/middleware" "github.com/weaveworks/common/server" +<<<<<<< HEAD +======= + "google.golang.org/grpc" +>>>>>>> 1ce95f0cd... all modules registered using API "github.com/cortexproject/cortex/pkg/alertmanager" + "github.com/cortexproject/cortex/pkg/api" "github.com/cortexproject/cortex/pkg/chunk" "github.com/cortexproject/cortex/pkg/chunk/purger" "github.com/cortexproject/cortex/pkg/chunk/storage" "github.com/cortexproject/cortex/pkg/compactor" - "github.com/cortexproject/cortex/pkg/configs/api" + configAPI "github.com/cortexproject/cortex/pkg/configs/api" "github.com/cortexproject/cortex/pkg/configs/db" "github.com/cortexproject/cortex/pkg/distributor" "github.com/cortexproject/cortex/pkg/flusher" "github.com/cortexproject/cortex/pkg/ingester" - "github.com/cortexproject/cortex/pkg/ingester/client" "github.com/cortexproject/cortex/pkg/querier" "github.com/cortexproject/cortex/pkg/querier/frontend" "github.com/cortexproject/cortex/pkg/querier/queryrange" @@ -38,7 +35,6 @@ import ( "github.com/cortexproject/cortex/pkg/ruler" "github.com/cortexproject/cortex/pkg/storegateway" "github.com/cortexproject/cortex/pkg/util" - "github.com/cortexproject/cortex/pkg/util/push" "github.com/cortexproject/cortex/pkg/util/runtimeconfig" "github.com/cortexproject/cortex/pkg/util/services" "github.com/cortexproject/cortex/pkg/util/validation" @@ -49,6 +45,7 @@ type ModuleName string // The various modules that make up Cortex. const ( + API ModuleName = "api" Ring ModuleName = "ring" RuntimeConfig ModuleName = "runtime-config" Overrides ModuleName = "overrides" @@ -97,6 +94,31 @@ func (m *ModuleName) UnmarshalYAML(unmarshal func(interface{}) error) error { return m.Set(s) } +func (t *Cortex) initAPI(cfg *Config) (services.Service, error) { + cfg.API.ServerPrefix = cfg.Server.PathPrefix + + if !cfg.AuthEnabled { + cfg.Server.GRPCMiddleware = []grpc.UnaryServerInterceptor{ + fakeGRPCAuthUniaryMiddleware, + } + cfg.Server.GRPCStreamMiddleware = []grpc.StreamServerInterceptor{ + fakeGRPCAuthStreamMiddleware, + } + t.httpAuthMiddleware = fakeHTTPAuthMiddleware + } + + a, err := api.New(cfg.API, t.server, util.Logger) + if err != nil { + return nil, err + } + + t.api = a + + t.api.RegisterAPI(cfg) + + return nil, nil +} + func (t *Cortex) initServer(cfg *Config) (services.Service, error) { serv, err := server.New(cfg.Server) if err != nil { @@ -117,8 +139,6 @@ func (t *Cortex) initServer(cfg *Config) (services.Service, error) { } s := NewServerService(t.server, servicesToWaitFor) - serv.HTTP.HandleFunc("/", indexHandler) - serv.HTTP.HandleFunc("/config", configHandler(cfg)) return s, nil } @@ -131,7 +151,9 @@ func (t *Cortex) initRing(cfg *Config) (serv services.Service, err error) { return nil, err } prometheus.MustRegister(t.ring) - t.server.HTTP.Handle("/ring", t.ring) + + t.api.RegisterRing(t.ring) + return t.ring, nil } @@ -171,9 +193,8 @@ func (t *Cortex) initDistributor(cfg *Config) (serv services.Service, err error) return } - t.server.HTTP.HandleFunc("/all_user_stats", t.distributor.AllUserStatsHandler) - t.server.HTTP.Handle("/api/prom/push", t.httpAuthMiddleware.Wrap(push.Handler(cfg.Distributor, t.distributor.Push))) - t.server.HTTP.Handle("/ha-tracker", t.distributor.Replicas) + t.api.RegisterDistributor(t.distributor, cfg.Distributor) + return t.distributor, nil } @@ -187,31 +208,8 @@ func (t *Cortex) initQuerier(cfg *Config) (serv services.Service, err error) { } queryable, engine := querier.New(cfg.Querier, t.distributor, t.storeQueryable, tombstonesLoader, prometheus.DefaultRegisterer) - api := v1.NewAPI( - engine, - queryable, - querier.DummyTargetRetriever{}, - querier.DummyAlertmanagerRetriever{}, - func() config.Config { return config.Config{} }, - map[string]string{}, // TODO: include configuration flags - func(f http.HandlerFunc) http.HandlerFunc { return f }, - func() v1.TSDBAdmin { return nil }, // Only needed for admin APIs. - false, // Disable admin APIs. - util.Logger, - querier.DummyRulesRetriever{}, - 0, 0, 0, // Remote read samples and concurrency limit. - regexp.MustCompile(".*"), - func() (v1.RuntimeInfo, error) { return v1.RuntimeInfo{}, errors.New("not implemented") }, - &v1.PrometheusVersion{}, - ) - promRouter := route.New().WithPrefix("/api/prom/api/v1") - api.Register(promRouter) - subrouter := t.server.HTTP.PathPrefix("/api/prom").Subrouter() - subrouter.PathPrefix("/api/v1").Handler(fakeRemoteAddr(t.httpAuthMiddleware.Wrap(promRouter))) - subrouter.Path("/read").Handler(t.httpAuthMiddleware.Wrap(querier.RemoteReadHandler(queryable))) - subrouter.Path("/chunks").Handler(t.httpAuthMiddleware.Wrap(querier.ChunksHandler(queryable))) - subrouter.Path("/user_stats").Handler(middleware.AuthenticateUser.Wrap(http.HandlerFunc(t.distributor.UserStatsHandler))) + t.api.RegisterQuerier(queryable, engine, t.distributor) // Query frontend worker will only be started after all its dependencies are started, not here. // Worker may also be nil, if not configured, which is OK. @@ -223,20 +221,6 @@ func (t *Cortex) initQuerier(cfg *Config) (serv services.Service, err error) { return worker, nil } -// Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. -// Requests to Querier sometimes doesn't have that (if they are fetched from Query-Frontend). -// Prometheus uses this when logging queries to QueryLogger, but Cortex doesn't call engine.SetQueryLogger to set one. -// -// Can be removed when (if) https://github.com/prometheus/prometheus/pull/6840 is merged. -func fakeRemoteAddr(handler http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.RemoteAddr == "" { - r.RemoteAddr = "127.0.0.1:8888" - } - handler.ServeHTTP(w, r) - }) -} - func (t *Cortex) initStoreQueryable(cfg *Config) (services.Service, error) { if cfg.Storage.Engine == storage.StorageEngineChunks { t.storeQueryable = querier.NewChunkStoreQueryable(cfg.Querier, t.store) @@ -268,10 +252,8 @@ func (t *Cortex) initIngester(cfg *Config) (serv services.Service, err error) { return } - client.RegisterIngesterServer(t.server.GRPC, t.ingester) - t.server.HTTP.Path("/flush").Handler(http.HandlerFunc(t.ingester.FlushHandler)) - t.server.HTTP.Path("/shutdown").Handler(http.HandlerFunc(t.ingester.ShutdownHandler)) - t.server.HTTP.Handle("/push", t.httpAuthMiddleware.Wrap(push.Handler(cfg.Distributor, t.ingester.Push))) + t.api.RegisterIngester(t.ingester, cfg.Distributor) + return t.ingester, nil } @@ -365,12 +347,8 @@ func (t *Cortex) initQueryFrontend(cfg *Config) (serv services.Service, err erro t.cache = cache t.frontend.Wrap(tripperware) - frontend.RegisterFrontendServer(t.server.GRPC, t.frontend) - t.server.HTTP.PathPrefix(cfg.HTTPPrefix).Handler( - t.httpAuthMiddleware.Wrap( - t.frontend.Handler(), - ), - ) + t.api.RegisterQueryFrontend(t.frontend) + return services.NewIdleService(nil, func(_ error) error { t.frontend.Close() if t.cache != nil { @@ -437,15 +415,9 @@ func (t *Cortex) initRuler(cfg *Config) (serv services.Service, err error) { return } - if cfg.Ruler.EnableAPI { - util.WarnExperimentalUse("Ruler API") - - subrouter := t.server.HTTP.PathPrefix(cfg.HTTPPrefix).Subrouter() - t.ruler.RegisterRoutes(subrouter, t.httpAuthMiddleware) - ruler.RegisterRulerServer(t.server.GRPC, t.ruler) - } + // Expose HTTP endpoints. + t.api.RegisterRuler(t.ruler, cfg.Ruler.EnableAPI) - t.server.HTTP.Handle("/ruler_ring", t.ruler) return t.ruler, nil } @@ -455,7 +427,7 @@ func (t *Cortex) initConfig(cfg *Config) (serv services.Service, err error) { return } - t.configAPI = api.New(t.configDB, cfg.Configs.API) + t.configAPI = configAPI.New(t.configDB, cfg.Configs.API) t.configAPI.RegisterRoutes(t.server.HTTP) return services.NewIdleService(nil, func(_ error) error { t.configDB.Close() @@ -468,11 +440,7 @@ func (t *Cortex) initAlertManager(cfg *Config) (serv services.Service, err error if err != nil { return } - t.server.HTTP.PathPrefix("/status").Handler(t.alertmanager.GetStatusHandler()) - - // TODO this clashed with the queirer and the distributor, so we cannot - // run them in the same process. - t.server.HTTP.PathPrefix("/api/prom").Handler(middleware.AuthenticateUser.Wrap(t.alertmanager)) + t.api.RegisterAlertmanager(t.alertmanager, cfg.Target == AlertManager) return t.alertmanager, nil } @@ -486,8 +454,7 @@ func (t *Cortex) initCompactor(cfg *Config) (serv services.Service, err error) { } // Expose HTTP endpoints. - t.server.HTTP.HandleFunc("/compactor/ring", t.compactor.RingHandler) - + t.api.RegisterCompactor(t.compactor) return t.compactor, nil } @@ -502,7 +469,7 @@ func (t *Cortex) initStoreGateway(cfg *Config) (serv services.Service, err error t.storeGateway = storegateway.NewStoreGateway(cfg.StoreGateway, cfg.TSDB, util.Logger, prometheus.DefaultRegisterer) // Expose HTTP endpoints. - t.server.HTTP.HandleFunc("/store-gateway/ring", t.storeGateway.RingHandler) + t.api.RegisterStoreGateway(t.storeGateway) return t.storeGateway, nil } @@ -535,16 +502,7 @@ func (t *Cortex) initDataPurger(cfg *Config) (services.Service, error) { return nil, err } - var deleteRequestHandler *purger.DeleteRequestHandler - deleteRequestHandler, err = purger.NewDeleteRequestHandler(t.deletesStore) - if err != nil { - return nil, err - } - - adminRouter := t.server.HTTP.PathPrefix(cfg.HTTPPrefix + "/api/v1/admin/tsdb").Subrouter() - - adminRouter.Path("/delete_series").Methods("PUT", "POST").Handler(t.httpAuthMiddleware.Wrap(http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler))) - adminRouter.Path("/delete_series").Methods("GET").Handler(t.httpAuthMiddleware.Wrap(http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler))) + t.api.RegisterPurger(t.deletesStore) return t.dataPurger, nil } @@ -568,6 +526,11 @@ var modules = map[ModuleName]module{ service: (*Cortex).initServer, }, + API: { + deps: []ModuleName{Server}, + wrappedService: (*Cortex).initAPI, + }, + RuntimeConfig: { wrappedService: (*Cortex).initRuntimeConfig, }, @@ -577,7 +540,7 @@ var modules = map[ModuleName]module{ }, Ring: { - deps: []ModuleName{Server, RuntimeConfig, MemberlistKV}, + deps: []ModuleName{API, RuntimeConfig, MemberlistKV}, wrappedService: (*Cortex).initRing, }, @@ -587,7 +550,7 @@ var modules = map[ModuleName]module{ }, Distributor: { - deps: []ModuleName{Ring, Server, Overrides}, + deps: []ModuleName{Ring, API, Overrides}, wrappedService: (*Cortex).initDistributor, }, @@ -601,17 +564,17 @@ var modules = map[ModuleName]module{ }, Ingester: { - deps: []ModuleName{Overrides, Store, Server, RuntimeConfig, MemberlistKV}, + deps: []ModuleName{Overrides, Store, API, RuntimeConfig, MemberlistKV}, wrappedService: (*Cortex).initIngester, }, Flusher: { - deps: []ModuleName{Store, Server}, + deps: []ModuleName{Store, API}, wrappedService: (*Cortex).initFlusher, }, Querier: { - deps: []ModuleName{Distributor, Store, Ring, Server, StoreQueryable}, + deps: []ModuleName{Distributor, Store, Ring, API, StoreQueryable}, wrappedService: (*Cortex).initQuerier, }, @@ -621,12 +584,12 @@ var modules = map[ModuleName]module{ }, QueryFrontend: { - deps: []ModuleName{Server, Overrides}, + deps: []ModuleName{API, Overrides}, wrappedService: (*Cortex).initQueryFrontend, }, TableManager: { - deps: []ModuleName{Server}, + deps: []ModuleName{API}, wrappedService: (*Cortex).initTableManager, }, @@ -636,31 +599,31 @@ var modules = map[ModuleName]module{ }, Configs: { - deps: []ModuleName{Server}, + deps: []ModuleName{API}, wrappedService: (*Cortex).initConfig, }, AlertManager: { - deps: []ModuleName{Server}, + deps: []ModuleName{API}, wrappedService: (*Cortex).initAlertManager, }, Compactor: { - deps: []ModuleName{Server}, + deps: []ModuleName{API}, wrappedService: (*Cortex).initCompactor, }, StoreGateway: { - deps: []ModuleName{Server}, + deps: []ModuleName{API}, wrappedService: (*Cortex).initStoreGateway, }, DataPurger: { - deps: []ModuleName{Store, DeleteRequestsStore, Server}, + deps: []ModuleName{Store, DeleteRequestsStore, API}, wrappedService: (*Cortex).initDataPurger, }, All: { - deps: []ModuleName{Querier, Ingester, Distributor, TableManager, DataPurger, StoreGateway}, + deps: []ModuleName{AlertManager, Ruler, Querier, Ingester, Distributor, TableManager, DataPurger, StoreGateway}, }, } From 424b596ebd2fbad380400a507da38389f7339aa1 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 12:43:01 -0400 Subject: [PATCH 03/28] update vendor directory and remove unused handlers Signed-off-by: Jacob Lisi --- pkg/cortex/server_service.go | 50 -------------- vendor/github.com/gorilla/mux/.travis.yml | 24 ------- .../github.com/gorilla/mux/ISSUE_TEMPLATE.md | 11 --- vendor/github.com/gorilla/mux/README.md | 69 +++++++++++++++++++ vendor/github.com/gorilla/mux/doc.go | 2 +- vendor/github.com/gorilla/mux/middleware.go | 61 ++++++++-------- vendor/github.com/gorilla/mux/regexp.go | 37 +++++++--- vendor/modules.txt | 2 +- 8 files changed, 132 insertions(+), 124 deletions(-) delete mode 100644 vendor/github.com/gorilla/mux/.travis.yml delete mode 100644 vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md diff --git a/pkg/cortex/server_service.go b/pkg/cortex/server_service.go index de4b0fb06bf..a16f67ac5c6 100644 --- a/pkg/cortex/server_service.go +++ b/pkg/cortex/server_service.go @@ -2,11 +2,9 @@ package cortex import ( "context" - "net/http" "github.com/go-kit/kit/log/level" "github.com/weaveworks/common/server" - "gopkg.in/yaml.v2" "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/services" @@ -53,51 +51,3 @@ func NewServerService(serv *server.Server, servicesToWaitFor func() []services.S return services.NewBasicService(nil, runFn, stoppingFn) } - -const indexPageContent = ` - - - - - Cortex - - -

Cortex

-

Admin Endpoints:

- - -

Dangerous:

- - -` - -func indexHandler(w http.ResponseWriter, _ *http.Request) { - if _, err := w.Write([]byte(indexPageContent)); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - -func configHandler(cfg *Config) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - out, err := yaml.Marshal(cfg) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "text/yaml") - w.WriteHeader(http.StatusOK) - if _, err := w.Write(out); err != nil { - level.Error(util.Logger).Log("msg", "error writing response", "err", err) - } - } -} diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml deleted file mode 100644 index d003ad922f3..00000000000 --- a/vendor/github.com/gorilla/mux/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: go - - -matrix: - include: - - go: 1.7.x - - go: 1.8.x - - go: 1.9.x - - go: 1.10.x - - go: 1.11.x - - go: 1.x - env: LATEST=true - - go: tip - allow_failures: - - go: tip - -install: - - # Skip - -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) - - if [[ "$LATEST" = true ]]; then go vet .; fi - - go test -v -race ./... diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md deleted file mode 100644 index 232be82e47a..00000000000 --- a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,11 +0,0 @@ -**What version of Go are you running?** (Paste the output of `go version`) - - -**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`) - - -**Describe your problem** (and what you have tried so far) - - -**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it) - diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md index c661599ab21..92e422eed7a 100644 --- a/vendor/github.com/gorilla/mux/README.md +++ b/vendor/github.com/gorilla/mux/README.md @@ -2,6 +2,7 @@ [![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) [![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) +[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux) [![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) ![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) @@ -29,6 +30,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv * [Walking Routes](#walking-routes) * [Graceful Shutdown](#graceful-shutdown) * [Middleware](#middleware) +* [Handling CORS Requests](#handling-cors-requests) * [Testing Handlers](#testing-handlers) * [Full Example](#full-example) @@ -491,6 +493,73 @@ r.Use(amw.Middleware) Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it. +### Handling CORS Requests + +[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header. + +* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin` +* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route +* If you do not specify any methods, then: +> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers. + +Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers: + +```go +package main + +import ( + "net/http" + "github.com/gorilla/mux" +) + +func main() { + r := mux.NewRouter() + + // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers + r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions) + r.Use(mux.CORSMethodMiddleware(r)) + + http.ListenAndServe(":8080", r) +} + +func fooHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + if r.Method == http.MethodOptions { + return + } + + w.Write([]byte("foo")) +} +``` + +And an request to `/foo` using something like: + +```bash +curl localhost:8080/foo -v +``` + +Would look like: + +```bash +* Trying ::1... +* TCP_NODELAY set +* Connected to localhost (::1) port 8080 (#0) +> GET /foo HTTP/1.1 +> Host: localhost:8080 +> User-Agent: curl/7.59.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS +< Access-Control-Allow-Origin: * +< Date: Fri, 28 Jun 2019 20:13:30 GMT +< Content-Length: 3 +< Content-Type: text/plain; charset=utf-8 +< +* Connection #0 to host localhost left intact +foo +``` + ### Testing Handlers Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_. diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go index 38957deead3..bd5a38b55d8 100644 --- a/vendor/github.com/gorilla/mux/doc.go +++ b/vendor/github.com/gorilla/mux/doc.go @@ -295,7 +295,7 @@ A more complex authentication middleware, which maps session token to users, cou r := mux.NewRouter() r.HandleFunc("/", handler) - amw := authenticationMiddleware{} + amw := authenticationMiddleware{tokenUsers: make(map[string]string)} amw.Populate() r.Use(amw.Middleware) diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go index ceb812cee28..cf2b26dc037 100644 --- a/vendor/github.com/gorilla/mux/middleware.go +++ b/vendor/github.com/gorilla/mux/middleware.go @@ -32,37 +32,19 @@ func (r *Router) useInterface(mw middleware) { r.middlewares = append(r.middlewares, mw) } -// CORSMethodMiddleware sets the Access-Control-Allow-Methods response header -// on a request, by matching routes based only on paths. It also handles -// OPTIONS requests, by settings Access-Control-Allow-Methods, and then -// returning without calling the next http handler. +// CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header +// on requests for routes that have an OPTIONS method matcher to all the method matchers on +// the route. Routes that do not explicitly handle OPTIONS requests will not be processed +// by the middleware. See examples for usage. func CORSMethodMiddleware(r *Router) MiddlewareFunc { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - var allMethods []string - - err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { - for _, m := range route.matchers { - if _, ok := m.(*routeRegexp); ok { - if m.Match(req, &RouteMatch{}) { - methods, err := route.GetMethods() - if err != nil { - return err - } - - allMethods = append(allMethods, methods...) - } - break - } - } - return nil - }) - + allMethods, err := getAllMethodsForRoute(r, req) if err == nil { - w.Header().Set("Access-Control-Allow-Methods", strings.Join(append(allMethods, "OPTIONS"), ",")) - - if req.Method == "OPTIONS" { - return + for _, v := range allMethods { + if v == http.MethodOptions { + w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ",")) + } } } @@ -70,3 +52,28 @@ func CORSMethodMiddleware(r *Router) MiddlewareFunc { }) } } + +// getAllMethodsForRoute returns all the methods from method matchers matching a given +// request. +func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) { + var allMethods []string + + err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { + for _, m := range route.matchers { + if _, ok := m.(*routeRegexp); ok { + if m.Match(req, &RouteMatch{}) { + methods, err := route.GetMethods() + if err != nil { + return err + } + + allMethods = append(allMethods, methods...) + } + break + } + } + return nil + }) + + return allMethods, err +} diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go index f2528867563..ac1abcd473e 100644 --- a/vendor/github.com/gorilla/mux/regexp.go +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -113,6 +113,13 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro if typ != regexpTypePrefix { pattern.WriteByte('$') } + + var wildcardHostPort bool + if typ == regexpTypeHost { + if !strings.Contains(pattern.String(), ":") { + wildcardHostPort = true + } + } reverse.WriteString(raw) if endSlash { reverse.WriteByte('/') @@ -131,13 +138,14 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro // Done! return &routeRegexp{ - template: template, - regexpType: typ, - options: options, - regexp: reg, - reverse: reverse.String(), - varsN: varsN, - varsR: varsR, + template: template, + regexpType: typ, + options: options, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, + wildcardHostPort: wildcardHostPort, }, nil } @@ -158,11 +166,22 @@ type routeRegexp struct { varsN []string // Variable regexps (validators). varsR []*regexp.Regexp + // Wildcard host-port (no strict port match in hostname) + wildcardHostPort bool } // Match matches the regexp against the URL host or path. func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { - if r.regexpType != regexpTypeHost { + if r.regexpType == regexpTypeHost { + host := getHost(req) + if r.wildcardHostPort { + // Don't be strict on the port match + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + } + return r.regexp.MatchString(host) + } else { if r.regexpType == regexpTypeQuery { return r.matchQueryString(req) } @@ -172,8 +191,6 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { } return r.regexp.MatchString(path) } - - return r.regexp.MatchString(getHost(req)) } // url builds a URL part using the given values. diff --git a/vendor/modules.txt b/vendor/modules.txt index c23bc172ac7..51684b27d70 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -249,7 +249,7 @@ github.com/gophercloud/gophercloud/openstack/identity/v2/tokens github.com/gophercloud/gophercloud/openstack/identity/v3/tokens github.com/gophercloud/gophercloud/openstack/utils github.com/gophercloud/gophercloud/pagination -# github.com/gorilla/mux v1.7.1 +# github.com/gorilla/mux v1.7.3 github.com/gorilla/mux # github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket From 701dafdb87aca8717f0f2edf714f5aec4f0d9f2d Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 12:50:36 -0400 Subject: [PATCH 04/28] disable single binary alertmanager & ruler Signed-off-by: Jacob Lisi --- pkg/cortex/modules.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cortex/modules.go b/pkg/cortex/modules.go index 6354c637771..24e4fa4438a 100644 --- a/pkg/cortex/modules.go +++ b/pkg/cortex/modules.go @@ -624,6 +624,6 @@ var modules = map[ModuleName]module{ }, All: { - deps: []ModuleName{AlertManager, Ruler, Querier, Ingester, Distributor, TableManager, DataPurger, StoreGateway}, + deps: []ModuleName{Querier, Ingester, Distributor, TableManager, DataPurger, StoreGateway}, }, } From 4c8fb4077fd73187df5472b41735b4e99cfe83ba Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 13:04:48 -0400 Subject: [PATCH 05/28] add logging to api package Signed-off-by: Jacob Lisi --- pkg/api/api.go | 5 +++++ pkg/ruler/api.go | 23 ----------------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 69d5289c924..f1909b3fb77 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -5,8 +5,10 @@ import ( "flag" "net/http" "regexp" + "strings" "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/gorilla/mux" "github.com/prometheus/common/route" "github.com/prometheus/prometheus/config" @@ -81,6 +83,7 @@ func New(cfg Config, s *server.Server, logger log.Logger) (*API, error) { } func (a *API) registerRoute(path string, handler http.Handler, auth bool, methods ...string) { + level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "path", path, "auth", auth) if auth { handler = a.authMiddleware.Wrap(handler) } @@ -94,6 +97,7 @@ func (a *API) registerRoute(path string, handler http.Handler, auth bool, method // Register the route under the prometheus component path as well as the provided legacy // path func (a *API) registerPrometheusRoute(path string, handler http.Handler, methods ...string) { + level.Debug(a.logger).Log("msg", "api: registering prometheus route", "methods", strings.Join(methods, ","), "path", path) a.registerRoute(a.cfg.LegacyHTTPPrefix+path, handler, true, methods...) if len(methods) == 0 { a.prometheusRouter.Path(path).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) @@ -124,6 +128,7 @@ func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager, tar // UI components lead to a large number of routes to support, utilize a path prefix instead a.server.HTTP.PathPrefix(a.cfg.AlertmanagerHTTPPrefix).Handler(a.authMiddleware.Wrap(am)) + level.Debug(a.logger).Log("msg", "api: registering alertmanager", "path_prefix", a.cfg.AlertmanagerHTTPPrefix) // If the target is Alertmanager, enable the legacy behaviour. Otherwise only enable // the component routed API. diff --git a/pkg/ruler/api.go b/pkg/ruler/api.go index f3020c6d60a..045631f4ac2 100644 --- a/pkg/ruler/api.go +++ b/pkg/ruler/api.go @@ -15,7 +15,6 @@ import ( "github.com/pkg/errors" v1 "github.com/prometheus/client_golang/api/prometheus/v1" "github.com/prometheus/prometheus/pkg/labels" - "github.com/weaveworks/common/middleware" "github.com/weaveworks/common/user" "gopkg.in/yaml.v2" @@ -26,28 +25,6 @@ import ( "github.com/cortexproject/cortex/pkg/util" ) -// RegisterRoutes registers the ruler API HTTP routes with the provided Router. -func (r *Ruler) RegisterRoutes(router *mux.Router, middleware middleware.Interface) { - // Routes for this API must be encoded to allow for various characters to be - // present in the path URL - router = router.UseEncodedPath() - for _, route := range []struct { - name, method, path string - handler http.HandlerFunc - }{ - {"get_rules", "GET", "/api/v1/rules", r.PrometheusRules}, - {"get_alerts", "GET", "/api/v1/alerts", r.PrometheusAlerts}, - {"list_rules", "GET", "/rules", r.ListRules}, - {"list_rules_namespace", "GET", "/rules/{namespace}", r.ListRules}, - {"get_rulegroup", "GET", "/rules/{namespace}/{groupName}", r.GetRuleGroup}, - {"set_rulegroup", "POST", "/rules/{namespace}", r.CreateRuleGroup}, - {"delete_rulegroup", "DELETE", "/rules/{namespace}/{groupName}", r.DeleteRuleGroup}, - } { - level.Debug(util.Logger).Log("msg", "ruler: registering route", "name", route.name, "method", route.method, "path", route.path) - router.Handle(route.path, middleware.Wrap(route.handler)).Methods(route.method).Name(route.name) - } -} - // In order to reimplement the prometheus rules API, a large amount of code was copied over // This is required because the prometheus api implementation does not pass a context to // the rule retrieval function. From 92fce99866cade154df84810c9ce17a664842754 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 19:09:54 -0400 Subject: [PATCH 06/28] remove unused auth setup in initAPI Signed-off-by: Jacob Lisi --- pkg/cortex/modules.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pkg/cortex/modules.go b/pkg/cortex/modules.go index 24e4fa4438a..f71eeceb64c 100644 --- a/pkg/cortex/modules.go +++ b/pkg/cortex/modules.go @@ -10,10 +10,6 @@ import ( "github.com/prometheus/prometheus/promql" httpgrpc_server "github.com/weaveworks/common/httpgrpc/server" "github.com/weaveworks/common/server" -<<<<<<< HEAD -======= - "google.golang.org/grpc" ->>>>>>> 1ce95f0cd... all modules registered using API "github.com/cortexproject/cortex/pkg/alertmanager" "github.com/cortexproject/cortex/pkg/api" @@ -97,16 +93,6 @@ func (m *ModuleName) UnmarshalYAML(unmarshal func(interface{}) error) error { func (t *Cortex) initAPI(cfg *Config) (services.Service, error) { cfg.API.ServerPrefix = cfg.Server.PathPrefix - if !cfg.AuthEnabled { - cfg.Server.GRPCMiddleware = []grpc.UnaryServerInterceptor{ - fakeGRPCAuthUniaryMiddleware, - } - cfg.Server.GRPCStreamMiddleware = []grpc.StreamServerInterceptor{ - fakeGRPCAuthStreamMiddleware, - } - t.httpAuthMiddleware = fakeHTTPAuthMiddleware - } - a, err := api.New(cfg.API, t.server, util.Logger) if err != nil { return nil, err From bd0306ececd27a1b4254c9eed11eb53e318c0e78 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 19:11:32 -0400 Subject: [PATCH 07/28] revert gorilla mux to current version Signed-off-by: Jacob Lisi --- vendor/github.com/gorilla/mux/.travis.yml | 24 +++++++ .../github.com/gorilla/mux/ISSUE_TEMPLATE.md | 11 +++ vendor/github.com/gorilla/mux/README.md | 69 ------------------- vendor/github.com/gorilla/mux/doc.go | 2 +- vendor/github.com/gorilla/mux/middleware.go | 61 ++++++++-------- vendor/github.com/gorilla/mux/regexp.go | 37 +++------- vendor/modules.txt | 2 +- 7 files changed, 74 insertions(+), 132 deletions(-) create mode 100644 vendor/github.com/gorilla/mux/.travis.yml create mode 100644 vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml new file mode 100644 index 00000000000..d003ad922f3 --- /dev/null +++ b/vendor/github.com/gorilla/mux/.travis.yml @@ -0,0 +1,24 @@ +language: go + + +matrix: + include: + - go: 1.7.x + - go: 1.8.x + - go: 1.9.x + - go: 1.10.x + - go: 1.11.x + - go: 1.x + env: LATEST=true + - go: tip + allow_failures: + - go: tip + +install: + - # Skip + +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - if [[ "$LATEST" = true ]]; then go vet .; fi + - go test -v -race ./... diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md new file mode 100644 index 00000000000..232be82e47a --- /dev/null +++ b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md @@ -0,0 +1,11 @@ +**What version of Go are you running?** (Paste the output of `go version`) + + +**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`) + + +**Describe your problem** (and what you have tried so far) + + +**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it) + diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md index 92e422eed7a..c661599ab21 100644 --- a/vendor/github.com/gorilla/mux/README.md +++ b/vendor/github.com/gorilla/mux/README.md @@ -2,7 +2,6 @@ [![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) [![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) -[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux) [![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) ![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) @@ -30,7 +29,6 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv * [Walking Routes](#walking-routes) * [Graceful Shutdown](#graceful-shutdown) * [Middleware](#middleware) -* [Handling CORS Requests](#handling-cors-requests) * [Testing Handlers](#testing-handlers) * [Full Example](#full-example) @@ -493,73 +491,6 @@ r.Use(amw.Middleware) Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it. -### Handling CORS Requests - -[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header. - -* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin` -* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route -* If you do not specify any methods, then: -> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers. - -Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers: - -```go -package main - -import ( - "net/http" - "github.com/gorilla/mux" -) - -func main() { - r := mux.NewRouter() - - // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers - r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions) - r.Use(mux.CORSMethodMiddleware(r)) - - http.ListenAndServe(":8080", r) -} - -func fooHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") - if r.Method == http.MethodOptions { - return - } - - w.Write([]byte("foo")) -} -``` - -And an request to `/foo` using something like: - -```bash -curl localhost:8080/foo -v -``` - -Would look like: - -```bash -* Trying ::1... -* TCP_NODELAY set -* Connected to localhost (::1) port 8080 (#0) -> GET /foo HTTP/1.1 -> Host: localhost:8080 -> User-Agent: curl/7.59.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS -< Access-Control-Allow-Origin: * -< Date: Fri, 28 Jun 2019 20:13:30 GMT -< Content-Length: 3 -< Content-Type: text/plain; charset=utf-8 -< -* Connection #0 to host localhost left intact -foo -``` - ### Testing Handlers Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_. diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go index bd5a38b55d8..38957deead3 100644 --- a/vendor/github.com/gorilla/mux/doc.go +++ b/vendor/github.com/gorilla/mux/doc.go @@ -295,7 +295,7 @@ A more complex authentication middleware, which maps session token to users, cou r := mux.NewRouter() r.HandleFunc("/", handler) - amw := authenticationMiddleware{tokenUsers: make(map[string]string)} + amw := authenticationMiddleware{} amw.Populate() r.Use(amw.Middleware) diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go index cf2b26dc037..ceb812cee28 100644 --- a/vendor/github.com/gorilla/mux/middleware.go +++ b/vendor/github.com/gorilla/mux/middleware.go @@ -32,48 +32,41 @@ func (r *Router) useInterface(mw middleware) { r.middlewares = append(r.middlewares, mw) } -// CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header -// on requests for routes that have an OPTIONS method matcher to all the method matchers on -// the route. Routes that do not explicitly handle OPTIONS requests will not be processed -// by the middleware. See examples for usage. +// CORSMethodMiddleware sets the Access-Control-Allow-Methods response header +// on a request, by matching routes based only on paths. It also handles +// OPTIONS requests, by settings Access-Control-Allow-Methods, and then +// returning without calling the next http handler. func CORSMethodMiddleware(r *Router) MiddlewareFunc { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - allMethods, err := getAllMethodsForRoute(r, req) - if err == nil { - for _, v := range allMethods { - if v == http.MethodOptions { - w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ",")) - } - } - } + var allMethods []string - next.ServeHTTP(w, req) - }) - } -} + err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { + for _, m := range route.matchers { + if _, ok := m.(*routeRegexp); ok { + if m.Match(req, &RouteMatch{}) { + methods, err := route.GetMethods() + if err != nil { + return err + } -// getAllMethodsForRoute returns all the methods from method matchers matching a given -// request. -func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) { - var allMethods []string - - err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { - for _, m := range route.matchers { - if _, ok := m.(*routeRegexp); ok { - if m.Match(req, &RouteMatch{}) { - methods, err := route.GetMethods() - if err != nil { - return err + allMethods = append(allMethods, methods...) + } + break } + } + return nil + }) + + if err == nil { + w.Header().Set("Access-Control-Allow-Methods", strings.Join(append(allMethods, "OPTIONS"), ",")) - allMethods = append(allMethods, methods...) + if req.Method == "OPTIONS" { + return } - break } - } - return nil - }) - return allMethods, err + next.ServeHTTP(w, req) + }) + } } diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go index ac1abcd473e..f2528867563 100644 --- a/vendor/github.com/gorilla/mux/regexp.go +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -113,13 +113,6 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro if typ != regexpTypePrefix { pattern.WriteByte('$') } - - var wildcardHostPort bool - if typ == regexpTypeHost { - if !strings.Contains(pattern.String(), ":") { - wildcardHostPort = true - } - } reverse.WriteString(raw) if endSlash { reverse.WriteByte('/') @@ -138,14 +131,13 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro // Done! return &routeRegexp{ - template: template, - regexpType: typ, - options: options, - regexp: reg, - reverse: reverse.String(), - varsN: varsN, - varsR: varsR, - wildcardHostPort: wildcardHostPort, + template: template, + regexpType: typ, + options: options, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, }, nil } @@ -166,22 +158,11 @@ type routeRegexp struct { varsN []string // Variable regexps (validators). varsR []*regexp.Regexp - // Wildcard host-port (no strict port match in hostname) - wildcardHostPort bool } // Match matches the regexp against the URL host or path. func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { - if r.regexpType == regexpTypeHost { - host := getHost(req) - if r.wildcardHostPort { - // Don't be strict on the port match - if i := strings.Index(host, ":"); i != -1 { - host = host[:i] - } - } - return r.regexp.MatchString(host) - } else { + if r.regexpType != regexpTypeHost { if r.regexpType == regexpTypeQuery { return r.matchQueryString(req) } @@ -191,6 +172,8 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { } return r.regexp.MatchString(path) } + + return r.regexp.MatchString(getHost(req)) } // url builds a URL part using the given values. diff --git a/vendor/modules.txt b/vendor/modules.txt index 51684b27d70..c23bc172ac7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -249,7 +249,7 @@ github.com/gophercloud/gophercloud/openstack/identity/v2/tokens github.com/gophercloud/gophercloud/openstack/identity/v3/tokens github.com/gophercloud/gophercloud/openstack/utils github.com/gophercloud/gophercloud/pagination -# github.com/gorilla/mux v1.7.3 +# github.com/gorilla/mux v1.7.1 github.com/gorilla/mux # github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket From b859d39e79b0d089373aadc93ee8394e9cfddfff Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 19:12:52 -0400 Subject: [PATCH 08/28] remove unneeded vendored import Signed-off-by: Jacob Lisi --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index 804c9a8df72..45b9359676e 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,6 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= From 2627e70522936aeed49ae9f921c7bf8a1863b522 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 19:13:40 -0400 Subject: [PATCH 09/28] revert go.sum Signed-off-by: Jacob Lisi --- go.sum | 6 ------ 1 file changed, 6 deletions(-) diff --git a/go.sum b/go.sum index 45b9359676e..e33fcfc2759 100644 --- a/go.sum +++ b/go.sum @@ -141,7 +141,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190531201743-edce55837238 h1:uNljlOxtOHrPnRoPPx+JanqjAGZpNiqAGVBfGskd/pg= @@ -511,8 +510,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.0.0/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -532,9 +529,7 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743 h1:143Bb8f8DuGWck/xpNUOckBVYfFbBTnLevfRZ1aVVqo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.0 h1:fAazJekOWnfBeQYwk9jEgIWWKmBxq4ev3WfsAnezgc4= github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -708,7 +703,6 @@ github.com/prometheus/prometheus v1.8.2-0.20200213233353-b90be6f32a33 h1:HBYrMJj github.com/prometheus/prometheus v1.8.2-0.20200213233353-b90be6f32a33/go.mod h1:fkIPPkuZnkXyopYHmXPxf9rgiPkVgZCN8w9o8+UgBlY= github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1 h1:+kGqA4dNN5hn7WwvKdzHl0rdN5AEkbNZd0VjRltAiZg= github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= From 322942a76cc8d287b1376d5834856041246c4c28 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 19:24:23 -0400 Subject: [PATCH 10/28] remove unused field Signed-off-by: Jacob Lisi --- pkg/cortex/cortex.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/cortex/cortex.go b/pkg/cortex/cortex.go index 1c81bc7ecc9..35742557911 100644 --- a/pkg/cortex/cortex.go +++ b/pkg/cortex/cortex.go @@ -182,8 +182,7 @@ func (c *Config) Validate(log log.Logger) error { // Cortex is the root datastructure for Cortex. type Cortex struct { - target ModuleName - httpAuthMiddleware middleware.Interface + target ModuleName // set during initialization serviceMap map[ModuleName]services.Service From cd2d2e536ceb7c4c44766e9fcfe1e9a89ff4848c Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 31 Mar 2020 19:25:12 -0400 Subject: [PATCH 11/28] update docs Signed-off-by: Jacob Lisi --- docs/configuration/config-file-reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index 0c68fb87978..00805047792 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -62,6 +62,15 @@ Where default_value is the value to use if the environment variable is undefined # CLI flag: -http.prefix [http_prefix: | default = "/api/prom"] +api: + # Base path for data storage. + # CLI flag: -http.alertmanager-http-prefix + [alertmanager_http_prefix: | default = "/alertmanager"] + + # Base path for data storage. + # CLI flag: -http.prometheus-http-prefix + [prometheus_http_prefix: | default = "/prometheus"] + # The server_config configures the HTTP and gRPC server of the launched # service(s). [server: ] From e34b4c3637c1d6489a94abef37bc9156125aa668 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 14:58:09 -0400 Subject: [PATCH 12/28] ensure legacy prefix is propagated to API module Signed-off-by: Jacob Lisi --- pkg/cortex/modules.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cortex/modules.go b/pkg/cortex/modules.go index f71eeceb64c..ee976fd607e 100644 --- a/pkg/cortex/modules.go +++ b/pkg/cortex/modules.go @@ -92,6 +92,7 @@ func (m *ModuleName) UnmarshalYAML(unmarshal func(interface{}) error) error { func (t *Cortex) initAPI(cfg *Config) (services.Service, error) { cfg.API.ServerPrefix = cfg.Server.PathPrefix + cfg.API.LegacyHTTPPrefix = cfg.HTTPPrefix a, err := api.New(cfg.API, t.server, util.Logger) if err != nil { From 2da693d3ffab591644f0a0ba2ad18e5a968df34e Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 14:58:49 -0400 Subject: [PATCH 13/28] goimports for handlers.go Signed-off-by: Jacob Lisi --- pkg/api/handlers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/api/handlers.go b/pkg/api/handlers.go index 40d630a4189..33401613b0c 100644 --- a/pkg/api/handlers.go +++ b/pkg/api/handlers.go @@ -3,9 +3,10 @@ package api import ( "net/http" - "github.com/cortexproject/cortex/pkg/util" "github.com/go-kit/kit/log/level" "gopkg.in/yaml.v2" + + "github.com/cortexproject/cortex/pkg/util" ) // TODO: Update this content to be a template that is dynamic based on how Cortex is run. From 27dfd7d2d1063e7a01e89f7b1df0ebc139e865e0 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 17:03:15 -0400 Subject: [PATCH 14/28] ensure prom wrapped with fakeAddr Signed-off-by: Jacob Lisi --- pkg/api/api.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index f1909b3fb77..834ac0725f4 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -97,13 +97,14 @@ func (a *API) registerRoute(path string, handler http.Handler, auth bool, method // Register the route under the prometheus component path as well as the provided legacy // path func (a *API) registerPrometheusRoute(path string, handler http.Handler, methods ...string) { + handler = fakeRemoteAddr(handler) level.Debug(a.logger).Log("msg", "api: registering prometheus route", "methods", strings.Join(methods, ","), "path", path) a.registerRoute(a.cfg.LegacyHTTPPrefix+path, handler, true, methods...) if len(methods) == 0 { - a.prometheusRouter.Path(path).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) + a.prometheusRouter.Path(path).Handler(a.authMiddleware.Wrap(handler)) return } - a.prometheusRouter.Path(path).Methods(methods...).Handler(fakeRemoteAddr(a.authMiddleware.Wrap(handler))) + a.prometheusRouter.Path(path).Methods(methods...).Handler(a.authMiddleware.Wrap(handler)) } // Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. From 6b913e5d529f3191b5bb1393c997797dee20c4c5 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 17:19:07 -0400 Subject: [PATCH 15/28] fix prefix for promrouter Signed-off-by: Jacob Lisi --- pkg/api/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 834ac0725f4..d0f0a82f4c1 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -246,7 +246,7 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine &v1.PrometheusVersion{}, ) - promRouter := route.New().WithPrefix(a.cfg.ServerPrefix + a.cfg.PrometheusHTTPPrefix + "/api/v1") + promRouter := route.New() api.Register(promRouter) a.registerPrometheusRoute("/api/v1/read", querier.RemoteReadHandler(queryable)) From 817b88bfea31492348a30584e1db2037d9604a70 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 17:38:16 -0400 Subject: [PATCH 16/28] use single util function for route registration Signed-off-by: Jacob Lisi --- pkg/api/api.go | 89 +++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index d0f0a82f4c1..70574d193da 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -67,11 +67,10 @@ func New(cfg Config, s *server.Server, logger log.Logger) (*API, error) { s.HTTP.UseEncodedPath() api := &API{ - cfg: cfg, - authMiddleware: cfg.HTTPAuthMiddleware, - prometheusRouter: s.HTTP.PathPrefix(cfg.PrometheusHTTPPrefix).Subrouter(), - server: s, - logger: logger, + cfg: cfg, + authMiddleware: cfg.HTTPAuthMiddleware, + server: s, + logger: logger, } // If no authentication middleware is present in the config, use the middlewar @@ -94,19 +93,6 @@ func (a *API) registerRoute(path string, handler http.Handler, auth bool, method a.server.HTTP.Path(path).Methods(methods...).Handler(handler) } -// Register the route under the prometheus component path as well as the provided legacy -// path -func (a *API) registerPrometheusRoute(path string, handler http.Handler, methods ...string) { - handler = fakeRemoteAddr(handler) - level.Debug(a.logger).Log("msg", "api: registering prometheus route", "methods", strings.Join(methods, ","), "path", path) - a.registerRoute(a.cfg.LegacyHTTPPrefix+path, handler, true, methods...) - if len(methods) == 0 { - a.prometheusRouter.Path(path).Handler(a.authMiddleware.Wrap(handler)) - return - } - a.prometheusRouter.Path(path).Methods(methods...).Handler(a.authMiddleware.Wrap(handler)) -} - // Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. // Requests to Querier sometimes doesn't have that (if they are fetched from Query-Frontend). // Prometheus uses this when logging queries to QueryLogger, but Cortex doesn't call engine.SetQueryLogger to set one. @@ -178,8 +164,12 @@ func (a *API) RegisterIngester(i *ingester.Ingester, pushConfig distributor.Conf func (a *API) RegisterPurger(store *purger.DeleteStore) { deleteRequestHandler := purger.NewDeleteRequestHandler(store) - a.registerPrometheusRoute("/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), "PUT", "POST") - a.registerPrometheusRoute("/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), true, "PUT", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") + + // Legacy Routes + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), true, "PUT", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") } // RegisterRuler registers routes associated with the Ruler service. If the @@ -188,8 +178,8 @@ func (a *API) RegisterRuler(r *ruler.Ruler, apiEnabled bool) { a.registerRoute("/ruler/ring", r, false) if apiEnabled { - a.registerPrometheusRoute("/api/v1/rules", http.HandlerFunc(r.PrometheusRules), "GET") - a.registerPrometheusRoute("/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/rules", http.HandlerFunc(r.PrometheusRules), true, "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), true, "GET") ruler.RegisterRulerServer(a.server.GRPC, r) @@ -200,6 +190,9 @@ func (a *API) RegisterRuler(r *ruler.Ruler, apiEnabled bool) { a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/rules", http.HandlerFunc(r.PrometheusRules), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules", http.HandlerFunc(r.ListRules), true, "GET") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") @@ -246,16 +239,17 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine &v1.PrometheusVersion{}, ) - promRouter := route.New() + promRouter := route.New().WithPrefix(a.cfg.ServerPrefix + a.cfg.PrometheusHTTPPrefix + "/api/v1") api.Register(promRouter) + promHandler := fakeRemoteAddr(promRouter) - a.registerPrometheusRoute("/api/v1/read", querier.RemoteReadHandler(queryable)) - a.registerPrometheusRoute("/api/v1/query", promRouter) - a.registerPrometheusRoute("/api/v1/query_range", promRouter) - a.registerPrometheusRoute("/api/v1/labels", promRouter) - a.registerPrometheusRoute("/api/v1/label/{name}/values", promRouter) - a.registerPrometheusRoute("/api/v1/series", promRouter) - a.registerPrometheusRoute("/api/v1/metadata", promRouter) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/read", querier.RemoteReadHandler(queryable), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query", promHandler, true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query_range", promHandler, true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/labels", promHandler, true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/label/{name}/values", promHandler, true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/series", promHandler, true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/metadata", promHandler, true) a.registerRoute("/api/v1/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) a.registerRoute("/api/v1/chunks", querier.ChunksHandler(queryable), true) @@ -263,6 +257,18 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine // Legacy Routes a.registerRoute("/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) a.registerRoute("/chunks", querier.ChunksHandler(queryable), true) + + legacyPromRouter := route.New().WithPrefix(a.cfg.ServerPrefix + a.cfg.LegacyHTTPPrefix + "/api/v1") + api.Register(legacyPromRouter) + legacyPromHandler := fakeRemoteAddr(legacyPromRouter) + + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/read", querier.RemoteReadHandler(queryable), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query", legacyPromHandler, true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query_range", legacyPromHandler, true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/labels", legacyPromHandler, true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/label/{name}/values", legacyPromHandler, true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/series", legacyPromHandler, true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/metadata", legacyPromHandler, true) } // RegisterQueryFrontend registers the Prometheus routes supported by the @@ -274,13 +280,22 @@ func (a *API) RegisterQueryFrontend(f *frontend.Frontend) { // Previously the frontend handled all calls to the provided prefix. Instead explicit // routing is used since it will be required to enable the frontend to be run as part // of a single binary in the future. - a.registerPrometheusRoute("/api/v1/read", f.Handler()) - a.registerPrometheusRoute("/api/v1/query", f.Handler()) - a.registerPrometheusRoute("/api/v1/query_range", f.Handler()) - a.registerPrometheusRoute("/api/v1/labels", f.Handler()) - a.registerPrometheusRoute("/api/v1/label/{name}/values", f.Handler()) - a.registerPrometheusRoute("/api/v1/series", f.Handler()) - a.registerPrometheusRoute("/api/v1/metadata", f.Handler()) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/read", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query_range", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/labels", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/label/{name}/values", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/series", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/metadata", f.Handler(), true) + + // Register Legacy Routers + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/read", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query_range", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/labels", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/label/{name}/values", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/series", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/metadata", f.Handler(), true) } // RegisterServiceMapHandler registers the Cortex structs service handler From c6fe85007fcec17f986e5d5ad69262718d19f94f Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 17:42:28 -0400 Subject: [PATCH 17/28] ensure correct methods are used for prometheus API calls Signed-off-by: Jacob Lisi --- pkg/api/api.go | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 70574d193da..3a95817b7d1 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -243,13 +243,13 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine api.Register(promRouter) promHandler := fakeRemoteAddr(promRouter) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/read", querier.RemoteReadHandler(queryable), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query", promHandler, true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query_range", promHandler, true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/labels", promHandler, true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/label/{name}/values", promHandler, true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/series", promHandler, true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/metadata", promHandler, true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/read", querier.RemoteReadHandler(queryable), true, "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query", promHandler, true, "GET", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query_range", promHandler, true, "GET", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/labels", promHandler, true, "GET", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/label/{name}/values", promHandler, true, "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/series", promHandler, true, "GET", "POST", "DELETE") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/metadata", promHandler, true, "GET") a.registerRoute("/api/v1/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) a.registerRoute("/api/v1/chunks", querier.ChunksHandler(queryable), true) @@ -262,13 +262,13 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine api.Register(legacyPromRouter) legacyPromHandler := fakeRemoteAddr(legacyPromRouter) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/read", querier.RemoteReadHandler(queryable), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query", legacyPromHandler, true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query_range", legacyPromHandler, true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/labels", legacyPromHandler, true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/label/{name}/values", legacyPromHandler, true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/series", legacyPromHandler, true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/metadata", legacyPromHandler, true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/read", querier.RemoteReadHandler(queryable), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query", legacyPromHandler, true, "GET", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query_range", legacyPromHandler, true, "GET", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/labels", legacyPromHandler, true, "GET", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/label/{name}/values", legacyPromHandler, true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/series", legacyPromHandler, true, "GET", "POST", "DELETE") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/metadata", legacyPromHandler, true, "GET") } // RegisterQueryFrontend registers the Prometheus routes supported by the @@ -280,22 +280,22 @@ func (a *API) RegisterQueryFrontend(f *frontend.Frontend) { // Previously the frontend handled all calls to the provided prefix. Instead explicit // routing is used since it will be required to enable the frontend to be run as part // of a single binary in the future. - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/read", f.Handler(), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query", f.Handler(), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query_range", f.Handler(), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/labels", f.Handler(), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/label/{name}/values", f.Handler(), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/series", f.Handler(), true) - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/metadata", f.Handler(), true) + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/read", f.Handler(), true, "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query", f.Handler(), true, "GET", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/query_range", f.Handler(), true, "GET", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/labels", f.Handler(), true, "GET", "POST") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/label/{name}/values", f.Handler(), true, "GET") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/series", f.Handler(), true, "GET", "POST", "DELETE") + a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/metadata", f.Handler(), true, "GET") // Register Legacy Routers - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/read", f.Handler(), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query", f.Handler(), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query_range", f.Handler(), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/labels", f.Handler(), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/label/{name}/values", f.Handler(), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/series", f.Handler(), true) - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/metadata", f.Handler(), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/read", f.Handler(), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query", f.Handler(), true, "GET", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/query_range", f.Handler(), true, "GET", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/labels", f.Handler(), true, "GET", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/label/{name}/values", f.Handler(), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/series", f.Handler(), true, "GET", "POST", "DELETE") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/metadata", f.Handler(), true, "GET") } // RegisterServiceMapHandler registers the Cortex structs service handler From 1da249e184c5caf111fb09234d5a0eb74945897d Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Wed, 1 Apr 2020 17:49:26 -0400 Subject: [PATCH 18/28] remove unused prometheuRouter Signed-off-by: Jacob Lisi --- pkg/api/api.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 3a95817b7d1..3977bb8c34d 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -9,7 +9,6 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/gorilla/mux" "github.com/prometheus/common/route" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/promql" @@ -55,11 +54,10 @@ func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { } type API struct { - cfg Config - authMiddleware middleware.Func - server *server.Server - prometheusRouter *mux.Router - logger log.Logger + cfg Config + authMiddleware middleware.Func + server *server.Server + logger log.Logger } func New(cfg Config, s *server.Server, logger log.Logger) (*API, error) { From 45790661a8ccf345807e14702865cbbd2ce9f805 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Mon, 6 Apr 2020 18:52:19 -0400 Subject: [PATCH 19/28] Update pkg/api/api.go Co-Authored-By: Marco Pracucci Signed-off-by: Jacob Lisi --- pkg/api/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 3977bb8c34d..68df0314d50 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -71,7 +71,7 @@ func New(cfg Config, s *server.Server, logger log.Logger) (*API, error) { logger: logger, } - // If no authentication middleware is present in the config, use the middlewar + // If no authentication middleware is present in the config, use the default authentication middleware. if cfg.HTTPAuthMiddleware == nil { api.authMiddleware = middleware.AuthenticateUser } From 1edcecba366d6194a7f200821ff93b6f89a725cf Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Mon, 6 Apr 2020 19:26:47 -0400 Subject: [PATCH 20/28] address straight forward PR feedback Signed-off-by: Jacob Lisi --- go.sum | 13 ++++++++ pkg/api/api.go | 46 +++++++++++++++++++++-------- pkg/api/handlers.go | 14 ++++----- pkg/distributor/distributor.go | 6 ++-- pkg/distributor/distributor_test.go | 4 +-- 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/go.sum b/go.sum index e33fcfc2759..baef3960932 100644 --- a/go.sum +++ b/go.sum @@ -102,6 +102,7 @@ github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQh github.com/armon/go-metrics v0.3.0 h1:B7AQgHi8QSEi4uHu7Sbsga+IJDU+CENgjxoo81vDUqU= github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -202,6 +203,7 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY= +github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= @@ -474,6 +476,7 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -529,8 +532,11 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743 h1:143Bb8f8DuGWck/xpNUOckBVYfFbBTnLevfRZ1aVVqo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.0 h1:fAazJekOWnfBeQYwk9jEgIWWKmBxq4ev3WfsAnezgc4= github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lovoo/gcloud-opentracing v0.3.0 h1:nAeKG70rIsog0TelcEtt6KU0Y1s5qXtsDLnHp0urPLU= github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -627,6 +633,7 @@ github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 h1:0R5 github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= @@ -798,9 +805,13 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= +go.elastic.co/apm v1.5.0 h1:arba7i+CVc36Jptww3R1ttW+O10ydvnBtidyd85DLpg= go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk= +go.elastic.co/apm/module/apmhttp v1.5.0 h1:sxntP97oENyWWi+6GAwXUo05oEpkwbiarZLqrzLRA4o= go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY= +go.elastic.co/apm/module/apmot v1.5.0 h1:rPyHRI6Ooqjwny67au6e2eIxLZshqd7bJfAUpdgOw/4= go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE= +go.elastic.co/fastjson v1.0.0 h1:ooXV/ABvf+tBul26jcVViPT3sBir0PvXgibYB1IQQzg= go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -822,6 +833,7 @@ go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/automaxprocs v1.2.0 h1:+RUihKM+nmYUoB9w0D0Ov5TJ2PpFO2FgenTxMJiZBZA= go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1103,6 +1115,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A= k8s.io/api v0.0.0-20190813020757-36bff7324fb7 h1:4uJOjRn9kWq4AqJRE8+qzmAy+lJd9rh8TY455dNef4U= diff --git a/pkg/api/api.go b/pkg/api/api.go index 68df0314d50..9711b3c670e 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -49,8 +49,8 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { // RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet with the set prefix. func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { - f.StringVar(&cfg.AlertmanagerHTTPPrefix, prefix+"http.alertmanager-http-prefix", "/alertmanager", "Base path for data storage.") - f.StringVar(&cfg.PrometheusHTTPPrefix, prefix+"http.prometheus-http-prefix", "/prometheus", "Base path for data storage.") + f.StringVar(&cfg.AlertmanagerHTTPPrefix, prefix+"http.alertmanager-http-prefix", "/alertmanager", "HTTP URL path under which the Alertmanager ui and api will be served.") + f.StringVar(&cfg.PrometheusHTTPPrefix, prefix+"http.prometheus-http-prefix", "/prometheus", "TTP URL path under which the Prometheus api will be served.") } type API struct { @@ -91,6 +91,18 @@ func (a *API) registerRoute(path string, handler http.Handler, auth bool, method a.server.HTTP.Path(path).Methods(methods...).Handler(handler) } +func (a *API) registerRoutesWithPrefix(path string, handler http.Handler, auth bool, methods ...string) { + level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "path", path, "auth", auth) + if auth { + handler = a.authMiddleware.Wrap(handler) + } + if len(methods) == 0 { + a.server.HTTP.Path(path).Handler(handler) + return + } + a.server.HTTP.PathPrefix(path).Methods(methods...).Handler(handler) +} + // Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. // Requests to Querier sometimes doesn't have that (if they are fetched from Query-Frontend). // Prometheus uses this when logging queries to QueryLogger, but Cortex doesn't call engine.SetQueryLogger to set one. @@ -109,17 +121,17 @@ func fakeRemoteAddr(handler http.Handler) http.Handler { // serve endpoints using the legacy http-prefix if it is not run as a single binary. func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager, target bool) { // Ensure this route is registered before the prefixed AM route - a.registerRoute("/multitenant-alertmanager/status", am.GetStatusHandler(), false) + a.registerRoute("/multitenant_alertmanager/status", am.GetStatusHandler(), false) // UI components lead to a large number of routes to support, utilize a path prefix instead - a.server.HTTP.PathPrefix(a.cfg.AlertmanagerHTTPPrefix).Handler(a.authMiddleware.Wrap(am)) + a.registerRoutesWithPrefix(a.cfg.AlertmanagerHTTPPrefix, am, true) level.Debug(a.logger).Log("msg", "api: registering alertmanager", "path_prefix", a.cfg.AlertmanagerHTTPPrefix) // If the target is Alertmanager, enable the legacy behaviour. Otherwise only enable // the component routed API. if target { a.registerRoute("/status", am.GetStatusHandler(), false) - a.server.HTTP.PathPrefix(a.cfg.LegacyHTTPPrefix).Handler(a.authMiddleware.Wrap(am)) + a.registerRoutesWithPrefix(a.cfg.LegacyHTTPPrefix, am, true) } } @@ -133,12 +145,12 @@ func (a *API) RegisterAPI(cfg interface{}) { func (a *API) RegisterDistributor(d *distributor.Distributor, pushConfig distributor.Config) { a.registerRoute("/api/v1/push", push.Handler(pushConfig, d.Push), true) a.registerRoute("/distributor/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false) - a.registerRoute("/distributor/ha-tracker", d.Replicas, false) + a.registerRoute("/distributor/ha_tracker", d.HATracker, false) // Legacy Routes a.registerRoute(a.cfg.LegacyHTTPPrefix+"/push", push.Handler(pushConfig, d.Push), true) a.registerRoute("/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false) - a.registerRoute("/ha-tracker", d.Replicas, false) + a.registerRoute("/ha-tracker", d.HATracker, false) } // RegisterIngester registers the ingesters HTTP and GRPC service @@ -166,8 +178,8 @@ func (a *API) RegisterPurger(store *purger.DeleteStore) { a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") // Legacy Routes - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), true, "PUT", "POST") - a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), true, "PUT", "POST") + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/admin/tsdb/delete_series", http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") } // RegisterRuler registers routes associated with the Ruler service. If the @@ -175,26 +187,31 @@ func (a *API) RegisterPurger(store *purger.DeleteStore) { func (a *API) RegisterRuler(r *ruler.Ruler, apiEnabled bool) { a.registerRoute("/ruler/ring", r, false) + // Legacy Ring Route + a.registerRoute("/ruler_ring", r, false) + if apiEnabled { + // Prometheus Rule API Routes a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/rules", http.HandlerFunc(r.PrometheusRules), true, "GET") a.registerRoute(a.cfg.PrometheusHTTPPrefix+"/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), true, "GET") ruler.RegisterRulerServer(a.server.GRPC, r) + // Ruler API Routes a.registerRoute("/api/v1/rules", http.HandlerFunc(r.ListRules), true, "GET") a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") - a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") a.registerRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") a.registerRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") + // Legacy Prometheus Rule API Routes a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/rules", http.HandlerFunc(r.PrometheusRules), true, "GET") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/api/v1/alerts", http.HandlerFunc(r.PrometheusAlerts), true, "GET") + // Legacy Ruler API Routes a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules", http.HandlerFunc(r.ListRules), true, "GET") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") - a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") a.registerRoute(a.cfg.LegacyHTTPPrefix+"/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") } @@ -202,6 +219,9 @@ func (a *API) RegisterRuler(r *ruler.Ruler, apiEnabled bool) { // // RegisterRing registers the ring UI page associated with the distributor for writes. func (a *API) RegisterRing(r *ring.Ring) { + a.registerRoute("/ingester/ring", r, false) + + // Legacy Route a.registerRoute("/ring", r, false) } @@ -253,8 +273,8 @@ func (a *API) RegisterQuerier(queryable storage.Queryable, engine *promql.Engine a.registerRoute("/api/v1/chunks", querier.ChunksHandler(queryable), true) // Legacy Routes - a.registerRoute("/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) - a.registerRoute("/chunks", querier.ChunksHandler(queryable), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true) + a.registerRoute(a.cfg.LegacyHTTPPrefix+"/chunks", querier.ChunksHandler(queryable), true) legacyPromRouter := route.New().WithPrefix(a.cfg.ServerPrefix + a.cfg.LegacyHTTPPrefix + "/api/v1") api.Register(legacyPromRouter) diff --git a/pkg/api/handlers.go b/pkg/api/handlers.go index 33401613b0c..ffbcad8e6b4 100644 --- a/pkg/api/handlers.go +++ b/pkg/api/handlers.go @@ -21,21 +21,21 @@ const indexPageContent = `

Cortex

Admin Endpoints:

Dangerous:

` diff --git a/pkg/distributor/distributor.go b/pkg/distributor/distributor.go index ec4e3b815d0..faaef40d543 100644 --- a/pkg/distributor/distributor.go +++ b/pkg/distributor/distributor.go @@ -126,7 +126,7 @@ type Distributor struct { distributorsRing *ring.Lifecycler // For handling HA replicas. - Replicas *haTracker + HATracker *haTracker // Per-user rate limiter. ingestionRateLimiter *limiter.RateLimiter @@ -220,7 +220,7 @@ func New(cfg Config, clientConfig ingester_client.Config, limits *validation.Ove distributorsRing: distributorsRing, limits: limits, ingestionRateLimiter: limiter.NewRateLimiter(ingestionRateStrategy, 10*time.Second), - Replicas: replicas, + HATracker: replicas, } subservices = append(subservices, d.ingesterPool) @@ -319,7 +319,7 @@ func (d *Distributor) checkSample(ctx context.Context, userID, cluster, replica // At this point we know we have both HA labels, we should lookup // the cluster/instance here to see if we want to accept this sample. - err := d.Replicas.checkReplica(ctx, userID, cluster, replica) + err := d.HATracker.checkReplica(ctx, userID, cluster, replica) // checkReplica should only have returned an error if there was a real error talking to Consul, or if the replica labels don't match. if err != nil { // Don't accept the sample. return false, err diff --git a/pkg/distributor/distributor_test.go b/pkg/distributor/distributor_test.go index c9a54487fe2..37c63215a8f 100644 --- a/pkg/distributor/distributor_test.go +++ b/pkg/distributor/distributor_test.go @@ -319,12 +319,12 @@ func TestDistributor_PushHAInstances(t *testing.T) { }) require.NoError(t, err) require.NoError(t, services.StartAndAwaitRunning(context.Background(), r)) - d.Replicas = r + d.HATracker = r } userID, err := user.ExtractOrgID(ctx) assert.NoError(t, err) - err = d.Replicas.checkReplica(ctx, userID, tc.cluster, tc.acceptedReplica) + err = d.HATracker.checkReplica(ctx, userID, tc.cluster, tc.acceptedReplica) assert.NoError(t, err) request := makeWriteRequestHA(tc.samples, tc.testReplica, tc.cluster) From 4dabad253e6485ff8586a70e32a50bf254ef92be Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Mon, 6 Apr 2020 19:35:17 -0400 Subject: [PATCH 21/28] remove ingester specific health check Signed-off-by: Jacob Lisi --- pkg/api/api.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 9711b3c670e..a55202608ec 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -16,7 +16,6 @@ import ( v1 "github.com/prometheus/prometheus/web/api/v1" "github.com/weaveworks/common/middleware" "github.com/weaveworks/common/server" - "google.golang.org/grpc/health/grpc_health_v1" "github.com/cortexproject/cortex/pkg/alertmanager" "github.com/cortexproject/cortex/pkg/chunk/purger" @@ -156,7 +155,6 @@ func (a *API) RegisterDistributor(d *distributor.Distributor, pushConfig distrib // RegisterIngester registers the ingesters HTTP and GRPC service func (a *API) RegisterIngester(i *ingester.Ingester, pushConfig distributor.Config) { client.RegisterIngesterServer(a.server.GRPC, i) - grpc_health_v1.RegisterHealthServer(a.server.GRPC, i) a.registerRoute("/ingester/flush", http.HandlerFunc(i.FlushHandler), false) a.registerRoute("/ingester/shutdown", http.HandlerFunc(i.ShutdownHandler), false) From 42c0be85b025458b242b38fb18647d0c053f6860 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 11:08:11 -0400 Subject: [PATCH 22/28] fix import error introduced in rebase Signed-off-by: Jacob Lisi --- pkg/cortex/cortex.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/cortex/cortex.go b/pkg/cortex/cortex.go index 35742557911..0bbf288a364 100644 --- a/pkg/cortex/cortex.go +++ b/pkg/cortex/cortex.go @@ -8,11 +8,6 @@ import ( "net/http" "os" - "google.golang.org/grpc/health/grpc_health_v1" - - "github.com/cortexproject/cortex/pkg/configs" - "github.com/cortexproject/cortex/pkg/storegateway" - "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/pkg/errors" @@ -20,6 +15,7 @@ import ( "github.com/weaveworks/common/middleware" "github.com/weaveworks/common/server" "google.golang.org/grpc" + "google.golang.org/grpc/health/grpc_health_v1" "gopkg.in/yaml.v2" "github.com/cortexproject/cortex/pkg/alertmanager" From b4752dab871735502bcbc0ae3554a27503705a28 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 12:12:20 -0400 Subject: [PATCH 23/28] fix alertmanager routing and update docs Signed-off-by: Jacob Lisi --- docs/configuration/config-file-reference.md | 4 ++-- pkg/api/api.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index 00805047792..790b9a42f5b 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -63,11 +63,11 @@ Where default_value is the value to use if the environment variable is undefined [http_prefix: | default = "/api/prom"] api: - # Base path for data storage. + # HTTP URL path under which the Alertmanager ui and api will be served. # CLI flag: -http.alertmanager-http-prefix [alertmanager_http_prefix: | default = "/alertmanager"] - # Base path for data storage. + # TTP URL path under which the Prometheus api will be served. # CLI flag: -http.prometheus-http-prefix [prometheus_http_prefix: | default = "/prometheus"] diff --git a/pkg/api/api.go b/pkg/api/api.go index a55202608ec..5e88394ebc0 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -90,16 +90,16 @@ func (a *API) registerRoute(path string, handler http.Handler, auth bool, method a.server.HTTP.Path(path).Methods(methods...).Handler(handler) } -func (a *API) registerRoutesWithPrefix(path string, handler http.Handler, auth bool, methods ...string) { - level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "path", path, "auth", auth) +func (a *API) registerRoutesWithPrefix(prefix string, handler http.Handler, auth bool, methods ...string) { + level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "prefix", prefix, "auth", auth) if auth { handler = a.authMiddleware.Wrap(handler) } if len(methods) == 0 { - a.server.HTTP.Path(path).Handler(handler) + a.server.HTTP.PathPrefix(prefix).Handler(handler) return } - a.server.HTTP.PathPrefix(path).Methods(methods...).Handler(handler) + a.server.HTTP.PathPrefix(prefix).Methods(methods...).Handler(handler) } // Latest Prometheus requires r.RemoteAddr to be set to addr:port, otherwise it reject the request. From 26a512618dec2a21a96f534f8570e75ef62cb5a4 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 12:24:15 -0400 Subject: [PATCH 24/28] fix typo Signed-off-by: Jacob Lisi --- pkg/api/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 5e88394ebc0..e98b49e750f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -49,7 +49,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { // RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet with the set prefix. func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { f.StringVar(&cfg.AlertmanagerHTTPPrefix, prefix+"http.alertmanager-http-prefix", "/alertmanager", "HTTP URL path under which the Alertmanager ui and api will be served.") - f.StringVar(&cfg.PrometheusHTTPPrefix, prefix+"http.prometheus-http-prefix", "/prometheus", "TTP URL path under which the Prometheus api will be served.") + f.StringVar(&cfg.PrometheusHTTPPrefix, prefix+"http.prometheus-http-prefix", "/prometheus", "HTTP URL path under which the Prometheus api will be served.") } type API struct { From 941d2e3268578c84c0a5136a5cc7a00c1afac746 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 12:45:32 -0400 Subject: [PATCH 25/28] update docs to fix typo Signed-off-by: Jacob Lisi --- CHANGELOG.md | 3 +++ docs/configuration/config-file-reference.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c89ac904fd..ec9ca313583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## master / unreleased +* [CHANGE] Added v1 API routes documented in #2327. #2372 + * Added `-http.alertmanager-http-prefix` and `http.prometheus-http-prefix` flags. + * Updated the index hosted at the root prefix to point to the updated routes. * [CHANGE] The metrics `cortex_distributor_ingester_appends_total` and `distributor_ingester_append_failures_total` now includes a `type` label to differentiate between `samples` and `metadata`. #2336 * [CHANGE] Experimental TSDB: renamed blocks meta fetcher metrics: #2375 * `cortex_querier_bucket_store_blocks_meta_syncs_total` > `cortex_querier_blocks_meta_syncs_total` diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index 790b9a42f5b..9531116e164 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -67,7 +67,7 @@ api: # CLI flag: -http.alertmanager-http-prefix [alertmanager_http_prefix: | default = "/alertmanager"] - # TTP URL path under which the Prometheus api will be served. + # HTTP URL path under which the Prometheus api will be served. # CLI flag: -http.prometheus-http-prefix [prometheus_http_prefix: | default = "/prometheus"] From 6ea96bb0281861565b4525fc3fc4f87ee9868c2e Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 12:57:24 -0400 Subject: [PATCH 26/28] add bugfix to changelog Signed-off-by: Jacob Lisi --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec9ca313583..7ae252fe619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * [ENHANCEMENT] Experimental TSDB: Added `cortex_querier_blocks_meta_synced`, which reflects current state of synced blocks over all tenants. #2392 * [ENHANCEMENT] Added `cortex_distributor_latest_seen_sample_timestamp_seconds` metric to see how far behind Prometheus servers are in sending data. #2371 * [ENHANCEMENT] FIFO cache to support eviction based on memory usage. The `-.fifocache.size` CLI flag has been renamed to `-.fifocache.max-size-items` as well as its YAML config option `size` renamed to `max_size_items`. Added `-.fifocache.max-size-bytes` CLI flag and YAML config option `max_size_bytes` to specify memory limit of the cache. #2319 +* [BUGFIX] Fixes #2411, Ensure requests are properly routed to the prometheus api embedded in the query if `server.path-prefix` is set. #2372 * [BUGFIX] Experimental TSDB: fixed chunk data corruption when querying back series using the experimental blocks storage. #2400 * [BUGFIX] Cassandra Storage: Fix endpoint TLS host verification. #2109 * [BUGFIX] Experimental TSDB: fixed response status code from `422` to `500` when an error occurs while iterating chunks with the experimental blocks storage. #2402 From f09a2af5e0a074ae537ade6275f230f50a86acb7 Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 12:58:21 -0400 Subject: [PATCH 27/28] add http prefix config to changelog Signed-off-by: Jacob Lisi --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae252fe619..7ea6ac123f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * [CHANGE] Added v1 API routes documented in #2327. #2372 * Added `-http.alertmanager-http-prefix` and `http.prometheus-http-prefix` flags. * Updated the index hosted at the root prefix to point to the updated routes. + * Legacy routes hardcoded with the `/api/prom` prefix now respect the `http.prefix` flag. * [CHANGE] The metrics `cortex_distributor_ingester_appends_total` and `distributor_ingester_append_failures_total` now includes a `type` label to differentiate between `samples` and `metadata`. #2336 * [CHANGE] Experimental TSDB: renamed blocks meta fetcher metrics: #2375 * `cortex_querier_bucket_store_blocks_meta_syncs_total` > `cortex_querier_blocks_meta_syncs_total` From b3d9c2e22968b280c19021790a6825bd0642139b Mon Sep 17 00:00:00 2001 From: Jacob Lisi Date: Tue, 7 Apr 2020 15:37:34 -0400 Subject: [PATCH 28/28] clarify changelog Signed-off-by: Jacob Lisi --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea6ac123f3..f33ca0d9106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,10 @@ ## master / unreleased * [CHANGE] Added v1 API routes documented in #2327. #2372 - * Added `-http.alertmanager-http-prefix` and `http.prometheus-http-prefix` flags. + * Added `-http.alertmanager-http-prefix` flag which allows the configuration of the path where the Alertmanager API and UI can be reached. The default is set to `/alertmanager`. + * Added `-http.prometheus-http-prefix` flag which allows the configuration of the path where the Prometheus API and UI can be reached. The default is set to `/prometheus`. * Updated the index hosted at the root prefix to point to the updated routes. - * Legacy routes hardcoded with the `/api/prom` prefix now respect the `http.prefix` flag. + * Legacy routes hardcoded with the `/api/prom` prefix now respect the `-http.prefix` flag. * [CHANGE] The metrics `cortex_distributor_ingester_appends_total` and `distributor_ingester_append_failures_total` now includes a `type` label to differentiate between `samples` and `metadata`. #2336 * [CHANGE] Experimental TSDB: renamed blocks meta fetcher metrics: #2375 * `cortex_querier_bucket_store_blocks_meta_syncs_total` > `cortex_querier_blocks_meta_syncs_total` @@ -17,7 +18,7 @@ * [ENHANCEMENT] Experimental TSDB: Added `cortex_querier_blocks_meta_synced`, which reflects current state of synced blocks over all tenants. #2392 * [ENHANCEMENT] Added `cortex_distributor_latest_seen_sample_timestamp_seconds` metric to see how far behind Prometheus servers are in sending data. #2371 * [ENHANCEMENT] FIFO cache to support eviction based on memory usage. The `-.fifocache.size` CLI flag has been renamed to `-.fifocache.max-size-items` as well as its YAML config option `size` renamed to `max_size_items`. Added `-.fifocache.max-size-bytes` CLI flag and YAML config option `max_size_bytes` to specify memory limit of the cache. #2319 -* [BUGFIX] Fixes #2411, Ensure requests are properly routed to the prometheus api embedded in the query if `server.path-prefix` is set. #2372 +* [BUGFIX] Fixes #2411, Ensure requests are properly routed to the prometheus api embedded in the query if `-server.path-prefix` is set. #2372 * [BUGFIX] Experimental TSDB: fixed chunk data corruption when querying back series using the experimental blocks storage. #2400 * [BUGFIX] Cassandra Storage: Fix endpoint TLS host verification. #2109 * [BUGFIX] Experimental TSDB: fixed response status code from `422` to `500` when an error occurs while iterating chunks with the experimental blocks storage. #2402