replace CEL ValidateWithRatcheting with variadic options

so we can now supply a shared CorrelatedObject
This commit is contained in:
Alexander Zielenski 2023-10-24 11:22:59 -07:00
parent b3525946d5
commit e7a9a14848
3 changed files with 24 additions and 14 deletions

View File

@ -144,20 +144,29 @@ func validator(s *schema.Structural, isResourceRoot bool, declType *cel.DeclType
return nil
}
type options struct {
ratchetingOptions
}
type Option func(*options)
func WithRatcheting(correlation *common.CorrelatedObject) Option {
return func(o *options) {
o.currentCorrelation = correlation
}
}
// Validate validates all x-kubernetes-validations rules in Validator against obj and returns any errors.
// If the validation rules exceed the costBudget, subsequent evaluations will be skipped, the list of errs returned will not be empty, and a negative remainingBudget will be returned.
// Most callers can ignore the returned remainingBudget value unless another validate call is going to be made
// context is passed for supporting context cancellation during cel validation
func (s *Validator) Validate(ctx context.Context, fldPath *field.Path, sts *schema.Structural, obj, oldObj interface{}, costBudget int64) (errs field.ErrorList, remainingBudget int64) {
return s.validate(ctx, fldPath, sts, obj, oldObj, ratchetingOptions{}, costBudget)
}
func (s *Validator) Validate(ctx context.Context, fldPath *field.Path, sts *schema.Structural, obj, oldObj interface{}, costBudget int64, opts ...Option) (errs field.ErrorList, remainingBudget int64) {
opt := options{}
for _, o := range opts {
o(&opt)
}
func (s *Validator) ValidateWithRatcheting(ctx context.Context, fldPath *field.Path, sts *schema.Structural, obj, oldObj interface{}, costBudget int64) (errs field.ErrorList, remainingBudget int64) {
// May be a worthwhile optimization to share the correlated object instance
// with the OpenAPI schema validator to avoid doing DeepEqual twice
return s.validate(ctx, fldPath, sts, obj, oldObj, ratchetingOptions{
currentCorrelation: common.NewCorrelatedObject(obj, oldObj, &model.Structural{Structural: sts}),
}, costBudget)
return s.validate(ctx, fldPath, sts, obj, oldObj, opt.ratchetingOptions, costBudget)
}
// ratchetingOptions stores the current correlation object and the nearest

View File

@ -39,6 +39,7 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apimachinery/pkg/util/yaml"
celconfig "k8s.io/apiserver/pkg/apis/cel"
"k8s.io/apiserver/pkg/cel/common"
"k8s.io/apiserver/pkg/warning"
)
@ -3564,13 +3565,14 @@ func TestRatcheting(t *testing.T) {
if budget == 0 {
budget = celconfig.RuntimeCELCostBudget
}
errs, _ := validator.ValidateWithRatcheting(
errs, _ := validator.Validate(
ctx,
field.NewPath("root"),
c.schema,
c.newObj,
c.oldObj,
budget,
WithRatcheting(common.NewCorrelatedObject(c.newObj, c.oldObj, &model.Structural{Structural: c.schema})),
)
require.Len(t, errs, len(c.errors), "must have expected number of errors")

View File

@ -246,9 +246,11 @@ func (a customResourceStrategy) ValidateUpdate(ctx context.Context, obj, old run
}
var options []validation.ValidationOption
var celOptions []cel.Option
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CRDValidationRatcheting) {
correlatedObject := common.NewCorrelatedObject(uNew.Object, uOld.Object, &model.Structural{Structural: a.structuralSchema})
options = append(options, validation.WithRatcheting(correlatedObject))
celOptions = append(celOptions, cel.WithRatcheting(correlatedObject))
}
var errs field.ErrorList
@ -266,11 +268,8 @@ func (a customResourceStrategy) ValidateUpdate(ctx context.Context, obj, old run
if celValidator := a.celValidator; celValidator != nil {
if has, err := hasBlockingErr(errs); has {
errs = append(errs, err)
} else if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CRDValidationRatcheting) {
err, _ := celValidator.ValidateWithRatcheting(ctx, nil, a.structuralSchema, uNew.Object, uOld.Object, celconfig.RuntimeCELCostBudget)
errs = append(errs, err...)
} else {
err, _ := celValidator.Validate(ctx, nil, a.structuralSchema, uNew.Object, uOld.Object, celconfig.RuntimeCELCostBudget)
err, _ := celValidator.Validate(ctx, nil, a.structuralSchema, uNew.Object, uOld.Object, celconfig.RuntimeCELCostBudget, celOptions...)
errs = append(errs, err...)
}
}