From 50893dee96dad5fe54169e746fcc09276afedcdf Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Fri, 3 Jan 2025 12:38:36 -0600 Subject: [PATCH] :seedling: Allow string validation on XIntOrString --- pkg/crd/markers/validation.go | 19 ++++++++++--------- pkg/crd/testdata/cronjob_types.go | 9 ++++++--- .../testdata.kubebuilder.io_cronjobs.yaml | 9 ++++++--- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/pkg/crd/markers/validation.go b/pkg/crd/markers/validation.go index 08d28612c..5cd5daf69 100644 --- a/pkg/crd/markers/validation.go +++ b/pkg/crd/markers/validation.go @@ -316,6 +316,10 @@ func hasNumericType(schema *apiext.JSONSchemaProps) bool { return schema.Type == "integer" || schema.Type == "number" } +func hasTextualType(schema *apiext.JSONSchemaProps) bool { + return schema.Type == "string" || schema.XIntOrString +} + func isIntegral(value float64) bool { return value == math.Trunc(value) && !math.IsNaN(value) && !math.IsInf(value, 0) } @@ -394,8 +398,8 @@ func (m MultipleOf) ApplyToSchema(schema *apiext.JSONSchemaProps) error { } func (m MaxLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "string" { - return fmt.Errorf("must apply maxlength to a string") + if !hasTextualType(schema) { + return fmt.Errorf("must apply maxlength to a textual value, found type %q", schema.Type) } val := int64(m) schema.MaxLength = &val @@ -403,8 +407,8 @@ func (m MaxLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { } func (m MinLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "string" { - return fmt.Errorf("must apply minlength to a string") + if !hasTextualType(schema) { + return fmt.Errorf("must apply minlength to a textual value, found type %q", schema.Type) } val := int64(m) schema.MinLength = &val @@ -412,11 +416,8 @@ func (m MinLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { } func (m Pattern) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - // Allow string types or IntOrStrings. An IntOrString will still - // apply the pattern validation when a string is detected, the pattern - // will not apply to ints though. - if schema.Type != "string" && !schema.XIntOrString { - return fmt.Errorf("must apply pattern to a `string` or `IntOrString`") + if !hasTextualType(schema) { + return fmt.Errorf("must apply pattern to a textual value, found type %q", schema.Type) } schema.Pattern = string(m) return nil diff --git a/pkg/crd/testdata/cronjob_types.go b/pkg/crd/testdata/cronjob_types.go index 4569d2f7d..dd9c960d7 100644 --- a/pkg/crd/testdata/cronjob_types.go +++ b/pkg/crd/testdata/cronjob_types.go @@ -249,11 +249,12 @@ type CronJobSpec struct { // +kubebuilder:validation:Schemaless Schemaless []byte `json:"schemaless,omitempty"` - // This tests that an IntOrString can also have a pattern attached - // to it. + // This tests that an IntOrString can also have string validation. // This can be useful if you want to limit the string to a percentage or integer. // The XIntOrString marker is a requirement for having a pattern on this type. // +kubebuilder:validation:XIntOrString + // +kubebuilder:validation:MaxLength=11 + // +kubebuilder:validation:MinLength=2 // +kubebuilder:validation:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$" IntOrStringWithAPattern *intstr.IntOrString `json:"intOrStringWithAPattern,omitempty"` @@ -358,10 +359,12 @@ type CronJobSpec struct { // +kubebuilder:validation:MinItems=3 LongerStringArray []LongerString `json:"longerStringArray,omitempty"` - // This tests that a slice of IntOrString can also have a pattern attached to it. + // This tests that a slice of IntOrString can also have string validation. // This can be useful if you want to limit the string to a percentage or integer. // The XIntOrString marker is a requirement for having a pattern on this type. // +kubebuilder:validation:items:XIntOrString + // +kubebuilder:validation:items:MaxLength=10 + // +kubebuilder:validation:items:MinLength=1 // +kubebuilder:validation:items:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$" IntOrStringArrayWithAPattern []*intstr.IntOrString `json:"intOrStringArrayWithAPattern,omitempty"` diff --git a/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml b/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml index e99637a39..b2f493daf 100644 --- a/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml +++ b/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml @@ -256,13 +256,15 @@ spec: type: integer intOrStringArrayWithAPattern: description: |- - This tests that a slice of IntOrString can also have a pattern attached to it. + This tests that a slice of IntOrString can also have string validation. This can be useful if you want to limit the string to a percentage or integer. The XIntOrString marker is a requirement for having a pattern on this type. items: anyOf: - type: integer - type: string + maxLength: 10 + minLength: 1 pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ x-kubernetes-int-or-string: true type: array @@ -271,10 +273,11 @@ spec: - type: integer - type: string description: |- - This tests that an IntOrString can also have a pattern attached - to it. + This tests that an IntOrString can also have string validation. This can be useful if you want to limit the string to a percentage or integer. The XIntOrString marker is a requirement for having a pattern on this type. + maxLength: 11 + minLength: 2 pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ x-kubernetes-int-or-string: true intWithValidations: