feat(validation-gen): migrate ResourceClaimStatus.Allocation NoModify validation to declarative validation

Co-Authored-by: Yongrui Lin <yongrlin@outlook.com>
This commit is contained in:
Aaron Prindle
2025-09-18 20:47:08 +00:00
committed by yongruilin
parent 331ea38769
commit f70142a6a9
12 changed files with 101 additions and 2 deletions

View File

@@ -836,6 +836,10 @@ func Validate_ResourceClaimStatus(ctx context.Context, op operation.Operation, f
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
earlyReturn = true
}
if e := validate.UpdatePointer(ctx, op, fldPath, obj, oldObj, validate.NoModify); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}

View File

@@ -838,6 +838,10 @@ func Validate_ResourceClaimStatus(ctx context.Context, op operation.Operation, f
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
earlyReturn = true
}
if e := validate.UpdatePointer(ctx, op, fldPath, obj, oldObj, validate.NoModify); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}

View File

@@ -858,6 +858,10 @@ func Validate_ResourceClaimStatus(ctx context.Context, op operation.Operation, f
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
earlyReturn = true
}
if e := validate.UpdatePointer(ctx, op, fldPath, obj, oldObj, validate.NoModify); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}

View File

@@ -437,7 +437,7 @@ func validateResourceClaimStatusUpdate(status, oldStatus *resource.ResourceClaim
// in this particular case, must not be validated again because
// validation for new results is tighter than it was before.
if oldStatus.Allocation != nil && status.Allocation != nil {
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(status.Allocation, oldStatus.Allocation, fldPath.Child("allocation"))...)
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(status.Allocation, oldStatus.Allocation, fldPath.Child("allocation")).WithOrigin("update").MarkCoveredByDeclarative()...)
} else if status.Allocation != nil {
allErrs = append(allErrs, validateAllocationResult(status.Allocation, fldPath.Child("allocation"), requestNames, false)...)
}

View File

