瀏覽代碼

Enable pprof/debug endpoints by default

Makes sure that debug endpoints are always available, which will aid in
debugging demon issues.

Wraps debug endpoints in the middleware chain so the can be blocked by
authz.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Brian Goff 8 年之前
父節點
當前提交
408c7ade70
共有 5 個文件被更改,包括 76 次插入65 次删除
  1. 0 46
      api/server/profiler.go
  2. 53 0
      api/server/router/debug/debug.go
  3. 13 0
      api/server/router/debug/debug_routes.go
  4. 9 16
      api/server/server.go
  5. 1 3
      cmd/dockerd/daemon.go

+ 0 - 46
api/server/profiler.go

@@ -1,46 +0,0 @@
-package server
-
-import (
-	"expvar"
-	"fmt"
-	"net/http"
-	"net/http/pprof"
-
-	"github.com/gorilla/mux"
-)
-
-const debugPathPrefix = "/debug/"
-
-func profilerSetup(mainRouter *mux.Router) {
-	var r = mainRouter.PathPrefix(debugPathPrefix).Subrouter()
-	r.HandleFunc("/vars", expVars)
-	r.HandleFunc("/pprof/", pprof.Index)
-	r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
-	r.HandleFunc("/pprof/profile", pprof.Profile)
-	r.HandleFunc("/pprof/symbol", pprof.Symbol)
-	r.HandleFunc("/pprof/trace", pprof.Trace)
-	r.HandleFunc("/pprof/{name}", handlePprof)
-}
-
-func handlePprof(w http.ResponseWriter, r *http.Request) {
-	var name string
-	if vars := mux.Vars(r); vars != nil {
-		name = vars["name"]
-	}
-	pprof.Handler(name).ServeHTTP(w, r)
-}
-
-// Replicated from expvar.go as not public.
-func expVars(w http.ResponseWriter, r *http.Request) {
-	first := true
-	w.Header().Set("Content-Type", "application/json; charset=utf-8")
-	fmt.Fprintln(w, "{")
-	expvar.Do(func(kv expvar.KeyValue) {
-		if !first {
-			fmt.Fprintln(w, ",")
-		}
-		first = false
-		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
-	})
-	fmt.Fprintln(w, "\n}")
-}

+ 53 - 0
api/server/router/debug/debug.go

@@ -0,0 +1,53 @@
+package debug
+
+import (
+	"expvar"
+	"net/http"
+	"net/http/pprof"
+
+	"github.com/docker/docker/api/server/httputils"
+	"github.com/docker/docker/api/server/router"
+	"golang.org/x/net/context"
+)
+
+// NewRouter creates a new debug router
+// The debug router holds endpoints for debug the daemon, such as those for pprof.
+func NewRouter() router.Router {
+	r := &debugRouter{}
+	r.initRoutes()
+	return r
+}
+
+type debugRouter struct {
+	routes []router.Route
+}
+
+func (r *debugRouter) initRoutes() {
+	r.routes = []router.Route{
+		router.NewGetRoute("/vars", frameworkAdaptHandler(expvar.Handler())),
+		router.NewGetRoute("/pprof/", frameworkAdaptHandlerFunc(pprof.Index)),
+		router.NewGetRoute("/pprof/cmdline", frameworkAdaptHandlerFunc(pprof.Cmdline)),
+		router.NewGetRoute("/pprof/profile", frameworkAdaptHandlerFunc(pprof.Profile)),
+		router.NewGetRoute("/pprof/symbol", frameworkAdaptHandlerFunc(pprof.Symbol)),
+		router.NewGetRoute("/pprof/trace", frameworkAdaptHandlerFunc(pprof.Trace)),
+		router.NewGetRoute("/pprof/{name}", handlePprof),
+	}
+}
+
+func (r *debugRouter) Routes() []router.Route {
+	return r.routes
+}
+
+func frameworkAdaptHandler(handler http.Handler) httputils.APIFunc {
+	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+		handler.ServeHTTP(w, r)
+		return nil
+	}
+}
+
+func frameworkAdaptHandlerFunc(handler http.HandlerFunc) httputils.APIFunc {
+	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+		handler(w, r)
+		return nil
+	}
+}

+ 13 - 0
api/server/router/debug/debug_routes.go

@@ -0,0 +1,13 @@
+package debug
+
+import (
+	"net/http"
+	"net/http/pprof"
+
+	"golang.org/x/net/context"
+)
+
+func handlePprof(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	pprof.Handler(vars["name"]).ServeHTTP(w, r)
+	return nil
+}

+ 9 - 16
api/server/server.go

@@ -12,6 +12,7 @@ import (
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/server/middleware"
 	"github.com/docker/docker/api/server/router"
+	"github.com/docker/docker/api/server/router/debug"
 	"github.com/docker/docker/dockerversion"
 	"github.com/gorilla/mux"
 	"golang.org/x/net/context"
@@ -148,13 +149,10 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
 
 // InitRouter initializes the list of routers for the server.
 // This method also enables the Go profiler if enableProfiler is true.
-func (s *Server) InitRouter(enableProfiler bool, routers ...router.Router) {
+func (s *Server) InitRouter(routers ...router.Router) {
 	s.routers = append(s.routers, routers...)
 
 	m := s.createMux()
-	if enableProfiler {
-		profilerSetup(m)
-	}
 	s.routerSwapper = &routerSwapper{
 		router: m,
 	}
@@ -175,6 +173,13 @@ func (s *Server) createMux() *mux.Router {
 		}
 	}
 
+	debugRouter := debug.NewRouter()
+	s.routers = append(s.routers, debugRouter)
+	for _, r := range debugRouter.Routes() {
+		f := s.makeHTTPHandler(r.Handler())
+		m.Path("/debug" + r.Path()).Handler(f)
+	}
+
 	err := errors.NewRequestNotFoundError(fmt.Errorf("page not found"))
 	notFoundHandler := httputils.MakeErrorHandler(err)
 	m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
@@ -194,15 +199,3 @@ func (s *Server) Wait(waitChan chan error) {
 	}
 	waitChan <- nil
 }
-
-// DisableProfiler reloads the server mux without adding the profiler routes.
-func (s *Server) DisableProfiler() {
-	s.routerSwapper.Swap(s.createMux())
-}
-
-// EnableProfiler reloads the server mux adding the profiler routes.
-func (s *Server) EnableProfiler() {
-	m := s.createMux()
-	profilerSetup(m)
-	s.routerSwapper.Swap(m)
-}

+ 1 - 3
cmd/dockerd/daemon.go

@@ -383,10 +383,8 @@ func (cli *DaemonCli) reloadConfig() {
 			switch {
 			case debugEnabled && !config.Debug: // disable debug
 				debug.Disable()
-				cli.api.DisableProfiler()
 			case config.Debug && !debugEnabled: // enable debug
 				debug.Enable()
-				cli.api.EnableProfiler()
 			}
 
 		}
@@ -536,7 +534,7 @@ func initRouter(opts routerOptions) {
 		}
 	}
 
-	opts.api.InitRouter(debug.IsEnabled(), routers...)
+	opts.api.InitRouter(routers...)
 }
 
 // TODO: remove this from cli and return the authzMiddleware