mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-18 13:57:38 +00:00
Merge pull request #134302 from lalitc375/device-class-selectors
feat(resource): Add validation for DeviceClass selectors and configs
This commit is contained in:
101
pkg/apis/resource/v1/zz_generated.validations.go
generated
101
pkg/apis/resource/v1/zz_generated.validations.go
generated
@@ -39,6 +39,22 @@ func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
// type DeviceClass
|
||||
scheme.AddValidationFunc((*resourcev1.DeviceClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_DeviceClass(ctx, op, nil /* fldPath */, obj.(*resourcev1.DeviceClass), safe.Cast[*resourcev1.DeviceClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type DeviceClassList
|
||||
scheme.AddValidationFunc((*resourcev1.DeviceClassList)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_DeviceClassList(ctx, op, nil /* fldPath */, obj.(*resourcev1.DeviceClassList), safe.Cast[*resourcev1.DeviceClassList](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type ResourceClaim
|
||||
scheme.AddValidationFunc((*resourcev1.ResourceClaim)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
@@ -166,6 +182,91 @@ func Validate_DeviceClaim(ctx context.Context, op operation.Operation, fldPath *
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClass validates an instance of DeviceClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1.DeviceClass) (errs field.ErrorList) {
|
||||
// field resourcev1.DeviceClass.TypeMeta has no validation
|
||||
// field resourcev1.DeviceClass.ObjectMeta has no validation
|
||||
|
||||
// field resourcev1.DeviceClass.Spec
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *resourcev1.DeviceClassSpec) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call the type's validation function
|
||||
errs = append(errs, Validate_DeviceClassSpec(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *resourcev1.DeviceClass) *resourcev1.DeviceClassSpec { return &oldObj.Spec }))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClassList validates an instance of DeviceClassList according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClassList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1.DeviceClassList) (errs field.ErrorList) {
|
||||
// field resourcev1.DeviceClassList.TypeMeta has no validation
|
||||
// field resourcev1.DeviceClassList.ListMeta has no validation
|
||||
|
||||
// field resourcev1.DeviceClassList.Items
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1.DeviceClass) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// iterate the list and call the type's validation function
|
||||
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_DeviceClass)...)
|
||||
return
|
||||
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *resourcev1.DeviceClassList) []resourcev1.DeviceClass { return oldObj.Items }))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClassSpec validates an instance of DeviceClassSpec according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClassSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1.DeviceClassSpec) (errs field.ErrorList) {
|
||||
// field resourcev1.DeviceClassSpec.Selectors
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1.DeviceSelector) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 32); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
return // do not proceed
|
||||
}
|
||||
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("selectors"), obj.Selectors, safe.Field(oldObj, func(oldObj *resourcev1.DeviceClassSpec) []resourcev1.DeviceSelector { return oldObj.Selectors }))...)
|
||||
|
||||
// field resourcev1.DeviceClassSpec.Config
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1.DeviceClassConfiguration) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 32); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
return // do not proceed
|
||||
}
|
||||
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("config"), obj.Config, safe.Field(oldObj, func(oldObj *resourcev1.DeviceClassSpec) []resourcev1.DeviceClassConfiguration { return oldObj.Config }))...)
|
||||
|
||||
// field resourcev1.DeviceClassSpec.ExtendedResourceName has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceRequestAllocationResult validates an instance of DeviceRequestAllocationResult according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceRequestAllocationResult(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1.DeviceRequestAllocationResult) (errs field.ErrorList) {
|
||||
|
||||
105
pkg/apis/resource/v1beta1/zz_generated.validations.go
generated
105
pkg/apis/resource/v1beta1/zz_generated.validations.go
generated
@@ -39,6 +39,22 @@ func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
// type DeviceClass
|
||||
scheme.AddValidationFunc((*resourcev1beta1.DeviceClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_DeviceClass(ctx, op, nil /* fldPath */, obj.(*resourcev1beta1.DeviceClass), safe.Cast[*resourcev1beta1.DeviceClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type DeviceClassList
|
||||
scheme.AddValidationFunc((*resourcev1beta1.DeviceClassList)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_DeviceClassList(ctx, op, nil /* fldPath */, obj.(*resourcev1beta1.DeviceClassList), safe.Cast[*resourcev1beta1.DeviceClassList](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type ResourceClaim
|
||||
scheme.AddValidationFunc((*resourcev1beta1.ResourceClaim)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
@@ -172,6 +188,95 @@ func Validate_DeviceClaim(ctx context.Context, op operation.Operation, fldPath *
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClass validates an instance of DeviceClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta1.DeviceClass) (errs field.ErrorList) {
|
||||
// field resourcev1beta1.DeviceClass.TypeMeta has no validation
|
||||
// field resourcev1beta1.DeviceClass.ObjectMeta has no validation
|
||||
|
||||
// field resourcev1beta1.DeviceClass.Spec
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *resourcev1beta1.DeviceClassSpec) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call the type's validation function
|
||||
errs = append(errs, Validate_DeviceClassSpec(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *resourcev1beta1.DeviceClass) *resourcev1beta1.DeviceClassSpec { return &oldObj.Spec }))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClassList validates an instance of DeviceClassList according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClassList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta1.DeviceClassList) (errs field.ErrorList) {
|
||||
// field resourcev1beta1.DeviceClassList.TypeMeta has no validation
|
||||
// field resourcev1beta1.DeviceClassList.ListMeta has no validation
|
||||
|
||||
// field resourcev1beta1.DeviceClassList.Items
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1beta1.DeviceClass) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// iterate the list and call the type's validation function
|
||||
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_DeviceClass)...)
|
||||
return
|
||||
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *resourcev1beta1.DeviceClassList) []resourcev1beta1.DeviceClass { return oldObj.Items }))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClassSpec validates an instance of DeviceClassSpec according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClassSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta1.DeviceClassSpec) (errs field.ErrorList) {
|
||||
// field resourcev1beta1.DeviceClassSpec.Selectors
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1beta1.DeviceSelector) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 32); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
return // do not proceed
|
||||
}
|
||||
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("selectors"), obj.Selectors, safe.Field(oldObj, func(oldObj *resourcev1beta1.DeviceClassSpec) []resourcev1beta1.DeviceSelector {
|
||||
return oldObj.Selectors
|
||||
}))...)
|
||||
|
||||
// field resourcev1beta1.DeviceClassSpec.Config
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1beta1.DeviceClassConfiguration) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 32); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
return // do not proceed
|
||||
}
|
||||
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("config"), obj.Config, safe.Field(oldObj, func(oldObj *resourcev1beta1.DeviceClassSpec) []resourcev1beta1.DeviceClassConfiguration {
|
||||
return oldObj.Config
|
||||
}))...)
|
||||
|
||||
// field resourcev1beta1.DeviceClassSpec.ExtendedResourceName has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceRequestAllocationResult validates an instance of DeviceRequestAllocationResult according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceRequestAllocationResult(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta1.DeviceRequestAllocationResult) (errs field.ErrorList) {
|
||||
|
||||
105
pkg/apis/resource/v1beta2/zz_generated.validations.go
generated
105
pkg/apis/resource/v1beta2/zz_generated.validations.go
generated
@@ -39,6 +39,22 @@ func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
// type DeviceClass
|
||||
scheme.AddValidationFunc((*resourcev1beta2.DeviceClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_DeviceClass(ctx, op, nil /* fldPath */, obj.(*resourcev1beta2.DeviceClass), safe.Cast[*resourcev1beta2.DeviceClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type DeviceClassList
|
||||
scheme.AddValidationFunc((*resourcev1beta2.DeviceClassList)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_DeviceClassList(ctx, op, nil /* fldPath */, obj.(*resourcev1beta2.DeviceClassList), safe.Cast[*resourcev1beta2.DeviceClassList](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type ResourceClaim
|
||||
scheme.AddValidationFunc((*resourcev1beta2.ResourceClaim)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
@@ -172,6 +188,95 @@ func Validate_DeviceClaim(ctx context.Context, op operation.Operation, fldPath *
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClass validates an instance of DeviceClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta2.DeviceClass) (errs field.ErrorList) {
|
||||
// field resourcev1beta2.DeviceClass.TypeMeta has no validation
|
||||
// field resourcev1beta2.DeviceClass.ObjectMeta has no validation
|
||||
|
||||
// field resourcev1beta2.DeviceClass.Spec
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *resourcev1beta2.DeviceClassSpec) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call the type's validation function
|
||||
errs = append(errs, Validate_DeviceClassSpec(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *resourcev1beta2.DeviceClass) *resourcev1beta2.DeviceClassSpec { return &oldObj.Spec }))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClassList validates an instance of DeviceClassList according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClassList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta2.DeviceClassList) (errs field.ErrorList) {
|
||||
// field resourcev1beta2.DeviceClassList.TypeMeta has no validation
|
||||
// field resourcev1beta2.DeviceClassList.ListMeta has no validation
|
||||
|
||||
// field resourcev1beta2.DeviceClassList.Items
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1beta2.DeviceClass) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// iterate the list and call the type's validation function
|
||||
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_DeviceClass)...)
|
||||
return
|
||||
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *resourcev1beta2.DeviceClassList) []resourcev1beta2.DeviceClass { return oldObj.Items }))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceClassSpec validates an instance of DeviceClassSpec according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceClassSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta2.DeviceClassSpec) (errs field.ErrorList) {
|
||||
// field resourcev1beta2.DeviceClassSpec.Selectors
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1beta2.DeviceSelector) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 32); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
return // do not proceed
|
||||
}
|
||||
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("selectors"), obj.Selectors, safe.Field(oldObj, func(oldObj *resourcev1beta2.DeviceClassSpec) []resourcev1beta2.DeviceSelector {
|
||||
return oldObj.Selectors
|
||||
}))...)
|
||||
|
||||
// field resourcev1beta2.DeviceClassSpec.Config
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []resourcev1beta2.DeviceClassConfiguration) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 32); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
return // do not proceed
|
||||
}
|
||||
if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("config"), obj.Config, safe.Field(oldObj, func(oldObj *resourcev1beta2.DeviceClassSpec) []resourcev1beta2.DeviceClassConfiguration {
|
||||
return oldObj.Config
|
||||
}))...)
|
||||
|
||||
// field resourcev1beta2.DeviceClassSpec.ExtendedResourceName has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_DeviceRequestAllocationResult validates an instance of DeviceRequestAllocationResult according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_DeviceRequestAllocationResult(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *resourcev1beta2.DeviceRequestAllocationResult) (errs field.ErrorList) {
|
||||
|
||||
@@ -544,8 +544,9 @@ func validateDeviceClassSpec(spec, oldSpec *resource.DeviceClassSpec, fldPath *f
|
||||
func(selector resource.DeviceSelector, fldPath *field.Path) field.ErrorList {
|
||||
return validateSelector(selector, fldPath, stored)
|
||||
},
|
||||
fldPath.Child("selectors"))...)
|
||||
fldPath.Child("selectors"), sizeCovered)...)
|
||||
// Same logic as above for configs.
|
||||
stored = false
|
||||
if oldSpec != nil {
|
||||
stored = apiequality.Semantic.DeepEqual(spec.Config, oldSpec.Config)
|
||||
}
|
||||
@@ -553,7 +554,7 @@ func validateDeviceClassSpec(spec, oldSpec *resource.DeviceClassSpec, fldPath *f
|
||||
func(config resource.DeviceClassConfiguration, fldPath *field.Path) field.ErrorList {
|
||||
return validateDeviceClassConfiguration(config, fldPath, stored)
|
||||
},
|
||||
fldPath.Child("config"))...)
|
||||
fldPath.Child("config"), sizeCovered)...)
|
||||
if spec.ExtendedResourceName != nil && !v1helper.IsExtendedResourceName(corev1.ResourceName(*spec.ExtendedResourceName)) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("extendedResourceName"), *spec.ExtendedResourceName,
|
||||
"must be a valid extended resource name"))
|
||||
|
||||
@@ -219,7 +219,7 @@ func TestValidateClass(t *testing.T) {
|
||||
},
|
||||
"too-many-selectors": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.TooMany(field.NewPath("spec", "selectors"), resource.DeviceSelectorsMaxSize+1, resource.DeviceSelectorsMaxSize),
|
||||
field.TooMany(field.NewPath("spec", "selectors"), resource.DeviceSelectorsMaxSize+1, resource.DeviceSelectorsMaxSize).WithOrigin("maxItems").MarkCoveredByDeclarative(),
|
||||
},
|
||||
class: func() *resource.DeviceClass {
|
||||
class := testClass(goodName)
|
||||
@@ -313,7 +313,7 @@ func TestValidateClass(t *testing.T) {
|
||||
},
|
||||
"too-many-configs": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.TooMany(field.NewPath("spec", "config"), resource.DeviceConfigMaxSize+1, resource.DeviceConfigMaxSize),
|
||||
field.TooMany(field.NewPath("spec", "config"), resource.DeviceConfigMaxSize+1, resource.DeviceConfigMaxSize).WithOrigin("maxItems").MarkCoveredByDeclarative(),
|
||||
},
|
||||
class: func() *resource.DeviceClass {
|
||||
class := testClass(goodName)
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package deviceclass
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -48,6 +49,26 @@ func TestDeclarativeValidate(t *testing.T) {
|
||||
"valid": {
|
||||
input: mkDeviceClass(),
|
||||
},
|
||||
// spec.selectors.
|
||||
"valid: at limit selectors": {
|
||||
input: mkDeviceClass(tweakSelectors(32)),
|
||||
},
|
||||
"too many selectors": {
|
||||
input: mkDeviceClass(tweakSelectors(33)),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.TooMany(field.NewPath("spec", "selectors"), 33, 32).WithOrigin("maxItems"),
|
||||
},
|
||||
},
|
||||
// spec.config
|
||||
"too many configs": {
|
||||
input: mkDeviceClass(tweakConfig(33)),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.TooMany(field.NewPath("spec", "config"), 33, 32).WithOrigin("maxItems"),
|
||||
},
|
||||
},
|
||||
"valid: at limit configs": {
|
||||
input: mkDeviceClass(tweakConfig(32)),
|
||||
},
|
||||
// TODO: Add more test cases
|
||||
}
|
||||
|
||||
@@ -80,6 +101,28 @@ func TestDeclarativeValidateUpdate(t *testing.T) {
|
||||
old: mkDeviceClass(),
|
||||
update: mkDeviceClass(),
|
||||
},
|
||||
"valid update: at limit selectors": {
|
||||
old: mkDeviceClass(),
|
||||
update: mkDeviceClass(tweakSelectors(32)),
|
||||
},
|
||||
"update with too many selectors": {
|
||||
old: mkDeviceClass(),
|
||||
update: mkDeviceClass(tweakSelectors(33)),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.TooMany(field.NewPath("spec", "selectors"), 33, 32).WithOrigin("maxItems"),
|
||||
},
|
||||
},
|
||||
"valid update: at limit configs": {
|
||||
old: mkDeviceClass(),
|
||||
update: mkDeviceClass(tweakConfig(32)),
|
||||
},
|
||||
"update with too many configs": {
|
||||
old: mkDeviceClass(),
|
||||
update: mkDeviceClass(tweakConfig(33)),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.TooMany(field.NewPath("spec", "config"), 33, 32).WithOrigin("maxItems"),
|
||||
},
|
||||
},
|
||||
// TODO: Add more test cases
|
||||
}
|
||||
|
||||
@@ -127,3 +170,35 @@ func mkDeviceClass(mutators ...func(*resource.DeviceClass)) resource.DeviceClass
|
||||
}
|
||||
return dc
|
||||
}
|
||||
|
||||
func tweakSelectors(count int) func(*resource.DeviceClass) {
|
||||
return func(dc *resource.DeviceClass) {
|
||||
dc.Spec.Selectors = []resource.DeviceSelector{}
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
dc.Spec.Selectors = append(dc.Spec.Selectors, resource.DeviceSelector{
|
||||
CEL: &resource.CELDeviceSelector{
|
||||
Expression: fmt.Sprintf("device.driver == \"test.driver.io%d\"", i),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tweakConfig(count int) func(*resource.DeviceClass) {
|
||||
return func(dc *resource.DeviceClass) {
|
||||
dc.Spec.Config = []resource.DeviceClassConfiguration{}
|
||||
for i := 0; i < count; i++ {
|
||||
dc.Spec.Config = append(dc.Spec.Config, resource.DeviceClassConfiguration{
|
||||
DeviceConfiguration: resource.DeviceConfiguration{
|
||||
Opaque: &resource.OpaqueDeviceConfiguration{
|
||||
Driver: "test.driver.io",
|
||||
Parameters: runtime.RawExtension{
|
||||
Raw: []byte(fmt.Sprintf(`{"key":"value%d"}`, i)),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +84,7 @@ func (deviceClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.
|
||||
newClass := obj.(*resource.DeviceClass)
|
||||
oldClass := old.(*resource.DeviceClass)
|
||||
|
||||
errorList := validation.ValidateDeviceClass(newClass)
|
||||
errorList = append(errorList, validation.ValidateDeviceClassUpdate(newClass, oldClass)...)
|
||||
errorList := validation.ValidateDeviceClassUpdate(newClass, oldClass)
|
||||
|
||||
return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newClass, oldClass, errorList, operation.Update)
|
||||
}
|
||||
|
||||
@@ -642,6 +642,8 @@ message DeviceClassSpec {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
repeated DeviceSelector selectors = 1;
|
||||
|
||||
// Config defines configuration parameters that apply to each device that is claimed via this class.
|
||||
@@ -652,6 +654,8 @@ message DeviceClassSpec {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
repeated DeviceClassConfiguration config = 2;
|
||||
|
||||
// ExtendedResourceName is the extended resource name for the devices of this class.
|
||||
|
||||
@@ -1672,6 +1672,8 @@ type DeviceClassSpec struct {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
Selectors []DeviceSelector `json:"selectors,omitempty" protobuf:"bytes,1,opt,name=selectors"`
|
||||
|
||||
// Config defines configuration parameters that apply to each device that is claimed via this class.
|
||||
@@ -1682,6 +1684,8 @@ type DeviceClassSpec struct {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
Config []DeviceClassConfiguration `json:"config,omitempty" protobuf:"bytes,2,opt,name=config"`
|
||||
|
||||
// SuitableNodes is tombstoned since Kubernetes 1.32 where
|
||||
|
||||
@@ -650,6 +650,8 @@ message DeviceClassSpec {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
repeated DeviceSelector selectors = 1;
|
||||
|
||||
// Config defines configuration parameters that apply to each device that is claimed via this class.
|
||||
@@ -660,6 +662,8 @@ message DeviceClassSpec {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
repeated DeviceClassConfiguration config = 2;
|
||||
|
||||
// ExtendedResourceName is the extended resource name for the devices of this class.
|
||||
|
||||
@@ -1680,6 +1680,8 @@ type DeviceClassSpec struct {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
Selectors []DeviceSelector `json:"selectors,omitempty" protobuf:"bytes,1,opt,name=selectors"`
|
||||
|
||||
// Config defines configuration parameters that apply to each device that is claimed via this class.
|
||||
@@ -1690,6 +1692,8 @@ type DeviceClassSpec struct {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
Config []DeviceClassConfiguration `json:"config,omitempty" protobuf:"bytes,2,opt,name=config"`
|
||||
|
||||
// SuitableNodes is tombstoned since Kubernetes 1.32 where
|
||||
|
||||
@@ -642,6 +642,8 @@ message DeviceClassSpec {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
repeated DeviceSelector selectors = 1;
|
||||
|
||||
// Config defines configuration parameters that apply to each device that is claimed via this class.
|
||||
@@ -652,6 +654,8 @@ message DeviceClassSpec {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
repeated DeviceClassConfiguration config = 2;
|
||||
|
||||
// ExtendedResourceName is the extended resource name for the devices of this class.
|
||||
|
||||
@@ -1672,6 +1672,8 @@ type DeviceClassSpec struct {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
Selectors []DeviceSelector `json:"selectors,omitempty" protobuf:"bytes,1,opt,name=selectors"`
|
||||
|
||||
// Config defines configuration parameters that apply to each device that is claimed via this class.
|
||||
@@ -1682,6 +1684,8 @@ type DeviceClassSpec struct {
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
// +k8s:optional
|
||||
// +k8s:maxItems=32
|
||||
Config []DeviceClassConfiguration `json:"config,omitempty" protobuf:"bytes,2,opt,name=config"`
|
||||
|
||||
// SuitableNodes is tombstoned since Kubernetes 1.32 where
|
||||
|
||||
@@ -76,62 +76,57 @@ func TestMaxLength(t *testing.T) {
|
||||
|
||||
func TestMaxItems(t *testing.T) {
|
||||
cases := []struct {
|
||||
fn func(op operation.Operation, fp *field.Path) field.ErrorList
|
||||
err string // regex
|
||||
name string
|
||||
items int
|
||||
max int
|
||||
err string // regex
|
||||
}{{
|
||||
fn: func(op operation.Operation, fp *field.Path) field.ErrorList {
|
||||
value := make([]string, 0)
|
||||
max := 0
|
||||
return MaxItems(context.Background(), op, fp, value, nil, max)
|
||||
},
|
||||
name: "0 items, max 0",
|
||||
items: 0,
|
||||
max: 0,
|
||||
}, {
|
||||
fn: func(op operation.Operation, fp *field.Path) field.ErrorList {
|
||||
value := make([]string, 1)
|
||||
max := 0
|
||||
return MaxItems(context.Background(), op, fp, value, nil, max)
|
||||
},
|
||||
err: "fldpath: Too many.*must have at most",
|
||||
name: "1 item, max 0",
|
||||
items: 1,
|
||||
max: 0,
|
||||
err: "fldpath: Too many.*must have at most",
|
||||
}, {
|
||||
fn: func(op operation.Operation, fp *field.Path) field.ErrorList {
|
||||
value := make([]int, 1)
|
||||
max := 1
|
||||
return MaxItems(context.Background(), op, fp, value, nil, max)
|
||||
},
|
||||
name: "1 item, max 1",
|
||||
items: 1,
|
||||
max: 1,
|
||||
}, {
|
||||
fn: func(op operation.Operation, fp *field.Path) field.ErrorList {
|
||||
value := make([]int, 2)
|
||||
max := 1
|
||||
return MaxItems(context.Background(), op, fp, value, nil, max)
|
||||
},
|
||||
err: "fldpath: Too many.*must have at most",
|
||||
name: "2 items, max 1",
|
||||
items: 2,
|
||||
max: 1,
|
||||
err: "fldpath: Too many.*must have at most",
|
||||
}, {
|
||||
fn: func(op operation.Operation, fp *field.Path) field.ErrorList {
|
||||
value := make([]bool, 0)
|
||||
max := -1
|
||||
return MaxItems(context.Background(), op, fp, value, nil, max)
|
||||
},
|
||||
err: "fldpath: Too many.*too many items",
|
||||
name: "0 items, max -1",
|
||||
items: 0,
|
||||
max: -1,
|
||||
err: "fldpath: Too many.*too many items",
|
||||
}}
|
||||
|
||||
for i, tc := range cases {
|
||||
result := tc.fn(operation.Operation{}, field.NewPath("fldpath"))
|
||||
if len(result) > 0 && tc.err == "" {
|
||||
t.Errorf("case %d: unexpected failure: %v", i, fmtErrs(result))
|
||||
continue
|
||||
}
|
||||
if len(result) == 0 && tc.err != "" {
|
||||
t.Errorf("case %d: unexpected success: expected %q", i, tc.err)
|
||||
continue
|
||||
}
|
||||
if len(result) > 0 {
|
||||
if len(result) > 1 {
|
||||
t.Errorf("case %d: unexepected multi-error: %v", i, fmtErrs(result))
|
||||
continue
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
value := make([]bool, tc.items)
|
||||
result := MaxItems(context.Background(), operation.Operation{}, field.NewPath("fldpath"), value, nil, tc.max)
|
||||
if len(result) > 0 && tc.err == "" {
|
||||
t.Errorf("unexpected failure: %v", fmtErrs(result))
|
||||
return
|
||||
}
|
||||
if re := regexp.MustCompile(tc.err); !re.MatchString(result[0].Error()) {
|
||||
t.Errorf("case %d: wrong error\nexpected: %q\n got: %v", i, tc.err, fmtErrs(result))
|
||||
if len(result) == 0 && tc.err != "" {
|
||||
t.Errorf("unexpected success: expected %q", tc.err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(result) > 0 {
|
||||
if len(result) > 1 {
|
||||
t.Errorf("unexepected multi-error: %v", fmtErrs(result))
|
||||
return
|
||||
}
|
||||
if re := regexp.MustCompile(tc.err); !re.MatchString(result[0].Error()) {
|
||||
t.Errorf("wrong error\nexpected: %q\n got: %v", tc.err, fmtErrs(result))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,10 +83,10 @@ func (mitv maxItemsTagValidator) Docs() TagDoc {
|
||||
return TagDoc{
|
||||
Tag: mitv.TagName(),
|
||||
Scopes: mitv.ValidScopes().UnsortedList(),
|
||||
Description: "Indicates that a list field has a limit on its size.",
|
||||
Description: "Indicates that a list has a limit on its size.",
|
||||
Payloads: []TagPayloadDoc{{
|
||||
Description: "<non-negative integer>",
|
||||
Docs: "This field must be no more than X items long.",
|
||||
Docs: "This list must be no more than X items long.",
|
||||
}},
|
||||
PayloadsType: codetags.ValueTypeInt,
|
||||
PayloadsRequired: true,
|
||||
|
||||
Reference in New Issue
Block a user