mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
apiserver: increment metric for deprecated API use
This commit is contained in:
parent
e06b0635de
commit
e4bb1daecf
@ -360,7 +360,7 @@ func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if handlerFunc != nil {
|
if handlerFunc != nil {
|
||||||
handlerFunc = metrics.InstrumentHandlerFunc(verb, requestInfo.APIGroup, requestInfo.APIVersion, resource, subresource, scope, metrics.APIServerComponent, handlerFunc)
|
handlerFunc = metrics.InstrumentHandlerFunc(verb, requestInfo.APIGroup, requestInfo.APIVersion, resource, subresource, scope, metrics.APIServerComponent, false, "", handlerFunc)
|
||||||
handler := genericfilters.WithWaitGroup(handlerFunc, longRunningFilter, crdInfo.waitGroup)
|
handler := genericfilters.WithWaitGroup(handlerFunc, longRunningFilter, crdInfo.waitGroup)
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
return
|
return
|
||||||
|
@ -629,8 +629,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
var (
|
var (
|
||||||
enableWarningHeaders = utilfeature.DefaultFeatureGate.Enabled(features.WarningHeaders)
|
enableWarningHeaders = utilfeature.DefaultFeatureGate.Enabled(features.WarningHeaders)
|
||||||
|
|
||||||
warnings []string
|
warnings []string
|
||||||
deprecated bool
|
deprecated bool
|
||||||
|
removedRelease string
|
||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -639,6 +640,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
currentMajor, currentMinor, _ := deprecation.MajorMinor(versioninfo.Get())
|
currentMajor, currentMinor, _ := deprecation.MajorMinor(versioninfo.Get())
|
||||||
deprecated = deprecation.IsDeprecated(versionedPtrWithGVK, currentMajor, currentMinor)
|
deprecated = deprecation.IsDeprecated(versionedPtrWithGVK, currentMajor, currentMinor)
|
||||||
if deprecated {
|
if deprecated {
|
||||||
|
removedRelease = deprecation.RemovedRelease(versionedPtrWithGVK)
|
||||||
warnings = append(warnings, deprecation.WarningMessage(versionedPtrWithGVK))
|
warnings = append(warnings, deprecation.WarningMessage(versionedPtrWithGVK))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,9 +656,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
|
|
||||||
if needOverride {
|
if needOverride {
|
||||||
// need change the reported verb
|
// need change the reported verb
|
||||||
handler = metrics.InstrumentRouteFunc(verbOverrider.OverrideMetricsVerb(action.Verb), group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler)
|
handler = metrics.InstrumentRouteFunc(verbOverrider.OverrideMetricsVerb(action.Verb), group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, handler)
|
||||||
} else {
|
} else {
|
||||||
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler)
|
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, handler)
|
||||||
}
|
}
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
@ -690,7 +692,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if isSubresource {
|
if isSubresource {
|
||||||
doc = "list " + subresource + " of objects of kind " + kind
|
doc = "list " + subresource + " of objects of kind " + kind
|
||||||
}
|
}
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -725,7 +727,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if isSubresource {
|
if isSubresource {
|
||||||
doc = "replace " + subresource + " of the specified " + kind
|
doc = "replace " + subresource + " of the specified " + kind
|
||||||
}
|
}
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulUpdateResource(updater, reqScope, admit))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulUpdateResource(updater, reqScope, admit))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -758,7 +760,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||||
supportedTypes = append(supportedTypes, string(types.ApplyPatchType))
|
supportedTypes = append(supportedTypes, string(types.ApplyPatchType))
|
||||||
}
|
}
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulPatchResource(patcher, reqScope, admit, supportedTypes))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulPatchResource(patcher, reqScope, admit, supportedTypes))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -783,7 +785,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
} else {
|
} else {
|
||||||
handler = restfulCreateResource(creater, reqScope, admit)
|
handler = restfulCreateResource(creater, reqScope, admit)
|
||||||
}
|
}
|
||||||
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler)
|
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, handler)
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -819,7 +821,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if deleteReturnsDeletedObject {
|
if deleteReturnsDeletedObject {
|
||||||
deleteReturnType = producedObject
|
deleteReturnType = producedObject
|
||||||
}
|
}
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -845,7 +847,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if isSubresource {
|
if isSubresource {
|
||||||
doc = "delete collection of " + subresource + " of a " + kind
|
doc = "delete collection of " + subresource + " of a " + kind
|
||||||
}
|
}
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -875,7 +877,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
doc = "watch changes to " + subresource + " of an object of kind " + kind
|
doc = "watch changes to " + subresource + " of an object of kind " + kind
|
||||||
}
|
}
|
||||||
doc += ". deprecated: use the 'watch' parameter with a list operation instead, filtered to a single item with the 'fieldSelector' parameter."
|
doc += ". deprecated: use the 'watch' parameter with a list operation instead, filtered to a single item with the 'fieldSelector' parameter."
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -898,7 +900,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
doc = "watch individual changes to a list of " + subresource + " of " + kind
|
doc = "watch individual changes to a list of " + subresource + " of " + kind
|
||||||
}
|
}
|
||||||
doc += ". deprecated: use the 'watch' parameter with a list operation instead."
|
doc += ". deprecated: use the 'watch' parameter with a list operation instead."
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
@ -924,7 +926,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
if isSubresource {
|
if isSubresource {
|
||||||
doc = "connect " + method + " requests to " + subresource + " of " + kind
|
doc = "connect " + method + " requests to " + subresource + " of " + kind
|
||||||
}
|
}
|
||||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulConnectResource(connecter, reqScope, admit, path, isSubresource))
|
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulConnectResource(connecter, reqScope, admit, path, isSubresource))
|
||||||
if enableWarningHeaders {
|
if enableWarningHeaders {
|
||||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,15 @@ const (
|
|||||||
* the metric stability policy.
|
* the metric stability policy.
|
||||||
*/
|
*/
|
||||||
var (
|
var (
|
||||||
|
deprecatedRequestGauge = compbasemetrics.NewGaugeVec(
|
||||||
|
&compbasemetrics.GaugeOpts{
|
||||||
|
Name: "apiserver_requested_deprecated_apis",
|
||||||
|
Help: "Gauge of deprecated APIs that have been requested, broken out by API group, version, resource, subresource, and removed_release.",
|
||||||
|
StabilityLevel: compbasemetrics.ALPHA,
|
||||||
|
},
|
||||||
|
[]string{"group", "version", "resource", "subresource", "removed_release"},
|
||||||
|
)
|
||||||
|
|
||||||
// TODO(a-robinson): Add unit tests for the handling of these metrics once
|
// TODO(a-robinson): Add unit tests for the handling of these metrics once
|
||||||
// the upstream library supports it.
|
// the upstream library supports it.
|
||||||
requestCounter = compbasemetrics.NewCounterVec(
|
requestCounter = compbasemetrics.NewCounterVec(
|
||||||
@ -162,6 +171,7 @@ var (
|
|||||||
kubectlExeRegexp = regexp.MustCompile(`^.*((?i:kubectl\.exe))`)
|
kubectlExeRegexp = regexp.MustCompile(`^.*((?i:kubectl\.exe))`)
|
||||||
|
|
||||||
metrics = []resettableCollector{
|
metrics = []resettableCollector{
|
||||||
|
deprecatedRequestGauge,
|
||||||
requestCounter,
|
requestCounter,
|
||||||
longRunningRequestGauge,
|
longRunningRequestGauge,
|
||||||
requestLatencies,
|
requestLatencies,
|
||||||
@ -288,12 +298,15 @@ func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, comp
|
|||||||
|
|
||||||
// MonitorRequest handles standard transformations for client and the reported verb and then invokes Monitor to record
|
// MonitorRequest handles standard transformations for client and the reported verb and then invokes Monitor to record
|
||||||
// a request. verb must be uppercase to be backwards compatible with existing monitoring tooling.
|
// a request. verb must be uppercase to be backwards compatible with existing monitoring tooling.
|
||||||
func MonitorRequest(req *http.Request, verb, group, version, resource, subresource, scope, component, contentType string, httpCode, respSize int, elapsed time.Duration) {
|
func MonitorRequest(req *http.Request, verb, group, version, resource, subresource, scope, component string, deprecated bool, removedRelease string, contentType string, httpCode, respSize int, elapsed time.Duration) {
|
||||||
reportedVerb := cleanVerb(verb, req)
|
reportedVerb := cleanVerb(verb, req)
|
||||||
dryRun := cleanDryRun(req.URL)
|
dryRun := cleanDryRun(req.URL)
|
||||||
elapsedSeconds := elapsed.Seconds()
|
elapsedSeconds := elapsed.Seconds()
|
||||||
cleanContentType := cleanContentType(contentType)
|
cleanContentType := cleanContentType(contentType)
|
||||||
requestCounter.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component, cleanContentType, codeToString(httpCode)).Inc()
|
requestCounter.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component, cleanContentType, codeToString(httpCode)).Inc()
|
||||||
|
if deprecated {
|
||||||
|
deprecatedRequestGauge.WithLabelValues(group, version, resource, subresource, removedRelease).Set(1)
|
||||||
|
}
|
||||||
requestLatencies.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component).Observe(elapsedSeconds)
|
requestLatencies.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component).Observe(elapsedSeconds)
|
||||||
// We are only interested in response sizes of read requests.
|
// We are only interested in response sizes of read requests.
|
||||||
if verb == "GET" || verb == "LIST" {
|
if verb == "GET" || verb == "LIST" {
|
||||||
@ -303,7 +316,7 @@ func MonitorRequest(req *http.Request, verb, group, version, resource, subresour
|
|||||||
|
|
||||||
// InstrumentRouteFunc works like Prometheus' InstrumentHandlerFunc but wraps
|
// InstrumentRouteFunc works like Prometheus' InstrumentHandlerFunc but wraps
|
||||||
// the go-restful RouteFunction instead of a HandlerFunc plus some Kubernetes endpoint specific information.
|
// the go-restful RouteFunction instead of a HandlerFunc plus some Kubernetes endpoint specific information.
|
||||||
func InstrumentRouteFunc(verb, group, version, resource, subresource, scope, component string, routeFunc restful.RouteFunction) restful.RouteFunction {
|
func InstrumentRouteFunc(verb, group, version, resource, subresource, scope, component string, deprecated bool, removedRelease string, routeFunc restful.RouteFunction) restful.RouteFunction {
|
||||||
return restful.RouteFunction(func(request *restful.Request, response *restful.Response) {
|
return restful.RouteFunction(func(request *restful.Request, response *restful.Response) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
@ -322,12 +335,12 @@ func InstrumentRouteFunc(verb, group, version, resource, subresource, scope, com
|
|||||||
|
|
||||||
routeFunc(request, response)
|
routeFunc(request, response)
|
||||||
|
|
||||||
MonitorRequest(request.Request, verb, group, version, resource, subresource, scope, component, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now))
|
MonitorRequest(request.Request, verb, group, version, resource, subresource, scope, component, deprecated, removedRelease, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstrumentHandlerFunc works like Prometheus' InstrumentHandlerFunc but adds some Kubernetes endpoint specific information.
|
// InstrumentHandlerFunc works like Prometheus' InstrumentHandlerFunc but adds some Kubernetes endpoint specific information.
|
||||||
func InstrumentHandlerFunc(verb, group, version, resource, subresource, scope, component string, handler http.HandlerFunc) http.HandlerFunc {
|
func InstrumentHandlerFunc(verb, group, version, resource, subresource, scope, component string, deprecated bool, removedRelease string, handler http.HandlerFunc) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
@ -344,7 +357,7 @@ func InstrumentHandlerFunc(verb, group, version, resource, subresource, scope, c
|
|||||||
|
|
||||||
handler(w, req)
|
handler(w, req)
|
||||||
|
|
||||||
MonitorRequest(req, verb, group, version, resource, subresource, scope, component, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now))
|
MonitorRequest(req, verb, group, version, resource, subresource, scope, component, deprecated, removedRelease, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,8 @@ func InstallPathHandler(mux mux, path string, checks ...HealthChecker) {
|
|||||||
/* subresource = */ path,
|
/* subresource = */ path,
|
||||||
/* scope = */ "",
|
/* scope = */ "",
|
||||||
/* component = */ "",
|
/* component = */ "",
|
||||||
|
/* deprecated */ false,
|
||||||
|
/* removedRelease */ "",
|
||||||
handleRootHealthz(checks...)))
|
handleRootHealthz(checks...)))
|
||||||
for _, check := range checks {
|
for _, check := range checks {
|
||||||
mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check))
|
mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check))
|
||||||
|
@ -95,11 +95,17 @@ func TestApiserverMetrics(t *testing.T) {
|
|||||||
t.Fatalf("unexpected error getting pods: %v", err)
|
t.Fatalf("unexpected error getting pods: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a request to a deprecated API to ensure there's at least one data point
|
||||||
|
if _, err := client.RbacV1beta1().Roles(metav1.NamespaceDefault).List(context.TODO(), metav1.ListOptions{}); err != nil {
|
||||||
|
t.Fatalf("unexpected error getting rbac roles: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
metrics, err := scrapeMetrics(s)
|
metrics, err := scrapeMetrics(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkForExpectedMetrics(t, metrics, []string{
|
checkForExpectedMetrics(t, metrics, []string{
|
||||||
|
"apiserver_requested_deprecated_apis",
|
||||||
"apiserver_request_total",
|
"apiserver_request_total",
|
||||||
"apiserver_request_duration_seconds_sum",
|
"apiserver_request_duration_seconds_sum",
|
||||||
"etcd_request_duration_seconds_sum",
|
"etcd_request_duration_seconds_sum",
|
||||||
|
Loading…
Reference in New Issue
Block a user