Merge pull request #89412 from coderanger/fix-kubelet-method-metrics

Apply the same style of fix as #87913 but for HTTP methods too.
This commit is contained in:
Kubernetes Prow Robot 2020-05-18 17:43:36 -07:00 committed by GitHub
commit 036fcda230
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 8 deletions

View File

@ -38,6 +38,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/proxy:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/proxy:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",

View File

@ -48,6 +48,7 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/proxy" "k8s.io/apimachinery/pkg/util/proxy"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/healthz"
@ -90,7 +91,8 @@ type Server struct {
auth AuthInterface auth AuthInterface
host HostInterface host HostInterface
restfulCont containerInterface restfulCont containerInterface
metricsBuckets map[string]bool metricsBuckets sets.String
metricsMethodBuckets sets.String
resourceAnalyzer stats.ResourceAnalyzer resourceAnalyzer stats.ResourceAnalyzer
redirectContainerStreaming bool redirectContainerStreaming bool
} }
@ -227,7 +229,8 @@ func NewServer(
resourceAnalyzer: resourceAnalyzer, resourceAnalyzer: resourceAnalyzer,
auth: auth, auth: auth,
restfulCont: &filteringContainer{Container: restful.NewContainer()}, restfulCont: &filteringContainer{Container: restful.NewContainer()},
metricsBuckets: make(map[string]bool), metricsBuckets: sets.NewString(),
metricsMethodBuckets: sets.NewString("OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"),
redirectContainerStreaming: redirectContainerStreaming, redirectContainerStreaming: redirectContainerStreaming,
} }
if auth != nil { if auth != nil {
@ -286,16 +289,24 @@ func (s *Server) InstallAuthFilter() {
// addMetricsBucketMatcher adds a regexp matcher and the relevant bucket to use when // addMetricsBucketMatcher adds a regexp matcher and the relevant bucket to use when
// it matches. Please be aware this is not thread safe and should not be used dynamically // it matches. Please be aware this is not thread safe and should not be used dynamically
func (s *Server) addMetricsBucketMatcher(bucket string) { func (s *Server) addMetricsBucketMatcher(bucket string) {
s.metricsBuckets[bucket] = true s.metricsBuckets.Insert(bucket)
} }
// getMetricBucket find the appropriate metrics reporting bucket for the given path // getMetricBucket find the appropriate metrics reporting bucket for the given path
func (s *Server) getMetricBucket(path string) string { func (s *Server) getMetricBucket(path string) string {
root := getURLRootPath(path) root := getURLRootPath(path)
if s.metricsBuckets[root] == true { if s.metricsBuckets.Has(root) {
return root return root
} }
return "Invalid path" return "other"
}
// getMetricMethodBucket checks for unknown or invalid HTTP verbs
func (s *Server) getMetricMethodBucket(method string) string {
if s.metricsMethodBuckets.Has(method) {
return method
}
return "other"
} }
// InstallDefaultHandlers registers the default set of supported HTTP request // InstallDefaultHandlers registers the default set of supported HTTP request
@ -909,7 +920,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
serverType = "readwrite" serverType = "readwrite"
} }
method, path := req.Method, s.getMetricBucket(req.URL.Path) method, path := s.getMetricMethodBucket(req.Method), s.getMetricBucket(req.URL.Path)
longRunning := strconv.FormatBool(isLongRunningRequest(path)) longRunning := strconv.FormatBool(isLongRunningRequest(path))

View File

@ -1510,8 +1510,8 @@ func TestMetricBuckets(t *testing.T) {
"stats summary sub": {url: "/stats/summary", bucket: "stats"}, "stats summary sub": {url: "/stats/summary", bucket: "stats"},
"stats containerName with uid": {url: "/stats/namespace/podName/uid/containerName", bucket: "stats"}, "stats containerName with uid": {url: "/stats/namespace/podName/uid/containerName", bucket: "stats"},
"stats containerName": {url: "/stats/podName/containerName", bucket: "stats"}, "stats containerName": {url: "/stats/podName/containerName", bucket: "stats"},
"invalid path": {url: "/junk", bucket: "Invalid path"}, "invalid path": {url: "/junk", bucket: "other"},
"invalid path starting with good": {url: "/healthzjunk", bucket: "Invalid path"}, "invalid path starting with good": {url: "/healthzjunk", bucket: "other"},
} }
fw := newServerTest() fw := newServerTest()
defer fw.testHTTPServer.Close() defer fw.testHTTPServer.Close()
@ -1523,6 +1523,26 @@ func TestMetricBuckets(t *testing.T) {
} }
} }
func TestMetricMethodBuckets(t *testing.T) {
tests := map[string]struct {
method string
bucket string
}{
"normal GET": {method: "GET", bucket: "GET"},
"normal POST": {method: "POST", bucket: "POST"},
"invalid method": {method: "WEIRD", bucket: "other"},
}
fw := newServerTest()
defer fw.testHTTPServer.Close()
for _, test := range tests {
method := test.method
bucket := test.bucket
require.Equal(t, fw.serverUnderTest.getMetricMethodBucket(method), bucket)
}
}
func TestDebuggingDisabledHandlers(t *testing.T) { func TestDebuggingDisabledHandlers(t *testing.T) {
fw := newServerTestWithDebug(false, false, nil) fw := newServerTestWithDebug(false, false, nil)
defer fw.testHTTPServer.Close() defer fw.testHTTPServer.Close()