Fix IntOrString cost estimation when schema has a MaxLength constraint

Kubernetes-commit: 8dc20a0f62d44af1d584efbbc6bf918b93c4e3d8
This commit is contained in:
Joel Speed 2025-07-09 12:14:28 +01:00 committed by Kubernetes Publisher
parent 953f6a8aff
commit 76004fdd79
1 changed files with 21 additions and 7 deletions

View File

@ -55,8 +55,15 @@ func SchemaDeclType(s Schema, isResourceRoot bool) *apiservercel.DeclType {
// `type(intOrStringField) == int ? intOrStringField < 5 : double(intOrStringField.replace('%', '')) < 0.5
//
dyn := apiservercel.NewSimpleTypeWithMinSize("dyn", cel.DynType, nil, 1) // smallest value for a serialized x-kubernetes-int-or-string is 0
// handle x-kubernetes-int-or-string by returning the max length/min serialized size of the largest possible string
dyn.MaxElements = maxRequestSizeBytes - 2
// If the schema has a maxlength constraint, bound the max elements based on the max length.
// Otherwise, fallback to the max request size.
if s.MaxLength() != nil {
dyn.MaxElements = estimateMaxElementsFromMaxLength(s)
} else {
dyn.MaxElements = estimateMaxStringLengthPerRequest(s)
}
return dyn
}
@ -159,11 +166,7 @@ func SchemaDeclType(s Schema, isResourceRoot bool) *apiservercel.DeclType {
strWithMaxLength := apiservercel.NewSimpleTypeWithMinSize("string", cel.StringType, types.String(""), apiservercel.MinStringSize)
if s.MaxLength() != nil {
// multiply the user-provided max length by 4 in the case of an otherwise-untyped string
// we do this because the OpenAPIv3 spec indicates that maxLength is specified in runes/code points,
// but we need to reason about length for things like request size, so we use bytes in this code (and an individual
// unicode code point can be up to 4 bytes long)
strWithMaxLength.MaxElements = zeroIfNegative(*s.MaxLength()) * 4
strWithMaxLength.MaxElements = estimateMaxElementsFromMaxLength(s)
} else {
if len(s.Enum()) > 0 {
strWithMaxLength.MaxElements = estimateMaxStringEnumLength(s)
@ -228,6 +231,7 @@ func WithTypeAndObjectMeta(s *spec.Schema) *spec.Schema {
// must only be called on schemas of type "string" or x-kubernetes-int-or-string: true
func estimateMaxStringLengthPerRequest(s Schema) int64 {
if s.IsXIntOrString() {
// handle x-kubernetes-int-or-string by returning the max length/min serialized size of the largest possible string
return maxRequestSizeBytes - 2
}
switch s.Format() {
@ -272,3 +276,13 @@ func estimateMaxAdditionalPropertiesFromMinSize(minSize int64) int64 {
// subtract 2 to account for { and }
return (maxRequestSizeBytes - 2) / keyValuePairSize
}
// estimateMaxElementsFromMaxLength estimates the maximum number of elements for a string schema
// that is bound with a maxLength constraint.
func estimateMaxElementsFromMaxLength(s Schema) int64 {
// multiply the user-provided max length by 4 in the case of an otherwise-untyped string
// we do this because the OpenAPIv3 spec indicates that maxLength is specified in runes/code points,
// but we need to reason about length for things like request size, so we use bytes in this code (and an individual
// unicode code point can be up to 4 bytes long)
return zeroIfNegative(*s.MaxLength()) * 4
}