From 5b713911e3ece7252c981d7bf5eebb0bd7323585 Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Thu, 4 Jun 2015 18:24:04 +0200 Subject: [PATCH] web/api: enable running API legacy and v1 in parallel --- main.go | 13 ++++++++++--- web/api/{ => legacy}/api.go | 14 +++++++------- web/api/{ => legacy}/api_test.go | 6 +++--- web/api/{ => legacy}/query.go | 20 ++++++++++---------- web/api/{ => legacy}/query_test.go | 2 +- web/web.go | 18 +++++++++++------- 6 files changed, 42 insertions(+), 31 deletions(-) rename web/api/{ => legacy}/api.go (79%) rename web/api/{ => legacy}/api_test.go (98%) rename web/api/{ => legacy}/query.go (89%) rename web/api/{ => legacy}/query_test.go (99%) diff --git a/main.go b/main.go index c4b2d64b4..555e139d7 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,8 @@ import ( "github.com/prometheus/prometheus/storage/remote/influxdb" "github.com/prometheus/prometheus/storage/remote/opentsdb" "github.com/prometheus/prometheus/web" - "github.com/prometheus/prometheus/web/api" + "github.com/prometheus/prometheus/web/api/legacy" + "github.com/prometheus/prometheus/web/api/v1" ) const deletionBatchSize = 100 @@ -184,16 +185,22 @@ func NewPrometheus() *prometheus { PathPrefix: *pathPrefix, } - metricsService := &api.MetricsService{ + apiLegacy := &legacy.API{ Now: clientmodel.Now, Storage: memStorage, QueryEngine: queryEngine, } + apiv1 := &v1.API{ + Storage: memStorage, + QueryEngine: queryEngine, + } + webService := web.NewWebService(&web.WebServiceOptions{ PathPrefix: *pathPrefix, StatusHandler: prometheusStatus, - MetricsHandler: metricsService, + APILegacy: apiLegacy, + APIv1: apiv1, ConsolesHandler: consolesHandler, AlertsHandler: alertsHandler, GraphsHandler: graphsHandler, diff --git a/web/api/api.go b/web/api/legacy/api.go similarity index 79% rename from web/api/api.go rename to web/api/legacy/api.go index dab2691bf..e8b97cd8a 100644 --- a/web/api/api.go +++ b/web/api/legacy/api.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package api +package legacy import ( "net/http" @@ -26,18 +26,18 @@ import ( "github.com/prometheus/prometheus/util/route" ) -// MetricsService manages the /api HTTP endpoint. -type MetricsService struct { +// API manages the /api HTTP endpoint. +type API struct { Now func() clientmodel.Timestamp Storage local.Storage QueryEngine *promql.Engine } // RegisterHandler registers the handler for the various endpoints below /api. -func (msrv *MetricsService) RegisterHandler(router *route.Router) { - router.Get("/query", handle("query", msrv.Query)) - router.Get("/query_range", handle("query_range", msrv.QueryRange)) - router.Get("/metrics", handle("metrics", msrv.Metrics)) +func (api *API) Register(router *route.Router) { + router.Get("/query", handle("query", api.Query)) + router.Get("/query_range", handle("query_range", api.QueryRange)) + router.Get("/metrics", handle("metrics", api.Metrics)) } func handle(name string, f http.HandlerFunc) http.HandlerFunc { diff --git a/web/api/api_test.go b/web/api/legacy/api_test.go similarity index 98% rename from web/api/api_test.go rename to web/api/legacy/api_test.go index b1971b1aa..bb7658725 100644 --- a/web/api/api_test.go +++ b/web/api/legacy/api_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package api +package legacy import ( "io/ioutil" @@ -93,13 +93,13 @@ func TestQuery(t *testing.T) { }) storage.WaitForIndexing() - api := MetricsService{ + api := &API{ Now: testNow, Storage: storage, QueryEngine: promql.NewEngine(storage), } rtr := route.New() - api.RegisterHandler(rtr.WithPrefix("/api")) + api.Register(rtr.WithPrefix("/api")) server := httptest.NewServer(rtr) defer server.Close() diff --git a/web/api/query.go b/web/api/legacy/query.go similarity index 89% rename from web/api/query.go rename to web/api/legacy/query.go index 128981b66..e1db462f9 100644 --- a/web/api/query.go +++ b/web/api/legacy/query.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package api +package legacy import ( "encoding/json" @@ -63,20 +63,20 @@ func parseDuration(d string) (time.Duration, error) { } // Query handles the /api/query endpoint. -func (serv MetricsService) Query(w http.ResponseWriter, r *http.Request) { +func (api *API) Query(w http.ResponseWriter, r *http.Request) { setAccessControlHeaders(w) w.Header().Set("Content-Type", "application/json") params := httputil.GetQueryParams(r) expr := params.Get("expr") - timestamp, err := parseTimestampOrNow(params.Get("timestamp"), serv.Now()) + timestamp, err := parseTimestampOrNow(params.Get("timestamp"), api.Now()) if err != nil { httpJSONError(w, fmt.Errorf("invalid query timestamp %s", err), http.StatusBadRequest) return } - query, err := serv.QueryEngine.NewInstantQuery(expr, timestamp) + query, err := api.QueryEngine.NewInstantQuery(expr, timestamp) if err != nil { httpJSONError(w, err, http.StatusOK) return @@ -92,7 +92,7 @@ func (serv MetricsService) Query(w http.ResponseWriter, r *http.Request) { } // QueryRange handles the /api/query_range endpoint. -func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) { +func (api *API) QueryRange(w http.ResponseWriter, r *http.Request) { setAccessControlHeaders(w) w.Header().Set("Content-Type", "application/json") @@ -111,7 +111,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) { return } - end, err := parseTimestampOrNow(params.Get("end"), serv.Now()) + end, err := parseTimestampOrNow(params.Get("end"), api.Now()) if err != nil { httpJSONError(w, fmt.Errorf("invalid query timestamp: %s", err), http.StatusBadRequest) return @@ -121,7 +121,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) { // the current time as the end time. Instead, the "end" parameter should // simply be omitted or set to an empty string for that case. if end == 0 { - end = serv.Now() + end = api.Now() } // For safety, limit the number of returned points per timeseries. @@ -136,7 +136,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) { end = end.Add(-time.Duration(end.UnixNano() % int64(step))) start := end.Add(-duration) - query, err := serv.QueryEngine.NewRangeQuery(expr, start, end, step) + query, err := api.QueryEngine.NewRangeQuery(expr, start, end, step) if err != nil { httpJSONError(w, err, http.StatusOK) return @@ -152,11 +152,11 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) { } // Metrics handles the /api/metrics endpoint. -func (serv MetricsService) Metrics(w http.ResponseWriter, r *http.Request) { +func (api *API) Metrics(w http.ResponseWriter, r *http.Request) { setAccessControlHeaders(w) w.Header().Set("Content-Type", "application/json") - metricNames := serv.Storage.LabelValuesForLabelName(clientmodel.MetricNameLabel) + metricNames := api.Storage.LabelValuesForLabelName(clientmodel.MetricNameLabel) sort.Sort(metricNames) resultBytes, err := json.Marshal(metricNames) if err != nil { diff --git a/web/api/query_test.go b/web/api/legacy/query_test.go similarity index 99% rename from web/api/query_test.go rename to web/api/legacy/query_test.go index 8ee334e58..d6336c28e 100644 --- a/web/api/query_test.go +++ b/web/api/legacy/query_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package api +package legacy import ( "testing" diff --git a/web/web.go b/web/web.go index 63e015062..146a0a807 100644 --- a/web/web.go +++ b/web/web.go @@ -26,13 +26,14 @@ import ( pprof_runtime "runtime/pprof" + clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/log" + + "github.com/prometheus/prometheus/web/api/legacy" + "github.com/prometheus/prometheus/web/api/v1" + "github.com/prometheus/prometheus/util/route" - - clientmodel "github.com/prometheus/client_golang/model" - - "github.com/prometheus/prometheus/web/api" "github.com/prometheus/prometheus/web/blob" ) @@ -57,7 +58,8 @@ type WebService struct { type WebServiceOptions struct { PathPrefix string StatusHandler *PrometheusStatusHandler - MetricsHandler *api.MetricsService + APILegacy *legacy.API + APIv1 *v1.API AlertsHandler *AlertsHandler ConsolesHandler *ConsolesHandler GraphsHandler *GraphsHandler @@ -75,7 +77,7 @@ func NewWebService(o *WebServiceOptions) *WebService { if o.PathPrefix != "" { // If the prefix is missing for the root path, append it. router.Get("/", func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, o.PathPrefix, 301) + http.Redirect(w, r, o.PathPrefix, 302) }) router = router.WithPrefix(o.PathPrefix) } @@ -89,7 +91,9 @@ func NewWebService(o *WebServiceOptions) *WebService { router.Get(*metricsPath, prometheus.Handler().ServeHTTP) - o.MetricsHandler.RegisterHandler(router.WithPrefix("/api")) + o.APILegacy.Register(router.WithPrefix("/api")) + + o.APIv1.Register(router.WithPrefix("/api/v1")) router.Get("/consoles/*filepath", instr("consoles", o.ConsolesHandler))