make PVCs immutable (except volumeName) post-creation
This commit is contained in:
@@ -1022,11 +1022,18 @@ func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) field.ErrorLi
|
|||||||
func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList {
|
func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList {
|
||||||
allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
|
allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
|
||||||
allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...)
|
allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...)
|
||||||
// if a pvc had a bound volume, we should not allow updates to resources or access modes
|
// PVController needs to update PVC.Spec w/ VolumeName.
|
||||||
if len(oldPvc.Spec.VolumeName) != 0 {
|
// Claims are immutable in order to enforce quota, range limits, etc. without gaming the system.
|
||||||
if !api.Semantic.DeepEqual(newPvc.Spec, oldPvc.Spec) {
|
if len(oldPvc.Spec.VolumeName) == 0 {
|
||||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "spec is immutable once a claim has been bound to a volume"))
|
// volumeName changes are allowed once.
|
||||||
}
|
// Reset back to empty string after equality check
|
||||||
|
oldPvc.Spec.VolumeName = newPvc.Spec.VolumeName
|
||||||
|
defer func() { oldPvc.Spec.VolumeName = "" }()
|
||||||
|
}
|
||||||
|
// changes to Spec are not allowed, but updates to label/annotations are OK.
|
||||||
|
// no-op updates pass validation.
|
||||||
|
if !api.Semantic.DeepEqual(newPvc.Spec, oldPvc.Spec) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "field is immutable after creation"))
|
||||||
}
|
}
|
||||||
newPvc.Status = oldPvc.Status
|
newPvc.Status = oldPvc.Status
|
||||||
return allErrs
|
return allErrs
|
||||||
|
@@ -740,11 +740,16 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
|
|||||||
oldClaim *api.PersistentVolumeClaim
|
oldClaim *api.PersistentVolumeClaim
|
||||||
newClaim *api.PersistentVolumeClaim
|
newClaim *api.PersistentVolumeClaim
|
||||||
}{
|
}{
|
||||||
"valid-update": {
|
"valid-update-volumeName-only": {
|
||||||
isExpectedFailure: false,
|
isExpectedFailure: false,
|
||||||
oldClaim: validClaim,
|
oldClaim: validClaim,
|
||||||
newClaim: validUpdateClaim,
|
newClaim: validUpdateClaim,
|
||||||
},
|
},
|
||||||
|
"valid-no-op-update": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validUpdateClaim,
|
||||||
|
newClaim: validUpdateClaim,
|
||||||
|
},
|
||||||
"invalid-update-change-resources-on-bound-claim": {
|
"invalid-update-change-resources-on-bound-claim": {
|
||||||
isExpectedFailure: true,
|
isExpectedFailure: true,
|
||||||
oldClaim: validUpdateClaim,
|
oldClaim: validUpdateClaim,
|
||||||
|
@@ -86,11 +86,7 @@ func TestUpdate(t *testing.T) {
|
|||||||
// updateFunc
|
// updateFunc
|
||||||
func(obj runtime.Object) runtime.Object {
|
func(obj runtime.Object) runtime.Object {
|
||||||
object := obj.(*api.PersistentVolumeClaim)
|
object := obj.(*api.PersistentVolumeClaim)
|
||||||
object.Spec.Resources = api.ResourceRequirements{
|
object.Spec.VolumeName = "onlyVolumeNameUpdateAllowed"
|
||||||
Requests: api.ResourceList{
|
|
||||||
api.ResourceName(api.ResourceStorage): resource.MustParse("20G"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return object
|
return object
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user