feat: migrate DeviceClaim.Requests uniqueness to declarative validation

This change migrates the validation for unique device request names
for the DeviceClaim.Requests field to a declarative format.

The `+k8s:unique=map` and `+k8s:listMapKey=name` tags have been added
to the `Requests` field within the `DeviceClaim` API type. This ensures
the generated validation code enforces that all entries in the `requests`
slice have a unique `name`.
This commit is contained in:
yongruilin
2025-10-09 04:48:51 +00:00
parent 28c655e79b
commit ca9e09b7d3
10 changed files with 28 additions and 4 deletions

View File

@@ -219,8 +219,10 @@ func Validate_DeviceClaim(ctx context.Context, op operation.Operation, fldPath *
if earlyReturn {
return // do not proceed
}
// lists with map semantics require unique keys
errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a resourcev1.DeviceRequest, b resourcev1.DeviceRequest) bool { return a.Name == b.Name })...)
// iterate the list and call the type's validation function
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_DeviceRequest)...)
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, func(a resourcev1.DeviceRequest, b resourcev1.DeviceRequest) bool { return a.Name == b.Name }, validate.SemanticDeepEqual, Validate_DeviceRequest)...)
return
}(fldPath.Child("requests"), obj.Requests, safe.Field(oldObj, func(oldObj *resourcev1.DeviceClaim) []resourcev1.DeviceRequest { return oldObj.Requests }))...)

View File

@@ -221,8 +221,10 @@ func Validate_DeviceClaim(ctx context.Context, op operation.Operation, fldPath *
if earlyReturn {
return // do not proceed
}
// lists with map semantics require unique keys
errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a resourcev1beta1.DeviceRequest, b resourcev1beta1.DeviceRequest) bool { return a.Name == b.Name })...)
// iterate the list and call the type's validation function
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_DeviceRequest)...)
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, func(a resourcev1beta1.DeviceRequest, b resourcev1beta1.DeviceRequest) bool { return a.Name == b.Name }, validate.SemanticDeepEqual, Validate_DeviceRequest)...)
return
}(fldPath.Child("requests"), obj.Requests, safe.Field(oldObj, func(oldObj *resourcev1beta1.DeviceClaim) []resourcev1beta1.DeviceRequest { return oldObj.Requests }))...)

View File

@@ -221,8 +221,10 @@ func Validate_DeviceClaim(ctx context.Context, op operation.Operation, fldPath *
if earlyReturn {
return // do not proceed
}
// lists with map semantics require unique keys
errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a resourcev1beta2.DeviceRequest, b resourcev1beta2.DeviceRequest) bool { return a.Name == b.Name })...)
// iterate the list and call the type's validation function
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_DeviceRequest)...)
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, func(a resourcev1beta2.DeviceRequest, b resourcev1beta2.DeviceRequest) bool { return a.Name == b.Name }, validate.SemanticDeepEqual, Validate_DeviceRequest)...)
return
}(fldPath.Child("requests"), obj.Requests, safe.Field(oldObj, func(oldObj *resourcev1beta2.DeviceClaim) []resourcev1beta2.DeviceRequest { return oldObj.Requests }))...)

View File

@@ -129,7 +129,7 @@ func validateDeviceClaim(deviceClaim *resource.DeviceClaim, fldPath *field.Path,
func(request resource.DeviceRequest) string {
return request.Name
},
fldPath.Child("requests"), sizeCovered)...)
fldPath.Child("requests"), sizeCovered, uniquenessCovered)...)
allErrs = append(allErrs, validateSlice(deviceClaim.Constraints, resource.DeviceConstraintsMaxSize,
func(constraint resource.DeviceConstraint, fldPath *field.Path) field.ErrorList {
return validateDeviceConstraint(constraint, fldPath, requestNames)

View File

@@ -562,6 +562,9 @@ message DeviceClaim {
//
// +optional
// +listType=atomic
// +k8s:listType=atomic
// +k8s:unique=map
// +k8s:listMapKey=name
// +k8s:maxItems=32
repeated DeviceRequest requests = 1;

View File

@@ -725,6 +725,9 @@ type DeviceClaim struct {
//
// +optional
// +listType=atomic
// +k8s:listType=atomic
// +k8s:unique=map
// +k8s:listMapKey=name
// +k8s:maxItems=32
Requests []DeviceRequest `json:"requests" protobuf:"bytes,1,name=requests"`

View File

@@ -570,6 +570,9 @@ message DeviceClaim {
//
// +optional
// +listType=atomic
// +k8s:listType=atomic
// +k8s:unique=map
// +k8s:listMapKey=name
// +k8s:maxItems=32
repeated DeviceRequest requests = 1;

View File

@@ -729,6 +729,9 @@ type DeviceClaim struct {
//
// +optional
// +listType=atomic
// +k8s:listType=atomic
// +k8s:unique=map
// +k8s:listMapKey=name
// +k8s:maxItems=32
Requests []DeviceRequest `json:"requests" protobuf:"bytes,1,name=requests"`

View File

@@ -562,6 +562,9 @@ message DeviceClaim {
//
// +optional
// +listType=atomic
// +k8s:listType=atomic
// +k8s:unique=map
// +k8s:listMapKey=name
// +k8s:maxItems=32
repeated DeviceRequest requests = 1;

View File

@@ -725,6 +725,9 @@ type DeviceClaim struct {
//
// +optional
// +listType=atomic
// +k8s:listType=atomic
// +k8s:unique=map
// +k8s:listMapKey=name
// +k8s:maxItems=32
Requests []DeviceRequest `json:"requests" protobuf:"bytes,1,name=requests"`