7931: Fix format/type mismatch.
[arvados.git] / services / keepstore / handlers.go
index 5e85ed6216d69ba43deed5d744e6d6bb7c79c99f..258604ce59c50176a4d4473fd7dbf87c8d66de9c 100644 (file)
@@ -29,8 +29,8 @@ import (
 
        "github.com/gorilla/mux"
 
+       "git.curoverse.com/arvados.git/sdk/go/health"
        "git.curoverse.com/arvados.git/sdk/go/httpserver"
-       log "github.com/Sirupsen/logrus"
 )
 
 type router struct {
@@ -40,52 +40,63 @@ type router struct {
 
 // MakeRESTRouter returns a new router that forwards all Keep requests
 // to the appropriate handlers.
-func MakeRESTRouter() *router {
-       rest := mux.NewRouter()
-       rtr := &router{Router: rest}
+func MakeRESTRouter() http.Handler {
+       rtr := &router{Router: mux.NewRouter()}
 
-       rest.HandleFunc(
+       rtr.HandleFunc(
                `/{hash:[0-9a-f]{32}}`, GetBlockHandler).Methods("GET", "HEAD")
-       rest.HandleFunc(
+       rtr.HandleFunc(
                `/{hash:[0-9a-f]{32}}+{hints}`,
                GetBlockHandler).Methods("GET", "HEAD")
 
-       rest.HandleFunc(`/{hash:[0-9a-f]{32}}`, PutBlockHandler).Methods("PUT")
-       rest.HandleFunc(`/{hash:[0-9a-f]{32}}`, DeleteHandler).Methods("DELETE")
+       rtr.HandleFunc(`/{hash:[0-9a-f]{32}}`, PutBlockHandler).Methods("PUT")
+       rtr.HandleFunc(`/{hash:[0-9a-f]{32}}`, DeleteHandler).Methods("DELETE")
        // List all blocks stored here. Privileged client only.
-       rest.HandleFunc(`/index`, rtr.IndexHandler).Methods("GET", "HEAD")
+       rtr.HandleFunc(`/index`, rtr.IndexHandler).Methods("GET", "HEAD")
        // List blocks stored here whose hash has the given prefix.
        // Privileged client only.
-       rest.HandleFunc(`/index/{prefix:[0-9a-f]{0,32}}`, rtr.IndexHandler).Methods("GET", "HEAD")
+       rtr.HandleFunc(`/index/{prefix:[0-9a-f]{0,32}}`, rtr.IndexHandler).Methods("GET", "HEAD")
 
        // Internals/debugging info (runtime.MemStats)
-       rest.HandleFunc(`/debug.json`, rtr.DebugHandler).Methods("GET", "HEAD")
+       rtr.HandleFunc(`/debug.json`, rtr.DebugHandler).Methods("GET", "HEAD")
 
        // List volumes: path, device number, bytes used/avail.
-       rest.HandleFunc(`/status.json`, rtr.StatusHandler).Methods("GET", "HEAD")
+       rtr.HandleFunc(`/status.json`, rtr.StatusHandler).Methods("GET", "HEAD")
 
        // List mounts: UUID, readonly, tier, device ID, ...
-       rest.HandleFunc(`/mounts`, rtr.MountsHandler).Methods("GET")
-       rest.HandleFunc(`/mounts/{uuid}/blocks`, rtr.IndexHandler).Methods("GET")
-       rest.HandleFunc(`/mounts/{uuid}/blocks/`, rtr.IndexHandler).Methods("GET")
+       rtr.HandleFunc(`/mounts`, rtr.MountsHandler).Methods("GET")
+       rtr.HandleFunc(`/mounts/{uuid}/blocks`, rtr.IndexHandler).Methods("GET")
+       rtr.HandleFunc(`/mounts/{uuid}/blocks/`, rtr.IndexHandler).Methods("GET")
 
        // Replace the current pull queue.
-       rest.HandleFunc(`/pull`, PullHandler).Methods("PUT")
+       rtr.HandleFunc(`/pull`, PullHandler).Methods("PUT")
 
        // Replace the current trash queue.
-       rest.HandleFunc(`/trash`, TrashHandler).Methods("PUT")
+       rtr.HandleFunc(`/trash`, TrashHandler).Methods("PUT")
 
        // Untrash moves blocks from trash back into store
-       rest.HandleFunc(`/untrash/{hash:[0-9a-f]{32}}`, UntrashHandler).Methods("PUT")
+       rtr.HandleFunc(`/untrash/{hash:[0-9a-f]{32}}`, UntrashHandler).Methods("PUT")
 
-       // Health check ping
-       rest.HandleFunc(`/_health/ping`, HealthCheckPingHandler).Methods("GET")
+       rtr.Handle("/_health/{check}", &health.Handler{
+               Token:  theConfig.ManagementToken,
+               Prefix: "/_health/",
+       }).Methods("GET")
 
        // Any request which does not match any of these routes gets
        // 400 Bad Request.
-       rest.NotFoundHandler = http.HandlerFunc(BadRequestHandler)
+       rtr.NotFoundHandler = http.HandlerFunc(BadRequestHandler)
 
-       return rtr
+       theConfig.metrics.setup()
+
+       rtr.limiter = httpserver.NewRequestLimiter(theConfig.MaxRequests, rtr)
+
+       mux := http.NewServeMux()
+       mux.Handle("/", theConfig.metrics.Instrument(
+               httpserver.AddRequestIDs(httpserver.LogRequests(rtr.limiter))))
+       mux.HandleFunc("/metrics.json", theConfig.metrics.exportJSON)
+       mux.Handle("/metrics", theConfig.metrics.exportProm)
+
+       return mux
 }
 
 // BadRequestHandler is a HandleFunc to address bad requests.
@@ -288,7 +299,7 @@ func (rtr *router) MountsHandler(resp http.ResponseWriter, req *http.Request) {
 
 // PoolStatus struct
 type PoolStatus struct {
-       Alloc uint64 `json:"BytesAllocated"`
+       Alloc uint64 `json:"BytesAllocatedCumulative"`
        Cap   int    `json:"BuffersMax"`
        Len   int    `json:"BuffersInUse"`
 }
@@ -308,6 +319,7 @@ type NodeStatus struct {
        TrashQueue      WorkQueueStatus
        RequestsCurrent int
        RequestsMax     int
+       Version         string
 }
 
 var st NodeStatus
@@ -343,6 +355,7 @@ func (rtr *router) StatusHandler(resp http.ResponseWriter, req *http.Request) {
 
 // populate the given NodeStatus struct with current values.
 func (rtr *router) readNodeStatus(st *NodeStatus) {
+       st.Version = version
        vols := KeepVM.AllReadable()
        if cap(st.Volumes) < len(vols) {
                st.Volumes = make([]*volumeStatusEnt, len(vols))
@@ -620,39 +633,6 @@ func UntrashHandler(resp http.ResponseWriter, req *http.Request) {
        }
 }
 
-var pingResponseOK = map[string]string{"health": "OK"}
-
-// HealthCheckPingHandler processes "GET /_health/ping" requests
-func HealthCheckPingHandler(resp http.ResponseWriter, req *http.Request) {
-       healthCheckDo(resp, req, pingResponseOK)
-}
-
-func healthCheckDo(resp http.ResponseWriter, req *http.Request, v interface{}) {
-       msg, code := healthCheckAuth(resp, req)
-       if msg != "" {
-               http.Error(resp, msg, code)
-               return
-       }
-
-       ok, err := json.Marshal(v)
-       if err != nil {
-               http.Error(resp, err.Error(), 500)
-       }
-
-       resp.Write(ok)
-}
-
-func healthCheckAuth(resp http.ResponseWriter, req *http.Request) (string, int) {
-       if theConfig.ManagementToken == "" {
-               return "disabled", http.StatusNotFound
-       } else if h := req.Header.Get("Authorization"); h == "" {
-               return "authorization required", http.StatusUnauthorized
-       } else if h != "Bearer "+theConfig.ManagementToken {
-               return "authorization error", http.StatusForbidden
-       }
-       return "", 0
-}
-
 // GetBlock and PutBlock implement lower-level code for handling
 // blocks by rooting through volumes connected to the local machine.
 // Once the handler has determined that system policy permits the