diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go index ad6530ffb7f..7b2349ddff6 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go @@ -223,7 +223,7 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm switch decision.Action { case ActionAdmit: if decision.Evaluation == EvalError { - celmetrics.Metrics.ObserveAdmissionWithError(ctx, decision.Elapsed, definition.Name, binding.Name) + celmetrics.Metrics.ObserveAdmission(ctx, decision.Elapsed, definition.Name, binding.Name, ErrorType(&decision)) } case ActionDeny: for _, action := range binding.Spec.ValidationActions { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/errors.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/errors.go new file mode 100644 index 00000000000..c8380baa9bf --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/errors.go @@ -0,0 +1,38 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validating + +import ( + "strings" + + celmetrics "k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics" +) + +// ErrorType decodes the error to determine the error type +// that the metrics understand. +func ErrorType(decision *PolicyDecision) celmetrics.ValidationErrorType { + if decision.Evaluation == EvalAdmit { + return celmetrics.ValidationNoError + } + if strings.HasPrefix(decision.Message, "compilation") { + return celmetrics.ValidationCompileError + } + if strings.HasPrefix(decision.Message, "validation failed due to running out of cost budget") { + return celmetrics.ValidatingOutOfBudget + } + return celmetrics.ValidatingInternalError +} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/errors.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/errors.go new file mode 100644 index 00000000000..e6dac566929 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/errors.go @@ -0,0 +1,38 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cel + +import ( + "errors" + + apiservercel "k8s.io/apiserver/pkg/cel" +) + +// ErrorType decodes the error to determine the error type +// that the metrics understand. +func ErrorType(err error) ValidationErrorType { + if err == nil { + return ValidationNoError + } + if errors.Is(err, apiservercel.ErrCompilation) { + return ValidationCompileError + } + if errors.Is(err, apiservercel.ErrOutOfBudget) { + return ValidatingOutOfBudget + } + return ValidatingInternalError +} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics.go index d1707eb60d2..3be9afa8e65 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics.go @@ -29,6 +29,22 @@ const ( metricsSubsystem = "validating_admission_policy" ) +// ValidationErrorType defines different error types that happen to a validation expression +type ValidationErrorType string + +const ( + // ValidationCompileError indicates that the expression fails to compile. + ValidationCompileError ValidationErrorType = "compile_error" + // ValidatingInternalError indicates that the expression fails due to internal + // errors that are out of the control of the user. + ValidatingInternalError ValidationErrorType = "internal_error" + // ValidatingOutOfBudget indicates that the expression fails due to running + // out of cost budget, or the budget cannot be obtained. + ValidatingOutOfBudget ValidationErrorType = "out_of_budget" + // ValidationNoError indicates that the expression returns without an error. + ValidationNoError ValidationErrorType = "no_error" +) + var ( // Metrics provides access to validation admission metrics. Metrics = newValidationAdmissionMetrics() @@ -81,8 +97,8 @@ func (m *ValidatingAdmissionPolicyMetrics) Reset() { m.policyLatency.Reset() } -// ObserveAdmissionWithError observes a policy validation error that was ignored due to failure policy. -func (m *ValidatingAdmissionPolicyMetrics) ObserveAdmissionWithError(ctx context.Context, elapsed time.Duration, policy, binding string) { +// ObserveAdmission observes a policy validation, with an optional error to indicate the error that may occur but ignored. +func (m *ValidatingAdmissionPolicyMetrics) ObserveAdmission(ctx context.Context, elapsed time.Duration, policy, binding string, errorType ValidationErrorType) { m.policyCheck.WithContext(ctx).WithLabelValues(policy, binding, "allow").Inc() m.policyLatency.WithContext(ctx).WithLabelValues(policy, binding, "allow").Observe(elapsed.Seconds()) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics_test.go index 682cf691638..e575e0faad0 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/metrics/metrics_test.go @@ -58,7 +58,7 @@ func TestNoUtils(t *testing.T) { apiserver_validating_admission_policy_check_total{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com"} 1 `, observer: func() { - Metrics.ObserveAdmissionWithError(context.TODO(), time.Duration(10)*time.Second, "policy.example.com", "binding.example.com") + Metrics.ObserveAdmission(context.TODO(), time.Duration(10)*time.Second, "policy.example.com", "binding.example.com") }, }, {