Add support to disable /debug/pprof and /debug/flags/v endpoint

Co-authored-by: xiaofei.sun <sunxiaofei@kuaishou.com>
Co-authored-by: SaranBalaji90 <srisaranbalaji@gmail.com>
This commit is contained in:
Sri Saran Balaji Vellore Rajakumar
2021-01-23 09:16:39 -08:00
parent f41def8d76
commit 51cdf4e97b
12 changed files with 134 additions and 52 deletions

View File

@@ -86,6 +86,8 @@ const (
specPath = "/spec/"
statsPath = "/stats/"
logsPath = "/logs/"
pprofBasePath = "/debug/pprof/"
debugFlagPath = "/debug/flags/v"
)
// Server is a http.Handler which exposes kubelet functionality over HTTP.
@@ -144,9 +146,12 @@ func ListenAndServeKubeletServer(
enableCAdvisorJSONEndpoints,
enableDebuggingHandlers,
enableContentionProfiling,
enableSystemLogHandler bool) {
klog.InfoS("Starting to listen", "address", address, "port", port)
handler := NewServer(host, resourceAnalyzer, auth, enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling, enableSystemLogHandler)
enableSystemLogHandler,
enableProfilingHandler,
enableDebugFlagsHandler bool) {
klog.Infof("Starting to listen on %s:%d", address, port)
handler := NewServer(host, resourceAnalyzer, auth, enableCAdvisorJSONEndpoints, enableDebuggingHandlers,
enableContentionProfiling, enableSystemLogHandler, enableProfilingHandler, enableDebugFlagsHandler)
s := &http.Server{
Addr: net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)),
Handler: &handler,
@@ -167,8 +172,8 @@ func ListenAndServeKubeletServer(
// ListenAndServeKubeletReadOnlyServer initializes a server to respond to HTTP network requests on the Kubelet.
func ListenAndServeKubeletReadOnlyServer(host HostInterface, resourceAnalyzer stats.ResourceAnalyzer, address net.IP, port uint, enableCAdvisorJSONEndpoints bool) {
klog.InfoS("Starting to listen read-only", "address", address, "port", port)
s := NewServer(host, resourceAnalyzer, nil, enableCAdvisorJSONEndpoints, false, false, false)
klog.V(1).Infof("Starting to listen read-only on %s:%d", address, port)
s := NewServer(host, resourceAnalyzer, nil, enableCAdvisorJSONEndpoints, false, false, false, false, false)
server := &http.Server{
Addr: net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)),
@@ -223,7 +228,9 @@ func NewServer(
enableCAdvisorJSONEndpoints,
enableDebuggingHandlers,
enableContentionProfiling,
enableSystemLogHandler bool) Server {
enableSystemLogHandler,
enableProfilingHandler,
enableDebugFlagsHandler bool) Server {
server := Server{
host: host,
resourceAnalyzer: resourceAnalyzer,
@@ -238,12 +245,11 @@ func NewServer(
server.InstallDefaultHandlers(enableCAdvisorJSONEndpoints)
if enableDebuggingHandlers {
server.InstallDebuggingHandlers()
// To maintain backward compatibility serve logs only when enableDebuggingHandlers is also enabled
// To maintain backward compatibility serve logs and pprof only when enableDebuggingHandlers is also enabled
// see https://github.com/kubernetes/kubernetes/pull/87273
server.InstallSystemLogHandler(enableSystemLogHandler)
if enableContentionProfiling {
goruntime.SetBlockProfileRate(1)
}
server.InstallProfilingHandler(enableProfilingHandler, enableContentionProfiling)
server.InstallDebugFlagsHandler(enableDebugFlagsHandler)
} else {
server.InstallDebuggingDisabledHandlers()
}
@@ -403,8 +409,6 @@ func (s *Server) InstallDefaultHandlers(enableCAdvisorJSONEndpoints bool) {
}
}
const pprofBasePath = "/debug/pprof/"
// InstallDebuggingHandlers registers the HTTP request patterns that serve logs or run commands/containers
func (s *Server) InstallDebuggingHandlers() {
klog.InfoS("Adding debug handlers to kubelet server")
@@ -487,33 +491,6 @@ func (s *Server) InstallDebuggingHandlers() {
s.addMetricsBucketMatcher("configz")
configz.InstallHandler(s.restfulCont)
s.addMetricsBucketMatcher("debug")
handlePprofEndpoint := func(req *restful.Request, resp *restful.Response) {
name := strings.TrimPrefix(req.Request.URL.Path, pprofBasePath)
switch name {
case "profile":
pprof.Profile(resp, req.Request)
case "symbol":
pprof.Symbol(resp, req.Request)
case "cmdline":
pprof.Cmdline(resp, req.Request)
case "trace":
pprof.Trace(resp, req.Request)
default:
pprof.Index(resp, req.Request)
}
}
// Setup pprof handlers.
ws = new(restful.WebService).Path(pprofBasePath)
ws.Route(ws.GET("/{subpath:*}").To(func(req *restful.Request, resp *restful.Response) {
handlePprofEndpoint(req, resp)
})).Doc("pprof endpoint")
s.restfulCont.Add(ws)
// Setup flags handlers.
// so far, only logging related endpoints are considered valid to add for these debug flags.
s.restfulCont.Handle("/debug/flags/v", routes.StringFlagPutHandler(logs.GlogSetter))
// The /runningpods endpoint is used for testing only.
s.addMetricsBucketMatcher("runningpods")
ws = new(restful.WebService)
@@ -563,10 +540,59 @@ func (s *Server) InstallSystemLogHandler(enableSystemLogHandler bool) {
Param(ws.PathParameter("logpath", "path to the log").DataType("string")))
s.restfulCont.Add(ws)
} else {
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "logs endpoint is disabled.", http.StatusMethodNotAllowed)
})
s.restfulCont.Handle(logsPath, h)
s.restfulCont.Handle(logsPath, getHandlerForDisabledEndpoint("logs endpoint is disabled."))
}
}
func getHandlerForDisabledEndpoint(errorMessage string) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, errorMessage, http.StatusMethodNotAllowed)
})
}
// InstallDebugFlagsHandler registers the HTTP request patterns for /debug/flags/v endpoint.
func (s *Server) InstallDebugFlagsHandler(enableDebugFlagsHandler bool) {
if enableDebugFlagsHandler {
// Setup flags handlers.
// so far, only logging related endpoints are considered valid to add for these debug flags.
s.restfulCont.Handle(debugFlagPath, routes.StringFlagPutHandler(logs.GlogSetter))
} else {
s.restfulCont.Handle(debugFlagPath, getHandlerForDisabledEndpoint("flags endpoint is disabled."))
return
}
}
// InstallProfilingHandler registers the HTTP request patterns for /debug/pprof endpoint.
func (s *Server) InstallProfilingHandler(enableSystemLogHandler bool, enableContentionProfiling bool) {
s.addMetricsBucketMatcher("debug")
if !enableSystemLogHandler {
s.restfulCont.Handle(pprofBasePath, getHandlerForDisabledEndpoint("profiling endpoint is disabled."))
return
}
handlePprofEndpoint := func(req *restful.Request, resp *restful.Response) {
name := strings.TrimPrefix(req.Request.URL.Path, pprofBasePath)
switch name {
case "profile":
pprof.Profile(resp, req.Request)
case "symbol":
pprof.Symbol(resp, req.Request)
case "cmdline":
pprof.Cmdline(resp, req.Request)
case "trace":
pprof.Trace(resp, req.Request)
default:
pprof.Index(resp, req.Request)
}
}
// Setup pprof handlers.
ws := new(restful.WebService).Path(pprofBasePath)
ws.Route(ws.GET("/{subpath:*}").To(handlePprofEndpoint)).Doc("pprof endpoint")
s.restfulCont.Add(ws)
if enableContentionProfiling {
goruntime.SetBlockProfileRate(1)
}
}

