Ejemplo n.º 1
0
// New initializes a new web Handler.
func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *PrometheusStatus, o *Options) *Handler {
	router := route.New()

	h := &Handler{
		router:      router,
		listenErrCh: make(chan error),
		quitCh:      make(chan struct{}),
		reloadCh:    make(chan struct{}),
		options:     o,
		statusInfo:  status,

		ruleManager: rm,
		queryEngine: qe,
		storage:     st,

		apiV1: &v1.API{
			QueryEngine: qe,
			Storage:     st,
		},
		apiLegacy: &legacy.API{
			QueryEngine: qe,
			Storage:     st,
			Now:         model.Now,
		},
	}

	if o.ExternalURL.Path != "" {
		// If the prefix is missing for the root path, prepend it.
		router.Get("/", func(w http.ResponseWriter, r *http.Request) {
			http.Redirect(w, r, o.ExternalURL.Path, http.StatusFound)
		})
		router = router.WithPrefix(o.ExternalURL.Path)
	}

	instrf := prometheus.InstrumentHandlerFunc
	instrh := prometheus.InstrumentHandler

	router.Get("/", instrf("status", h.status))
	router.Get("/alerts", instrf("alerts", h.alerts))
	router.Get("/graph", instrf("graph", h.graph))
	router.Get("/version", instrf("version", h.version))

	router.Get("/heap", instrf("heap", dumpHeap))

	router.Get("/federate", instrf("federate", h.federation))
	router.Get(o.MetricsPath, prometheus.Handler().ServeHTTP)

	h.apiLegacy.Register(router.WithPrefix("/api"))
	h.apiV1.Register(router.WithPrefix("/api/v1"))

	router.Get("/consoles/*filepath", instrf("consoles", h.consoles))

	if o.UseLocalAssets {
		router.Get("/static/*filepath", instrf("static", route.FileServe("web/blob/static")))
	} else {
		router.Get("/static/*filepath", instrh("static", blob.Handler{}))
	}

	if o.UserAssetsPath != "" {
		router.Get("/user/*filepath", instrf("user", route.FileServe(o.UserAssetsPath)))
	}

	if o.EnableQuit {
		router.Post("/-/quit", h.quit)
	}

	router.Post("/-/reload", h.reload)

	router.Get("/debug/*subpath", http.DefaultServeMux.ServeHTTP)
	router.Post("/debug/*subpath", http.DefaultServeMux.ServeHTTP)

	return h
}
Ejemplo n.º 2
0
func TestQuery(t *testing.T) {
	scenarios := []struct {
		// URL query string.
		queryStr string
		// Expected HTTP response status code.
		status int
		// Regex to match against response body.
		bodyRe string
	}{
		{
			queryStr: "",
			status:   http.StatusOK,
			bodyRe:   `{"type":"error","value":"Parse error at char 1: no expression found in input","version":1}`,
		},
		{
			queryStr: "expr=testmetric",
			status:   http.StatusOK,
			bodyRe:   `{"type":"vector","value":\[\{"metric":{"__name__":"testmetric"},"value":"0","timestamp":\d+\.\d+}\],"version":1\}`,
		},
		{
			queryStr: "expr=testmetric&timestamp=" + testTimestamp.String(),
			status:   http.StatusOK,
			bodyRe:   `{"type":"vector","value":\[\{"metric":{"__name__":"testmetric"},"value":"0","timestamp":` + testTimestamp.String() + `}\],"version":1\}`,
		},
		{
			queryStr: "expr=testmetric&timestamp=" + testTimestamp.Add(-time.Hour).String(),
			status:   http.StatusOK,
			bodyRe:   `{"type":"vector","value":\[\],"version":1\}`,
		},
		{
			queryStr: "timestamp=invalid",
			status:   http.StatusBadRequest,
			bodyRe:   "invalid query timestamp",
		},
		{
			queryStr: "expr=(badexpression",
			status:   http.StatusOK,
			bodyRe:   `{"type":"error","value":"Parse error at char 15: unclosed left parenthesis","version":1}`,
		},
	}

	storage, closer := local.NewTestStorage(t, 1)
	defer closer.Close()
	storage.Append(&clientmodel.Sample{
		Metric: clientmodel.Metric{
			clientmodel.MetricNameLabel: "testmetric",
		},
		Timestamp: testTimestamp,
		Value:     0,
	})
	storage.WaitForIndexing()

	api := &API{
		Now:         testNow,
		Storage:     storage,
		QueryEngine: promql.NewEngine(storage, nil),
	}
	rtr := route.New()
	api.Register(rtr.WithPrefix("/api"))

	server := httptest.NewServer(rtr)
	defer server.Close()

	for i, s := range scenarios {
		// Do query.
		resp, err := http.Get(server.URL + "/api/query?" + s.queryStr)
		if err != nil {
			t.Fatalf("%d. Error querying API: %s", i, err)
		}

		// Check status code.
		if resp.StatusCode != s.status {
			t.Fatalf("%d. Unexpected status code; got %d, want %d", i, resp.StatusCode, s.status)
		}

		// Check response headers.
		ct := resp.Header["Content-Type"]
		if len(ct) != 1 {
			t.Fatalf("%d. Unexpected number of 'Content-Type' headers; got %d, want 1", i, len(ct))
		}
		if ct[0] != "application/json" {
			t.Fatalf("%d. Unexpected 'Content-Type' header; got %s; want %s", i, ct[0], "application/json")
		}

		// Check body.
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatalf("%d. Error reading response body: %s", i, err)
		}
		re := regexp.MustCompile(s.bodyRe)
		if !re.Match(b) {
			t.Fatalf("%d. Body didn't match '%s'. Body: %s", i, s.bodyRe, string(b))
		}
	}
}