@@ -1165,7 +1165,7 @@ func TestValidateClaimStatusUpdate(t *testing.T) {
claim := validAllocatedClaim.DeepCopy()
claim.Status.Allocation.Devices.Results[0].Driver += "-2"
return claim.Status.Allocation
}(), "field is immutable")},
}(), "field is immutable").MarkCoveredByDeclarative()},
oldClaim: validAllocatedClaim,
update: func(claim *resource.ResourceClaim) *resource.ResourceClaim {
claim.Status.Allocation.Devices.Results[0].Driver += "-2"

View File

@@ -647,6 +647,53 @@ func TestValidateStatusUpdateForDeclarative(t *testing.T) {
tweakStatusReservedFor(generateResourceClaimReferences(256)...),
),
},
"valid status.allocation unchanged": {
old: mkResourceClaimWithStatus(),
update: mkResourceClaimWithStatus(),
},
"valid status.allocation set from nil": {
old: mkValidResourceClaim(),
update: mkResourceClaimWithStatus(),
},
"valid status.allocation cleared (Unset is allowed)": {
old: mkResourceClaimWithStatus(),
update: mkValidResourceClaim(),
},
"invalid status.allocation changed device (NoModify)": {
old: mkResourceClaimWithStatus(),
update: tweakStatusAllocationDevice(mkResourceClaimWithStatus(), "device-different"),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("status", "allocation"), nil, "field is immutable").WithOrigin("update"),
},
},
"invalid status.allocation changed driver (NoModify)": {
old: mkResourceClaimWithStatus(),
update: tweakStatusAllocationDriver(mkResourceClaimWithStatus(), "different.example.com"),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("status", "allocation"), nil, "field is immutable").WithOrigin("update"),
},
},
"invalid status.allocation changed pool (NoModify)": {
old: mkResourceClaimWithStatus(),
update: tweakStatusAllocationPool(mkResourceClaimWithStatus(), "different-pool"),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("status", "allocation"), nil, "field is immutable").WithOrigin("update"),
},
},
"invalid status.allocation added result (NoModify)": {
old: mkResourceClaimWithStatus(),
update: addStatusAllocationResult(mkResourceClaimWithStatus()),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("status", "allocation"), nil, "field is immutable").WithOrigin("update"),
},
},
"invalid status.allocation removed result (NoModify)": {
old: addStatusAllocationResult(mkResourceClaimWithStatus()),
update: mkResourceClaimWithStatus(),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("status", "allocation"), nil, "field is immutable").WithOrigin("update"),
},
},
}
for k, tc := range testCases {
t.Run(k, func(t *testing.T) {
@@ -849,3 +896,37 @@ func tweakFirstAvailableTolerations(tolerations []resource.DeviceToleration) fun
}
}
}
func tweakStatusAllocationDevice(obj resource.ResourceClaim, device string) resource.ResourceClaim {
if obj.Status.Allocation != nil && len(obj.Status.Allocation.Devices.Results) > 0 {
obj.Status.Allocation.Devices.Results[0].Device = device
}
return obj
}
func tweakStatusAllocationDriver(obj resource.ResourceClaim, driver string) resource.ResourceClaim {
if obj.Status.Allocation != nil && len(obj.Status.Allocation.Devices.Results) > 0 {
obj.Status.Allocation.Devices.Results[0].Driver = driver
}
return obj
}
func tweakStatusAllocationPool(obj resource.ResourceClaim, pool string) resource.ResourceClaim {
if obj.Status.Allocation != nil && len(obj.Status.Allocation.Devices.Results) > 0 {
obj.Status.Allocation.Devices.Results[0].Pool = pool
}
return obj
}
func addStatusAllocationResult(obj resource.ResourceClaim) resource.ResourceClaim {
if obj.Status.Allocation != nil {
obj.Status.Allocation.Devices.Results = append(obj.Status.Allocation.Devices.Results,
resource.DeviceRequestAllocationResult{
Request: "req-0",
Driver: "another.example.com",
Pool: "pool-1",
Device: "device-1",
})
}
return obj
}

View File

@@ -1362,6 +1362,7 @@ message ResourceClaimStatus {
//
// +optional
// +k8s:optional
// +k8s:update=NoModify
optional AllocationResult allocation = 1;
// ReservedFor indicates which entities are currently allowed to use

View File

@@ -1365,6 +1365,7 @@ type ResourceClaimStatus struct {
//
// +optional
// +k8s:optional
// +k8s:update=NoModify
Allocation *AllocationResult `json:"allocation,omitempty" protobuf:"bytes,1,opt,name=allocation"`
// ReservedFor indicates which entities are currently allowed to use

View File

@@ -1376,6 +1376,7 @@ message ResourceClaimStatus {
//
// +optional
// +k8s:optional
// +k8s:update=NoModify
optional AllocationResult allocation = 1;
// ReservedFor indicates which entities are currently allowed to use

View File

@@ -1372,6 +1372,7 @@ type ResourceClaimStatus struct {
//
// +optional
// +k8s:optional
// +k8s:update=NoModify
Allocation *AllocationResult `json:"allocation,omitempty" protobuf:"bytes,1,opt,name=allocation"`
// ReservedFor indicates which entities are currently allowed to use

View File

@@ -1362,6 +1362,7 @@ message ResourceClaimStatus {
//
// +optional
// +k8s:optional
// +k8s:update=NoModify
optional AllocationResult allocation = 1;
// ReservedFor indicates which entities are currently allowed to use

View File

@@ -1365,6 +1365,7 @@ type ResourceClaimStatus struct {
//
// +optional
// +k8s:optional
// +k8s:update=NoModify
Allocation *AllocationResult `json:"allocation,omitempty" protobuf:"bytes,1,opt,name=allocation"`
// ReservedFor indicates which entities are currently allowed to use