View File

@@ -307,7 +307,7 @@ func newServerTestWithDebug(enableDebugging bool, streamingServer streaming.Serv
return newServerTestWithDebuggingHandlers(enableDebugging, enableDebugging, streamingServer)
}
func newServerTestWithDebuggingHandlers(enableDebugging, enableSystemLogHandler bool, streamingServer streaming.Server) *serverTestFramework {
func newServerTestWithDebuggingHandlers(enableDebugging, enableLogAndProfilingHandler bool, streamingServer streaming.Server) *serverTestFramework {
fw := &serverTestFramework{}
fw.fakeKubelet = &fakeKubelet{
hostnameFunc: func() string {
@@ -343,7 +343,9 @@ func newServerTestWithDebuggingHandlers(enableDebugging, enableSystemLogHandler
true,
enableDebugging,
false,
enableSystemLogHandler)
enableLogAndProfilingHandler,
enableLogAndProfilingHandler,
enableLogAndProfilingHandler)
fw.serverUnderTest = &server
fw.testHTTPServer = httptest.NewServer(fw.serverUnderTest)
return fw
@@ -1549,12 +1551,14 @@ func TestDebuggingDisabledHandlers(t *testing.T) {
}
func TestDisablingSystemLogHandler(t *testing.T) {
func TestDisablingLogAndProfilingHandler(t *testing.T) {
fw := newServerTestWithDebuggingHandlers(true, false, nil)
defer fw.testHTTPServer.Close()
// verify logs endpoint is disabled
// verify debug endpoints are disabled
verifyEndpointResponse(t, fw, "/logs/kubelet.log", "logs endpoint is disabled.\n")
verifyEndpointResponse(t, fw, "/debug/pprof/profile?seconds=2", "profiling endpoint is disabled.\n")
verifyEndpointResponse(t, fw, "/debug/flags/v", "flags endpoint is disabled.\n")
}
func TestFailedParseParamsSummaryHandler(t *testing.T) {