web/api: enable running API legacy and v1 in parallel
This commit is contained in:
parent
ab9c98acac
commit
5b713911e3
13
main.go
13
main.go
|
@ -41,7 +41,8 @@ import (
|
||||||
"github.com/prometheus/prometheus/storage/remote/influxdb"
|
"github.com/prometheus/prometheus/storage/remote/influxdb"
|
||||||
"github.com/prometheus/prometheus/storage/remote/opentsdb"
|
"github.com/prometheus/prometheus/storage/remote/opentsdb"
|
||||||
"github.com/prometheus/prometheus/web"
|
"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
|
const deletionBatchSize = 100
|
||||||
|
@ -184,16 +185,22 @@ func NewPrometheus() *prometheus {
|
||||||
PathPrefix: *pathPrefix,
|
PathPrefix: *pathPrefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsService := &api.MetricsService{
|
apiLegacy := &legacy.API{
|
||||||
Now: clientmodel.Now,
|
Now: clientmodel.Now,
|
||||||
Storage: memStorage,
|
Storage: memStorage,
|
||||||
QueryEngine: queryEngine,
|
QueryEngine: queryEngine,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiv1 := &v1.API{
|
||||||
|
Storage: memStorage,
|
||||||
|
QueryEngine: queryEngine,
|
||||||
|
}
|
||||||
|
|
||||||
webService := web.NewWebService(&web.WebServiceOptions{
|
webService := web.NewWebService(&web.WebServiceOptions{
|
||||||
PathPrefix: *pathPrefix,
|
PathPrefix: *pathPrefix,
|
||||||
StatusHandler: prometheusStatus,
|
StatusHandler: prometheusStatus,
|
||||||
MetricsHandler: metricsService,
|
APILegacy: apiLegacy,
|
||||||
|
APIv1: apiv1,
|
||||||
ConsolesHandler: consolesHandler,
|
ConsolesHandler: consolesHandler,
|
||||||
AlertsHandler: alertsHandler,
|
AlertsHandler: alertsHandler,
|
||||||
GraphsHandler: graphsHandler,
|
GraphsHandler: graphsHandler,
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package api
|
package legacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -26,18 +26,18 @@ import (
|
||||||
"github.com/prometheus/prometheus/util/route"
|
"github.com/prometheus/prometheus/util/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MetricsService manages the /api HTTP endpoint.
|
// API manages the /api HTTP endpoint.
|
||||||
type MetricsService struct {
|
type API struct {
|
||||||
Now func() clientmodel.Timestamp
|
Now func() clientmodel.Timestamp
|
||||||
Storage local.Storage
|
Storage local.Storage
|
||||||
QueryEngine *promql.Engine
|
QueryEngine *promql.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterHandler registers the handler for the various endpoints below /api.
|
// RegisterHandler registers the handler for the various endpoints below /api.
|
||||||
func (msrv *MetricsService) RegisterHandler(router *route.Router) {
|
func (api *API) Register(router *route.Router) {
|
||||||
router.Get("/query", handle("query", msrv.Query))
|
router.Get("/query", handle("query", api.Query))
|
||||||
router.Get("/query_range", handle("query_range", msrv.QueryRange))
|
router.Get("/query_range", handle("query_range", api.QueryRange))
|
||||||
router.Get("/metrics", handle("metrics", msrv.Metrics))
|
router.Get("/metrics", handle("metrics", api.Metrics))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle(name string, f http.HandlerFunc) http.HandlerFunc {
|
func handle(name string, f http.HandlerFunc) http.HandlerFunc {
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package api
|
package legacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -93,13 +93,13 @@ func TestQuery(t *testing.T) {
|
||||||
})
|
})
|
||||||
storage.WaitForIndexing()
|
storage.WaitForIndexing()
|
||||||
|
|
||||||
api := MetricsService{
|
api := &API{
|
||||||
Now: testNow,
|
Now: testNow,
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
QueryEngine: promql.NewEngine(storage),
|
QueryEngine: promql.NewEngine(storage),
|
||||||
}
|
}
|
||||||
rtr := route.New()
|
rtr := route.New()
|
||||||
api.RegisterHandler(rtr.WithPrefix("/api"))
|
api.Register(rtr.WithPrefix("/api"))
|
||||||
|
|
||||||
server := httptest.NewServer(rtr)
|
server := httptest.NewServer(rtr)
|
||||||
defer server.Close()
|
defer server.Close()
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package api
|
package legacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -63,20 +63,20 @@ func parseDuration(d string) (time.Duration, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query handles the /api/query endpoint.
|
// 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)
|
setAccessControlHeaders(w)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
params := httputil.GetQueryParams(r)
|
params := httputil.GetQueryParams(r)
|
||||||
expr := params.Get("expr")
|
expr := params.Get("expr")
|
||||||
|
|
||||||
timestamp, err := parseTimestampOrNow(params.Get("timestamp"), serv.Now())
|
timestamp, err := parseTimestampOrNow(params.Get("timestamp"), api.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpJSONError(w, fmt.Errorf("invalid query timestamp %s", err), http.StatusBadRequest)
|
httpJSONError(w, fmt.Errorf("invalid query timestamp %s", err), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
query, err := serv.QueryEngine.NewInstantQuery(expr, timestamp)
|
query, err := api.QueryEngine.NewInstantQuery(expr, timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpJSONError(w, err, http.StatusOK)
|
httpJSONError(w, err, http.StatusOK)
|
||||||
return
|
return
|
||||||
|
@ -92,7 +92,7 @@ func (serv MetricsService) Query(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRange handles the /api/query_range endpoint.
|
// 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)
|
setAccessControlHeaders(w)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
end, err := parseTimestampOrNow(params.Get("end"), serv.Now())
|
end, err := parseTimestampOrNow(params.Get("end"), api.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpJSONError(w, fmt.Errorf("invalid query timestamp: %s", err), http.StatusBadRequest)
|
httpJSONError(w, fmt.Errorf("invalid query timestamp: %s", err), http.StatusBadRequest)
|
||||||
return
|
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
|
// the current time as the end time. Instead, the "end" parameter should
|
||||||
// simply be omitted or set to an empty string for that case.
|
// simply be omitted or set to an empty string for that case.
|
||||||
if end == 0 {
|
if end == 0 {
|
||||||
end = serv.Now()
|
end = api.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
// For safety, limit the number of returned points per timeseries.
|
// 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)))
|
end = end.Add(-time.Duration(end.UnixNano() % int64(step)))
|
||||||
start := end.Add(-duration)
|
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 {
|
if err != nil {
|
||||||
httpJSONError(w, err, http.StatusOK)
|
httpJSONError(w, err, http.StatusOK)
|
||||||
return
|
return
|
||||||
|
@ -152,11 +152,11 @@ func (serv MetricsService) QueryRange(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metrics handles the /api/metrics endpoint.
|
// 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)
|
setAccessControlHeaders(w)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
metricNames := serv.Storage.LabelValuesForLabelName(clientmodel.MetricNameLabel)
|
metricNames := api.Storage.LabelValuesForLabelName(clientmodel.MetricNameLabel)
|
||||||
sort.Sort(metricNames)
|
sort.Sort(metricNames)
|
||||||
resultBytes, err := json.Marshal(metricNames)
|
resultBytes, err := json.Marshal(metricNames)
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package api
|
package legacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
18
web/web.go
18
web/web.go
|
@ -26,13 +26,14 @@ import (
|
||||||
|
|
||||||
pprof_runtime "runtime/pprof"
|
pprof_runtime "runtime/pprof"
|
||||||
|
|
||||||
|
clientmodel "github.com/prometheus/client_golang/model"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/log"
|
"github.com/prometheus/log"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/web/api/legacy"
|
||||||
|
"github.com/prometheus/prometheus/web/api/v1"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/util/route"
|
"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"
|
"github.com/prometheus/prometheus/web/blob"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,7 +58,8 @@ type WebService struct {
|
||||||
type WebServiceOptions struct {
|
type WebServiceOptions struct {
|
||||||
PathPrefix string
|
PathPrefix string
|
||||||
StatusHandler *PrometheusStatusHandler
|
StatusHandler *PrometheusStatusHandler
|
||||||
MetricsHandler *api.MetricsService
|
APILegacy *legacy.API
|
||||||
|
APIv1 *v1.API
|
||||||
AlertsHandler *AlertsHandler
|
AlertsHandler *AlertsHandler
|
||||||
ConsolesHandler *ConsolesHandler
|
ConsolesHandler *ConsolesHandler
|
||||||
GraphsHandler *GraphsHandler
|
GraphsHandler *GraphsHandler
|
||||||
|
@ -75,7 +77,7 @@ func NewWebService(o *WebServiceOptions) *WebService {
|
||||||
if o.PathPrefix != "" {
|
if o.PathPrefix != "" {
|
||||||
// If the prefix is missing for the root path, append it.
|
// If the prefix is missing for the root path, append it.
|
||||||
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
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)
|
router = router.WithPrefix(o.PathPrefix)
|
||||||
}
|
}
|
||||||
|
@ -89,7 +91,9 @@ func NewWebService(o *WebServiceOptions) *WebService {
|
||||||
|
|
||||||
router.Get(*metricsPath, prometheus.Handler().ServeHTTP)
|
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))
|
router.Get("/consoles/*filepath", instr("consoles", o.ConsolesHandler))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue