Add metrics integration.

This commit is contained in:
Kermit Alexander II 2022-10-31 19:22:35 +00:00
parent c84e920a48
commit 99494e6777
9 changed files with 125 additions and 72 deletions

View File

@ -47,10 +47,10 @@ func newValidationAdmissionMetrics() *ValidatingAdmissionPolicyMetrics {
Namespace: metricsNamespace,
Subsystem: metricsSubsystem,
Name: "check_total",
Help: "Validation admission policy check total, labeled by policy and param resource, and further identified by binding, validation expression, enforcement action taken, and state.",
Help: "Validation admission policy check total, labeled by policy and further identified by binding, enforcement action taken, and state.",
StabilityLevel: metrics.ALPHA,
},
[]string{"policy", "policy_binding", "validation_expression", "enforcement_action", "params", "state"},
[]string{"policy", "policy_binding", "enforcement_action", "state"},
)
definition := metrics.NewCounterVec(&metrics.CounterOpts{
Namespace: metricsNamespace,
@ -65,7 +65,7 @@ func newValidationAdmissionMetrics() *ValidatingAdmissionPolicyMetrics {
Namespace: metricsNamespace,
Subsystem: metricsSubsystem,
Name: "check_duration_seconds",
Help: "Validation admission latency for individual validation expressions in seconds, labeled by policy and param resource, further including binding, state and enforcement action taken.",
Help: "Validation admission latency for individual validation expressions in seconds, labeled by policy and further including binding, state and enforcement action taken.",
// the bucket distribution here is based oo the benchmark suite at
// github.com/DangerOnTheRanger/cel-benchmark performed on 16-core Intel Xeon
// the lowest bucket was based around the 180ns/op figure for BenchmarkAccess,
@ -77,7 +77,7 @@ func newValidationAdmissionMetrics() *ValidatingAdmissionPolicyMetrics {
Buckets: []float64{0.0000005, 0.001, 0.01, 0.1, 1.0},
StabilityLevel: metrics.ALPHA,
},
[]string{"policy", "policy_binding", "validation_expression", "enforcement_action", "params", "state"},
[]string{"policy", "policy_binding", "enforcement_action", "state"},
)
legacyregistry.MustRegister(check)
@ -98,8 +98,14 @@ func (m *ValidatingAdmissionPolicyMetrics) ObserveDefinition(ctx context.Context
m.policyDefinition.WithContext(ctx).WithLabelValues(state, enforcementAction).Inc()
}
// ObserveCheck observes a policy validation check.
func (m *ValidatingAdmissionPolicyMetrics) ObserveCheck(ctx context.Context, elapsed time.Duration, policy, binding, expression, enforcementAction, params, state string) {
m.policyCheck.WithContext(ctx).WithLabelValues(policy, binding, expression, enforcementAction, params, state).Inc()
m.policyLatency.WithContext(ctx).WithLabelValues(policy, binding, expression, enforcementAction, params, state).Observe(elapsed.Seconds())
// 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, state string) {
m.policyCheck.WithContext(ctx).WithLabelValues(policy, binding, "allow", state).Inc()
m.policyLatency.WithContext(ctx).WithLabelValues(policy, binding, "allow", state).Observe(elapsed.Seconds())
}
// ObserveRejection observes a policy validation error that was at least one of the reasons for a deny.
func (m *ValidatingAdmissionPolicyMetrics) ObserveRejection(ctx context.Context, elapsed time.Duration, policy, binding, state string) {
m.policyCheck.WithContext(ctx).WithLabelValues(policy, binding, "deny", state).Inc()
m.policyLatency.WithContext(ctx).WithLabelValues(policy, binding, "deny", state).Observe(elapsed.Seconds())
}

View File

@ -42,24 +42,45 @@ func TestNoUtils(t *testing.T) {
observer metricsObserver
}{
{
desc: "observe policy check",
desc: "observe policy admission",
want: `
# HELP apiserver_validating_admission_policy_check_duration_seconds [ALPHA] Validation admission latency for individual validation expressions in seconds, labeled by policy and param resource, further including binding, state and enforcement action taken.
# HELP apiserver_validating_admission_policy_check_duration_seconds [ALPHA] Validation admission latency for individual validation expressions in seconds, labeled by policy and further including binding, state and enforcement action taken.
# TYPE apiserver_validating_admission_policy_check_duration_seconds histogram
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true",le="0.0000005"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true",le="0.001"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true",le="0.01"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true",le="0.1"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true",le="1"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true",le="+Inf"} 1
apiserver_validating_admission_policy_check_duration_seconds_sum{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true"} 10
apiserver_validating_admission_policy_check_duration_seconds_count{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true"} 1
# HELP apiserver_validating_admission_policy_check_total [ALPHA] Validation admission policy check total, labeled by policy and param resource, and further identified by binding, validation expression, enforcement action taken, and state.
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.0000005"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.001"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.01"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.1"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="1"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="+Inf"} 1
apiserver_validating_admission_policy_check_duration_seconds_sum{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active"} 10
apiserver_validating_admission_policy_check_duration_seconds_count{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active"} 1
# HELP apiserver_validating_admission_policy_check_total [ALPHA] Validation admission policy check total, labeled by policy and further identified by binding, enforcement action taken, and state.
# TYPE apiserver_validating_admission_policy_check_total counter
apiserver_validating_admission_policy_check_total{enforcement_action="allow",params="params.example.com",policy="policy.example.com",policy_binding="binding.example.com",state="active",validation_expression="true"} 1
apiserver_validating_admission_policy_check_total{enforcement_action="allow",policy="policy.example.com",policy_binding="binding.example.com",state="active"} 1
`,
observer: func() {
Metrics.ObserveCheck(context.TODO(), time.Duration(10)*time.Second, "policy.example.com", "binding.example.com", "true", "allow", "params.example.com", "active")
Metrics.ObserveAdmissionWithError(context.TODO(), time.Duration(10)*time.Second, "policy.example.com", "binding.example.com", "active")
},
},
{
desc: "observe policy rejection",
want: `
# HELP apiserver_validating_admission_policy_check_duration_seconds [ALPHA] Validation admission latency for individual validation expressions in seconds, labeled by policy and further including binding, state and enforcement action taken.
# TYPE apiserver_validating_admission_policy_check_duration_seconds histogram
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.0000005"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.001"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.01"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="0.1"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="1"} 0
apiserver_validating_admission_policy_check_duration_seconds_bucket{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active",le="+Inf"} 1
apiserver_validating_admission_policy_check_duration_seconds_sum{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active"} 10
apiserver_validating_admission_policy_check_duration_seconds_count{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active"} 1
# HELP apiserver_validating_admission_policy_check_total [ALPHA] Validation admission policy check total, labeled by policy and further identified by binding, enforcement action taken, and state.
# TYPE apiserver_validating_admission_policy_check_total counter
apiserver_validating_admission_policy_check_total{enforcement_action="deny",policy="policy.example.com",policy_binding="binding.example.com",state="active"} 1
`,
observer: func() {
Metrics.ObserveRejection(context.TODO(), time.Duration(10)*time.Second, "policy.example.com", "binding.example.com", "active")
},
},
{

View File

@ -581,7 +581,7 @@ func (v testValidator) Validate(a admission.Attributes, o admission.ObjectInterf
// Policy always denies
return []policyDecision{
{
kind: deny,
action: actionDeny,
message: "Denied",
},
}, nil

View File

@ -34,6 +34,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/admission"
celmetrics "k8s.io/apiserver/pkg/admission/cel"
"k8s.io/apiserver/pkg/admission/plugin/cel/internal/generic"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/informers"
@ -227,7 +228,7 @@ func (c *celAdmissionController) Validate(
}
deniedDecisions = append(deniedDecisions, policyDecisionWithMetadata{
policyDecision: policyDecision{
kind: deny,
action: actionDeny,
message: message,
},
definition: definition,
@ -236,7 +237,7 @@ func (c *celAdmissionController) Validate(
default:
deniedDecisions = append(deniedDecisions, policyDecisionWithMetadata{
policyDecision: policyDecision{
kind: deny,
action: actionDeny,
message: fmt.Errorf("unrecognized failure policy: '%v'", policy).Error(),
},
definition: definition,
@ -353,18 +354,21 @@ func (c *celAdmissionController) Validate(
}
for _, decision := range decisions {
switch decision.kind {
case admit:
// TODO: add metrics for ignored error here
case deny:
switch decision.action {
case actionAdmit:
if decision.evaluation == evalError {
celmetrics.Metrics.ObserveAdmissionWithError(ctx, decision.elapsed, definition.Name, binding.Name, "active")
}
case actionDeny:
deniedDecisions = append(deniedDecisions, policyDecisionWithMetadata{
definition: definition,
binding: binding,
policyDecision: decision,
})
celmetrics.Metrics.ObserveRejection(ctx, decision.elapsed, definition.Name, binding.Name, "active")
default:
return fmt.Errorf("unrecognized evaluation decision '%s' for ValidatingAdmissionPolicyBinding '%s' with ValidatingAdmissionPolicy '%s'",
decision.kind, binding.Name, definition.Name)
decision.action, binding.Name, definition.Name)
}
}
}
@ -389,7 +393,6 @@ func (c *celAdmissionController) Validate(
err.ErrStatus.Details.Causes = append(err.ErrStatus.Details.Causes, metav1.StatusCause{Message: message})
return err
}
return nil
}

View File

@ -26,6 +26,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
celmetrics "k8s.io/apiserver/pkg/admission/cel"
"k8s.io/apiserver/pkg/admission/plugin/cel/internal/generic"
"k8s.io/client-go/dynamic/dynamicinformer"
"k8s.io/client-go/tools/cache"
@ -41,6 +42,8 @@ func (c *celAdmissionController) reconcilePolicyDefinition(namespace, name strin
if !ok {
info = &definitionInfo{}
c.definitionInfo[nn] = info
// TODO(DangerOnTheRanger): add support for "warn" being a valid enforcementAction
celmetrics.Metrics.ObserveDefinition(context.TODO(), "active", "deny")
}
var paramSource *v1alpha1.ParamKind

View File

@ -18,22 +18,33 @@ package cel
import (
"net/http"
"time"
"k8s.io/api/admissionregistration/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type policyDecisionKind string
type policyDecisionAction string
const (
admit policyDecisionKind = "admit"
deny policyDecisionKind = "deny"
actionAdmit policyDecisionAction = "admit"
actionDeny policyDecisionAction = "deny"
)
type policyDecisionEvaluation string
const (
evalAdmit policyDecisionEvaluation = "admit"
evalError policyDecisionEvaluation = "error"
evalDeny policyDecisionEvaluation = "deny"
)
type policyDecision struct {
kind policyDecisionKind
message string
reason metav1.StatusReason
action policyDecisionAction
evaluation policyDecisionEvaluation
message string
reason metav1.StatusReason
elapsed time.Duration
}
type policyDecisionWithMetadata struct {

View File

@ -20,6 +20,7 @@ import (
"fmt"
"reflect"
"strings"
"time"
celtypes "github.com/google/cel-go/common/types"
"github.com/google/cel-go/interpreter"
@ -156,11 +157,11 @@ func objectToResolveVal(r runtime.Object) (interface{}, error) {
return v.Object, nil
}
func policyDecisionKindForError(f v1alpha1.FailurePolicyType) policyDecisionKind {
func policyDecisionActionForError(f v1alpha1.FailurePolicyType) policyDecisionAction {
if f == v1alpha1.Ignore {
return admit
return actionAdmit
}
return deny
return actionDeny
}
// Validate validates all cel expressions in Validator and returns a PolicyDecision for each CEL expression or returns an error.
@ -213,21 +214,27 @@ func (v *CELValidator) Validate(a admission.Attributes, o admission.ObjectInterf
var policyDecision = &decisions[i]
if compilationResult.Error != nil {
policyDecision.kind = policyDecisionKindForError(f)
policyDecision.action = policyDecisionActionForError(f)
policyDecision.evaluation = evalError
policyDecision.message = fmt.Sprintf("compilation error: %v", compilationResult.Error)
continue
}
if compilationResult.Program == nil {
policyDecision.kind = policyDecisionKindForError(f)
policyDecision.action = policyDecisionActionForError(f)
policyDecision.evaluation = evalError
policyDecision.message = "unexpected internal error compiling expression"
continue
}
t1 := time.Now()
evalResult, _, err := compilationResult.Program.Eval(va)
elapsed := time.Since(t1)
policyDecision.elapsed = elapsed
if err != nil {
policyDecision.kind = policyDecisionKindForError(f)
policyDecision.action = policyDecisionActionForError(f)
policyDecision.evaluation = evalError
policyDecision.message = fmt.Sprintf("expression '%v' resulted in error: %v", v.policy.Spec.Validations[i].Expression, err)
} else if evalResult != celtypes.True {
policyDecision.kind = deny
policyDecision.action = actionDeny
if validation.Reason == nil {
policyDecision.reason = metav1.StatusReasonInvalid
} else {
@ -240,7 +247,8 @@ func (v *CELValidator) Validate(a admission.Attributes, o admission.ObjectInterf
}
} else {
policyDecision.kind = admit
policyDecision.action = actionAdmit
policyDecision.evaluation = evalAdmit
}
}

View File

@ -219,8 +219,8 @@ func getValidPolicy(validations []v1alpha1.Validation, params *v1alpha1.ParamKin
}
}
func generatedDecision(k policyDecisionKind, m string, r metav1.StatusReason) policyDecision {
return policyDecision{kind: k, message: m, reason: r}
func generatedDecision(k policyDecisionAction, m string, r metav1.StatusReason) policyDecision {
return policyDecision{action: k, message: m, reason: r}
}
func TestValidate(t *testing.T) {
@ -281,7 +281,7 @@ func TestValidate(t *testing.T) {
}, nil, nil),
attributes: newValidAttribute(nil, false),
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -293,7 +293,7 @@ func TestValidate(t *testing.T) {
}, nil, nil),
attributes: newValidAttribute(nil, false),
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -308,8 +308,8 @@ func TestValidate(t *testing.T) {
}, nil, nil),
attributes: newValidAttribute(nil, false),
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -319,7 +319,7 @@ func TestValidate(t *testing.T) {
}, nil, nil),
attributes: newValidAttribute(nil, false),
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -330,7 +330,7 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, false),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -348,7 +348,7 @@ func TestValidate(t *testing.T) {
},
},
policyDecisions: []policyDecision{
generatedDecision(deny, "failed expression: object.subsets.size() > 2", metav1.StatusReasonInvalid),
generatedDecision(actionDeny, "failed expression: object.subsets.size() > 2", metav1.StatusReasonInvalid),
},
},
{
@ -364,8 +364,8 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, false),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(deny, "failed expression: object.subsets.size() > 2", metav1.StatusReasonInvalid),
generatedDecision(actionAdmit, "", ""),
generatedDecision(actionDeny, "failed expression: object.subsets.size() > 2", metav1.StatusReasonInvalid),
},
},
{
@ -381,8 +381,8 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, false),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(deny, "failed expression: oldObject != null", metav1.StatusReasonInvalid),
generatedDecision(deny, "failed expression: object.subsets.size() > 2", metav1.StatusReasonInvalid),
generatedDecision(actionDeny, "failed expression: oldObject != null", metav1.StatusReasonInvalid),
generatedDecision(actionDeny, "failed expression: object.subsets.size() > 2", metav1.StatusReasonInvalid),
},
},
{
@ -398,8 +398,8 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, true),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -413,7 +413,7 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, true),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(deny, "failed expression: oldObject == null", metav1.StatusReasonForbidden),
generatedDecision(actionDeny, "failed expression: oldObject == null", metav1.StatusReasonForbidden),
},
},
{
@ -428,7 +428,7 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, true),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(deny, "old object should be present", metav1.StatusReasonForbidden),
generatedDecision(actionDeny, "old object should be present", metav1.StatusReasonForbidden),
},
},
{
@ -441,7 +441,7 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, true),
params: configMapParams,
policyDecisions: []policyDecision{
generatedDecision(deny, "resulted in error", ""),
generatedDecision(actionDeny, "resulted in error", ""),
},
},
{
@ -454,7 +454,7 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, false),
params: crdParams,
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -470,8 +470,8 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, false),
params: crdParams,
policyDecisions: []policyDecision{
generatedDecision(deny, "compilation error: compilation failed: ERROR: <input>:1:6: Syntax error:", ""),
generatedDecision(deny, "failed expression: object.subsets.size() > params.spec.testSize", metav1.StatusReasonInvalid),
generatedDecision(actionDeny, "compilation error: compilation failed: ERROR: <input>:1:6: Syntax error:", ""),
generatedDecision(actionDeny, "failed expression: object.subsets.size() > params.spec.testSize", metav1.StatusReasonInvalid),
},
},
{
@ -487,8 +487,8 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(nil, false),
params: crdParams,
policyDecisions: []policyDecision{
generatedDecision(admit, "compilation error: compilation failed: ERROR:", ""),
generatedDecision(deny, "failed expression: object.subsets.size() > params.spec.testSize", metav1.StatusReasonInvalid),
generatedDecision(actionAdmit, "compilation error: compilation failed: ERROR:", ""),
generatedDecision(actionDeny, "failed expression: object.subsets.size() > params.spec.testSize", metav1.StatusReasonInvalid),
},
},
{
@ -501,7 +501,7 @@ func TestValidate(t *testing.T) {
attributes: newValidAttribute(&podObject, false),
params: crdParams,
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
{
@ -518,7 +518,7 @@ func TestValidate(t *testing.T) {
// if paramRef is unset on a binding
params: runtime.Object(nilUnstructured),
policyDecisions: []policyDecision{
generatedDecision(deny, "params as required", metav1.StatusReasonForbidden),
generatedDecision(actionDeny, "params as required", metav1.StatusReasonForbidden),
},
},
{
@ -534,7 +534,7 @@ func TestValidate(t *testing.T) {
// if paramRef is unset on a binding
params: runtime.Object(nilUnstructured),
policyDecisions: []policyDecision{
generatedDecision(admit, "", ""),
generatedDecision(actionAdmit, "", ""),
},
},
}
@ -556,8 +556,8 @@ func TestValidate(t *testing.T) {
}
require.Equal(t, len(policyResults), len(tc.policyDecisions))
for i, policyDecision := range tc.policyDecisions {
if policyDecision.kind != policyResults[i].kind {
t.Errorf("Expected policy decision kind '%v' but got '%v'", policyDecision.kind, policyResults[i].kind)
if policyDecision.action != policyResults[i].action {
t.Errorf("Expected policy decision kind '%v' but got '%v'", policyDecision.action, policyResults[i].action)
}
if !strings.Contains(policyResults[i].message, policyDecision.message) {
t.Errorf("Expected policy decision message contains '%v' but got '%v'", policyDecision.message, policyResults[i].message)

1
vendor/modules.txt vendored
View File

@ -1432,6 +1432,7 @@ k8s.io/apimachinery/third_party/forked/golang/reflect
# k8s.io/apiserver v0.0.0 => ./staging/src/k8s.io/apiserver
## explicit; go 1.19
k8s.io/apiserver/pkg/admission
k8s.io/apiserver/pkg/admission/cel
k8s.io/apiserver/pkg/admission/configuration
k8s.io/apiserver/pkg/admission/initializer
k8s.io/apiserver/pkg/admission/metrics