1package api 2 3import ( 4 "context" 5 "flag" 6 "net/http" 7 "path" 8 "strings" 9 "time" 10 11 "github.com/NYTimes/gziphandler" 12 "github.com/felixge/fgprof" 13 "github.com/go-kit/log" 14 "github.com/go-kit/log/level" 15 "github.com/prometheus/client_golang/prometheus" 16 "github.com/prometheus/prometheus/storage" 17 "github.com/weaveworks/common/middleware" 18 "github.com/weaveworks/common/server" 19 20 "github.com/cortexproject/cortex/pkg/alertmanager" 21 "github.com/cortexproject/cortex/pkg/alertmanager/alertmanagerpb" 22 "github.com/cortexproject/cortex/pkg/chunk/purger" 23 "github.com/cortexproject/cortex/pkg/compactor" 24 "github.com/cortexproject/cortex/pkg/cortexpb" 25 "github.com/cortexproject/cortex/pkg/distributor" 26 "github.com/cortexproject/cortex/pkg/distributor/distributorpb" 27 frontendv1 "github.com/cortexproject/cortex/pkg/frontend/v1" 28 "github.com/cortexproject/cortex/pkg/frontend/v1/frontendv1pb" 29 frontendv2 "github.com/cortexproject/cortex/pkg/frontend/v2" 30 "github.com/cortexproject/cortex/pkg/frontend/v2/frontendv2pb" 31 "github.com/cortexproject/cortex/pkg/ingester/client" 32 "github.com/cortexproject/cortex/pkg/querier" 33 "github.com/cortexproject/cortex/pkg/ring" 34 "github.com/cortexproject/cortex/pkg/ruler" 35 "github.com/cortexproject/cortex/pkg/scheduler" 36 "github.com/cortexproject/cortex/pkg/scheduler/schedulerpb" 37 "github.com/cortexproject/cortex/pkg/storegateway" 38 "github.com/cortexproject/cortex/pkg/storegateway/storegatewaypb" 39 "github.com/cortexproject/cortex/pkg/util/push" 40) 41 42// DistributorPushWrapper wraps around a push. It is similar to middleware.Interface. 43type DistributorPushWrapper func(next push.Func) push.Func 44type ConfigHandler func(actualCfg interface{}, defaultCfg interface{}) http.HandlerFunc 45 46type Config struct { 47 ResponseCompression bool `yaml:"response_compression_enabled"` 48 49 AlertmanagerHTTPPrefix string `yaml:"alertmanager_http_prefix"` 50 PrometheusHTTPPrefix string `yaml:"prometheus_http_prefix"` 51 52 // The following configs are injected by the upstream caller. 53 ServerPrefix string `yaml:"-"` 54 LegacyHTTPPrefix string `yaml:"-"` 55 HTTPAuthMiddleware middleware.Interface `yaml:"-"` 56 57 // This allows downstream projects to wrap the distributor push function 58 // and access the deserialized write requests before/after they are pushed. 59 DistributorPushWrapper DistributorPushWrapper `yaml:"-"` 60 61 // The CustomConfigHandler allows for providing a different handler for the 62 // `/config` endpoint. If this field is set _before_ the API module is 63 // initialized, the custom config handler will be used instead of 64 // DefaultConfigHandler. 65 CustomConfigHandler ConfigHandler `yaml:"-"` 66} 67 68// RegisterFlags adds the flags required to config this to the given FlagSet. 69func (cfg *Config) RegisterFlags(f *flag.FlagSet) { 70 f.BoolVar(&cfg.ResponseCompression, "api.response-compression-enabled", false, "Use GZIP compression for API responses. Some endpoints serve large YAML or JSON blobs which can benefit from compression.") 71 cfg.RegisterFlagsWithPrefix("", f) 72} 73 74// RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet with the set prefix. 75func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { 76 f.StringVar(&cfg.AlertmanagerHTTPPrefix, prefix+"http.alertmanager-http-prefix", "/alertmanager", "HTTP URL path under which the Alertmanager ui and api will be served.") 77 f.StringVar(&cfg.PrometheusHTTPPrefix, prefix+"http.prometheus-http-prefix", "/prometheus", "HTTP URL path under which the Prometheus api will be served.") 78} 79 80// Push either wraps the distributor push function as configured or returns the distributor push directly. 81func (cfg *Config) wrapDistributorPush(d *distributor.Distributor) push.Func { 82 if cfg.DistributorPushWrapper != nil { 83 return cfg.DistributorPushWrapper(d.Push) 84 } 85 86 return d.Push 87} 88 89type API struct { 90 AuthMiddleware middleware.Interface 91 92 cfg Config 93 server *server.Server 94 logger log.Logger 95 sourceIPs *middleware.SourceIPExtractor 96 indexPage *IndexPageContent 97} 98 99func New(cfg Config, serverCfg server.Config, s *server.Server, logger log.Logger) (*API, error) { 100 // Ensure the encoded path is used. Required for the rules API 101 s.HTTP.UseEncodedPath() 102 103 var sourceIPs *middleware.SourceIPExtractor 104 if serverCfg.LogSourceIPs { 105 var err error 106 sourceIPs, err = middleware.NewSourceIPs(serverCfg.LogSourceIPsHeader, serverCfg.LogSourceIPsRegex) 107 if err != nil { 108 // This should have already been caught in the Server creation 109 return nil, err 110 } 111 } 112 113 api := &API{ 114 cfg: cfg, 115 AuthMiddleware: cfg.HTTPAuthMiddleware, 116 server: s, 117 logger: logger, 118 sourceIPs: sourceIPs, 119 indexPage: newIndexPageContent(), 120 } 121 122 // If no authentication middleware is present in the config, use the default authentication middleware. 123 if cfg.HTTPAuthMiddleware == nil { 124 api.AuthMiddleware = middleware.AuthenticateUser 125 } 126 127 return api, nil 128} 129 130// RegisterRoute registers a single route enforcing HTTP methods. A single 131// route is expected to be specific about which HTTP methods are supported. 132func (a *API) RegisterRoute(path string, handler http.Handler, auth bool, method string, methods ...string) { 133 methods = append([]string{method}, methods...) 134 135 level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "path", path, "auth", auth) 136 137 if auth { 138 handler = a.AuthMiddleware.Wrap(handler) 139 } 140 141 if a.cfg.ResponseCompression { 142 handler = gziphandler.GzipHandler(handler) 143 } 144 145 if len(methods) == 0 { 146 a.server.HTTP.Path(path).Handler(handler) 147 return 148 } 149 a.server.HTTP.Path(path).Methods(methods...).Handler(handler) 150} 151 152func (a *API) RegisterRoutesWithPrefix(prefix string, handler http.Handler, auth bool, methods ...string) { 153 level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "prefix", prefix, "auth", auth) 154 if auth { 155 handler = a.AuthMiddleware.Wrap(handler) 156 } 157 158 if a.cfg.ResponseCompression { 159 handler = gziphandler.GzipHandler(handler) 160 } 161 162 if len(methods) == 0 { 163 a.server.HTTP.PathPrefix(prefix).Handler(handler) 164 return 165 } 166 a.server.HTTP.PathPrefix(prefix).Methods(methods...).Handler(handler) 167} 168 169// RegisterAlertmanager registers endpoints associated with the alertmanager. It will only 170// serve endpoints using the legacy http-prefix if it is not run as a single binary. 171func (a *API) RegisterAlertmanager(am *alertmanager.MultitenantAlertmanager, target, apiEnabled bool) { 172 alertmanagerpb.RegisterAlertmanagerServer(a.server.GRPC, am) 173 174 a.indexPage.AddLink(SectionAdminEndpoints, "/multitenant_alertmanager/status", "Alertmanager Status") 175 a.indexPage.AddLink(SectionAdminEndpoints, "/multitenant_alertmanager/ring", "Alertmanager Ring Status") 176 // Ensure this route is registered before the prefixed AM route 177 a.RegisterRoute("/multitenant_alertmanager/status", am.GetStatusHandler(), false, "GET") 178 a.RegisterRoute("/multitenant_alertmanager/configs", http.HandlerFunc(am.ListAllConfigs), false, "GET") 179 a.RegisterRoute("/multitenant_alertmanager/ring", http.HandlerFunc(am.RingHandler), false, "GET", "POST") 180 a.RegisterRoute("/multitenant_alertmanager/delete_tenant_config", http.HandlerFunc(am.DeleteUserConfig), true, "POST") 181 182 // UI components lead to a large number of routes to support, utilize a path prefix instead 183 a.RegisterRoutesWithPrefix(a.cfg.AlertmanagerHTTPPrefix, am, true) 184 level.Debug(a.logger).Log("msg", "api: registering alertmanager", "path_prefix", a.cfg.AlertmanagerHTTPPrefix) 185 186 // MultiTenant Alertmanager Experimental API routes 187 if apiEnabled { 188 a.RegisterRoute("/api/v1/alerts", http.HandlerFunc(am.GetUserConfig), true, "GET") 189 a.RegisterRoute("/api/v1/alerts", http.HandlerFunc(am.SetUserConfig), true, "POST") 190 a.RegisterRoute("/api/v1/alerts", http.HandlerFunc(am.DeleteUserConfig), true, "DELETE") 191 } 192 193 // If the target is Alertmanager, enable the legacy behaviour. Otherwise only enable 194 // the component routed API. 195 if target { 196 a.RegisterRoute("/status", am.GetStatusHandler(), false, "GET") 197 // WARNING: If LegacyHTTPPrefix is an empty string, any other paths added after this point will be 198 // silently ignored by the HTTP service. Therefore, this must be the last route to be configured. 199 a.RegisterRoutesWithPrefix(a.cfg.LegacyHTTPPrefix, am, true) 200 } 201} 202 203// RegisterAPI registers the standard endpoints associated with a running Cortex. 204func (a *API) RegisterAPI(httpPathPrefix string, actualCfg interface{}, defaultCfg interface{}) { 205 a.indexPage.AddLink(SectionAdminEndpoints, "/config", "Current Config (including the default values)") 206 a.indexPage.AddLink(SectionAdminEndpoints, "/config?mode=diff", "Current Config (show only values that differ from the defaults)") 207 208 a.RegisterRoute("/config", a.cfg.configHandler(actualCfg, defaultCfg), false, "GET") 209 a.RegisterRoute("/", indexHandler(httpPathPrefix, a.indexPage), false, "GET") 210 a.RegisterRoute("/debug/fgprof", fgprof.Handler(), false, "GET") 211} 212 213// RegisterRuntimeConfig registers the endpoints associates with the runtime configuration 214func (a *API) RegisterRuntimeConfig(runtimeConfigHandler http.HandlerFunc) { 215 a.indexPage.AddLink(SectionAdminEndpoints, "/runtime_config", "Current Runtime Config (incl. Overrides)") 216 a.indexPage.AddLink(SectionAdminEndpoints, "/runtime_config?mode=diff", "Current Runtime Config (show only values that differ from the defaults)") 217 218 a.RegisterRoute("/runtime_config", runtimeConfigHandler, false, "GET") 219} 220 221// RegisterDistributor registers the endpoints associated with the distributor. 222func (a *API) RegisterDistributor(d *distributor.Distributor, pushConfig distributor.Config) { 223 distributorpb.RegisterDistributorServer(a.server.GRPC, d) 224 225 a.RegisterRoute("/api/v1/push", push.Handler(pushConfig.MaxRecvMsgSize, a.sourceIPs, a.cfg.wrapDistributorPush(d)), true, "POST") 226 227 a.indexPage.AddLink(SectionAdminEndpoints, "/distributor/ring", "Distributor Ring Status") 228 a.indexPage.AddLink(SectionAdminEndpoints, "/distributor/all_user_stats", "Usage Statistics") 229 a.indexPage.AddLink(SectionAdminEndpoints, "/distributor/ha_tracker", "HA Tracking Status") 230 231 a.RegisterRoute("/distributor/ring", d, false, "GET", "POST") 232 a.RegisterRoute("/distributor/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false, "GET") 233 a.RegisterRoute("/distributor/ha_tracker", d.HATracker, false, "GET") 234 235 // Legacy Routes 236 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/push"), push.Handler(pushConfig.MaxRecvMsgSize, a.sourceIPs, a.cfg.wrapDistributorPush(d)), true, "POST") 237 a.RegisterRoute("/all_user_stats", http.HandlerFunc(d.AllUserStatsHandler), false, "GET") 238 a.RegisterRoute("/ha-tracker", d.HATracker, false, "GET") 239} 240 241// Ingester is defined as an interface to allow for alternative implementations 242// of ingesters to be passed into the API.RegisterIngester() method. 243type Ingester interface { 244 client.IngesterServer 245 FlushHandler(http.ResponseWriter, *http.Request) 246 ShutdownHandler(http.ResponseWriter, *http.Request) 247 Push(context.Context, *cortexpb.WriteRequest) (*cortexpb.WriteResponse, error) 248} 249 250// RegisterIngester registers the ingesters HTTP and GRPC service 251func (a *API) RegisterIngester(i Ingester, pushConfig distributor.Config) { 252 client.RegisterIngesterServer(a.server.GRPC, i) 253 254 a.indexPage.AddLink(SectionDangerous, "/ingester/flush", "Trigger a Flush of data from Ingester to storage") 255 a.indexPage.AddLink(SectionDangerous, "/ingester/shutdown", "Trigger Ingester Shutdown (Dangerous)") 256 a.RegisterRoute("/ingester/flush", http.HandlerFunc(i.FlushHandler), false, "GET", "POST") 257 a.RegisterRoute("/ingester/shutdown", http.HandlerFunc(i.ShutdownHandler), false, "GET", "POST") 258 a.RegisterRoute("/ingester/push", push.Handler(pushConfig.MaxRecvMsgSize, a.sourceIPs, i.Push), true, "POST") // For testing and debugging. 259 260 // Legacy Routes 261 a.RegisterRoute("/flush", http.HandlerFunc(i.FlushHandler), false, "GET", "POST") 262 a.RegisterRoute("/shutdown", http.HandlerFunc(i.ShutdownHandler), false, "GET", "POST") 263 a.RegisterRoute("/push", push.Handler(pushConfig.MaxRecvMsgSize, a.sourceIPs, i.Push), true, "POST") // For testing and debugging. 264} 265 266// RegisterChunksPurger registers the endpoints associated with the Purger/DeleteStore. They do not exactly 267// match the Prometheus API but mirror it closely enough to justify their routing under the Prometheus 268// component/ 269func (a *API) RegisterChunksPurger(store *purger.DeleteStore, deleteRequestCancelPeriod time.Duration) { 270 deleteRequestHandler := purger.NewDeleteRequestHandler(store, deleteRequestCancelPeriod, prometheus.DefaultRegisterer) 271 272 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/admin/tsdb/delete_series"), http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), true, "PUT", "POST") 273 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/admin/tsdb/delete_series"), http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") 274 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/admin/tsdb/cancel_delete_request"), http.HandlerFunc(deleteRequestHandler.CancelDeleteRequestHandler), true, "PUT", "POST") 275 276 // Legacy Routes 277 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/admin/tsdb/delete_series"), http.HandlerFunc(deleteRequestHandler.AddDeleteRequestHandler), true, "PUT", "POST") 278 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/admin/tsdb/delete_series"), http.HandlerFunc(deleteRequestHandler.GetAllDeleteRequestsHandler), true, "GET") 279 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/admin/tsdb/cancel_delete_request"), http.HandlerFunc(deleteRequestHandler.CancelDeleteRequestHandler), true, "PUT", "POST") 280} 281 282func (a *API) RegisterTenantDeletion(api *purger.TenantDeletionAPI) { 283 a.RegisterRoute("/purger/delete_tenant", http.HandlerFunc(api.DeleteTenant), true, "POST") 284 a.RegisterRoute("/purger/delete_tenant_status", http.HandlerFunc(api.DeleteTenantStatus), true, "GET") 285} 286 287// RegisterRuler registers routes associated with the Ruler service. 288func (a *API) RegisterRuler(r *ruler.Ruler) { 289 a.indexPage.AddLink(SectionAdminEndpoints, "/ruler/ring", "Ruler Ring Status") 290 a.RegisterRoute("/ruler/ring", r, false, "GET", "POST") 291 292 // Administrative API, uses authentication to inform which user's configuration to delete. 293 a.RegisterRoute("/ruler/delete_tenant_config", http.HandlerFunc(r.DeleteTenantConfiguration), true, "POST") 294 295 // Legacy Ring Route 296 a.RegisterRoute("/ruler_ring", r, false, "GET", "POST") 297 298 // List all user rule groups 299 a.RegisterRoute("/ruler/rule_groups", http.HandlerFunc(r.ListAllRules), false, "GET") 300 301 ruler.RegisterRulerServer(a.server.GRPC, r) 302} 303 304// RegisterRulerAPI registers routes associated with the Ruler API 305func (a *API) RegisterRulerAPI(r *ruler.API) { 306 // Prometheus Rule API Routes 307 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/rules"), http.HandlerFunc(r.PrometheusRules), true, "GET") 308 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/alerts"), http.HandlerFunc(r.PrometheusAlerts), true, "GET") 309 310 // Ruler API Routes 311 a.RegisterRoute("/api/v1/rules", http.HandlerFunc(r.ListRules), true, "GET") 312 a.RegisterRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.ListRules), true, "GET") 313 a.RegisterRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.GetRuleGroup), true, "GET") 314 a.RegisterRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.CreateRuleGroup), true, "POST") 315 a.RegisterRoute("/api/v1/rules/{namespace}/{groupName}", http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") 316 a.RegisterRoute("/api/v1/rules/{namespace}", http.HandlerFunc(r.DeleteNamespace), true, "DELETE") 317 318 // Legacy Prometheus Rule API Routes 319 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/rules"), http.HandlerFunc(r.PrometheusRules), true, "GET") 320 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/alerts"), http.HandlerFunc(r.PrometheusAlerts), true, "GET") 321 322 // Legacy Ruler API Routes 323 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/rules"), http.HandlerFunc(r.ListRules), true, "GET") 324 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/rules/{namespace}"), http.HandlerFunc(r.ListRules), true, "GET") 325 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/rules/{namespace}/{groupName}"), http.HandlerFunc(r.GetRuleGroup), true, "GET") 326 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/rules/{namespace}"), http.HandlerFunc(r.CreateRuleGroup), true, "POST") 327 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/rules/{namespace}/{groupName}"), http.HandlerFunc(r.DeleteRuleGroup), true, "DELETE") 328 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/rules/{namespace}"), http.HandlerFunc(r.DeleteNamespace), true, "DELETE") 329} 330 331// RegisterRing registers the ring UI page associated with the distributor for writes. 332func (a *API) RegisterRing(r *ring.Ring) { 333 a.indexPage.AddLink(SectionAdminEndpoints, "/ingester/ring", "Ingester Ring Status") 334 a.RegisterRoute("/ingester/ring", r, false, "GET", "POST") 335 336 // Legacy Route 337 a.RegisterRoute("/ring", r, false, "GET", "POST") 338} 339 340// RegisterStoreGateway registers the ring UI page associated with the store-gateway. 341func (a *API) RegisterStoreGateway(s *storegateway.StoreGateway) { 342 storegatewaypb.RegisterStoreGatewayServer(a.server.GRPC, s) 343 344 a.indexPage.AddLink(SectionAdminEndpoints, "/store-gateway/ring", "Store Gateway Ring") 345 a.RegisterRoute("/store-gateway/ring", http.HandlerFunc(s.RingHandler), false, "GET", "POST") 346} 347 348// RegisterCompactor registers the ring UI page associated with the compactor. 349func (a *API) RegisterCompactor(c *compactor.Compactor) { 350 a.indexPage.AddLink(SectionAdminEndpoints, "/compactor/ring", "Compactor Ring Status") 351 a.RegisterRoute("/compactor/ring", http.HandlerFunc(c.RingHandler), false, "GET", "POST") 352} 353 354type Distributor interface { 355 querier.Distributor 356 UserStatsHandler(w http.ResponseWriter, r *http.Request) 357} 358 359// RegisterQueryable registers the the default routes associated with the querier 360// module. 361func (a *API) RegisterQueryable( 362 queryable storage.SampleAndChunkQueryable, 363 distributor Distributor, 364) { 365 // these routes are always registered to the default server 366 a.RegisterRoute("/api/v1/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true, "GET") 367 a.RegisterRoute("/api/v1/chunks", querier.ChunksHandler(queryable), true, "GET") 368 369 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/user_stats"), http.HandlerFunc(distributor.UserStatsHandler), true, "GET") 370 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/chunks"), querier.ChunksHandler(queryable), true, "GET") 371} 372 373// RegisterQueryAPI registers the Prometheus API routes with the provided handler. 374func (a *API) RegisterQueryAPI(handler http.Handler) { 375 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/read"), handler, true, "POST") 376 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/query"), handler, true, "GET", "POST") 377 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/query_range"), handler, true, "GET", "POST") 378 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/query_exemplars"), handler, true, "GET", "POST") 379 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/labels"), handler, true, "GET", "POST") 380 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/label/{name}/values"), handler, true, "GET") 381 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/series"), handler, true, "GET", "POST", "DELETE") 382 a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/metadata"), handler, true, "GET") 383 384 // Register Legacy Routers 385 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/read"), handler, true, "POST") 386 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/query"), handler, true, "GET", "POST") 387 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/query_range"), handler, true, "GET", "POST") 388 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/query_exemplars"), handler, true, "GET", "POST") 389 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/labels"), handler, true, "GET", "POST") 390 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/label/{name}/values"), handler, true, "GET") 391 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/series"), handler, true, "GET", "POST", "DELETE") 392 a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/metadata"), handler, true, "GET") 393} 394 395// RegisterQueryFrontend registers the Prometheus routes supported by the 396// Cortex querier service. Currently this can not be registered simultaneously 397// with the Querier. 398func (a *API) RegisterQueryFrontendHandler(h http.Handler) { 399 a.RegisterQueryAPI(h) 400} 401 402func (a *API) RegisterQueryFrontend1(f *frontendv1.Frontend) { 403 frontendv1pb.RegisterFrontendServer(a.server.GRPC, f) 404} 405 406func (a *API) RegisterQueryFrontend2(f *frontendv2.Frontend) { 407 frontendv2pb.RegisterFrontendForQuerierServer(a.server.GRPC, f) 408} 409 410func (a *API) RegisterQueryScheduler(f *scheduler.Scheduler) { 411 schedulerpb.RegisterSchedulerForFrontendServer(a.server.GRPC, f) 412 schedulerpb.RegisterSchedulerForQuerierServer(a.server.GRPC, f) 413} 414 415// RegisterServiceMapHandler registers the Cortex structs service handler 416// TODO: Refactor this code to be accomplished using the services.ServiceManager 417// or a future module manager #2291 418func (a *API) RegisterServiceMapHandler(handler http.Handler) { 419 a.indexPage.AddLink(SectionAdminEndpoints, "/services", "Service Status") 420 a.RegisterRoute("/services", handler, false, "GET") 421} 422 423func (a *API) RegisterMemberlistKV(handler http.Handler) { 424 a.indexPage.AddLink(SectionAdminEndpoints, "/memberlist", "Memberlist Status") 425 a.RegisterRoute("/memberlist", handler, false, "GET") 426} 427