mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
admit upgrading storage class of pvc from beta annotation to spec field
This commit is contained in:
parent
4ca2e884ef
commit
285ee41ba7
@ -1796,6 +1796,16 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeCl
|
|||||||
oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName
|
oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if validateStorageClassUpgrade(oldPvcClone.Annotations, newPvcClone.Annotations,
|
||||||
|
oldPvcClone.Spec.StorageClassName, newPvcClone.Spec.StorageClassName) {
|
||||||
|
newPvcClone.Spec.StorageClassName = nil
|
||||||
|
metav1.SetMetaDataAnnotation(&newPvcClone.ObjectMeta, core.BetaStorageClassAnnotation, oldPvcClone.Annotations[core.BetaStorageClassAnnotation])
|
||||||
|
} else {
|
||||||
|
// storageclass annotation should be immutable after creation
|
||||||
|
// TODO: remove Beta when no longer needed
|
||||||
|
allErrs = append(allErrs, ValidateImmutableAnnotation(newPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], oldPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], v1.BetaStorageClassAnnotation, field.NewPath("metadata"))...)
|
||||||
|
}
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
|
||||||
// lets make sure storage values are same.
|
// lets make sure storage values are same.
|
||||||
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
|
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
|
||||||
@ -1820,16 +1830,28 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeCl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// storageclass annotation should be immutable after creation
|
|
||||||
// TODO: remove Beta when no longer needed
|
|
||||||
allErrs = append(allErrs, ValidateImmutableAnnotation(newPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], oldPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], v1.BetaStorageClassAnnotation, field.NewPath("metadata"))...)
|
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...)
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provide an upgrade path from PVC with storage class specified in beta
|
||||||
|
// annotation to storage class specified in attribute. We allow update of
|
||||||
|
// StorageClassName only if following four conditions are met at the same time:
|
||||||
|
// 1. The old pvc's StorageClassAnnotation is set
|
||||||
|
// 2. The old pvc's StorageClassName is not set
|
||||||
|
// 3. The new pvc's StorageClassName is set and equal to the old value in annotation
|
||||||
|
// 4. If the new pvc's StorageClassAnnotation is set,it must be equal to the old pv/pvc's StorageClassAnnotation
|
||||||
|
func validateStorageClassUpgrade(oldAnnotations, newAnnotations map[string]string, oldScName, newScName *string) bool {
|
||||||
|
oldSc, oldAnnotationExist := oldAnnotations[core.BetaStorageClassAnnotation]
|
||||||
|
newScInAnnotation, newAnnotationExist := newAnnotations[core.BetaStorageClassAnnotation]
|
||||||
|
return oldAnnotationExist /* condition 1 */ &&
|
||||||
|
oldScName == nil /* condition 2*/ &&
|
||||||
|
(newScName != nil && *newScName == oldSc) /* condition 3 */ &&
|
||||||
|
(!newAnnotationExist || newScInAnnotation == oldSc) /* condition 4 */
|
||||||
|
}
|
||||||
|
|
||||||
// ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PersistentVolumeClaim
|
// ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PersistentVolumeClaim
|
||||||
func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVolumeClaim) field.ErrorList {
|
func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVolumeClaim) field.ErrorList {
|
||||||
allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
|
allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
|
||||||
|
@ -736,6 +736,29 @@ func testVolumeClaimAnnotation(name string, namespace string, ann string, annval
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testVolumeClaimStorageClassInSpec(name, namespace, scName string, spec core.PersistentVolumeClaimSpec) *core.PersistentVolumeClaim {
|
||||||
|
spec.StorageClassName = &scName
|
||||||
|
return &core.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Spec: spec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testVolumeClaimStorageClassInAnnotationAndSpec(name, namespace, scNameInAnn, scName string, spec core.PersistentVolumeClaimSpec) *core.PersistentVolumeClaim {
|
||||||
|
spec.StorageClassName = &scName
|
||||||
|
return &core.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
Annotations: map[string]string{v1.BetaStorageClassAnnotation: scNameInAnn},
|
||||||
|
},
|
||||||
|
Spec: spec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidatePersistentVolumeClaim(t *testing.T) {
|
func TestValidatePersistentVolumeClaim(t *testing.T) {
|
||||||
invalidClassName := "-invalid-"
|
invalidClassName := "-invalid-"
|
||||||
validClassName := "valid"
|
validClassName := "valid"
|
||||||
@ -1251,6 +1274,52 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
|
|||||||
Phase: core.ClaimPending,
|
Phase: core.ClaimPending,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
validClaimStorageClassInSpec := testVolumeClaimStorageClassInSpec("foo", "ns", "fast", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadOnlyMany,
|
||||||
|
},
|
||||||
|
Resources: core.ResourceRequirements{
|
||||||
|
Requests: core.ResourceList{
|
||||||
|
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
invalidClaimStorageClassInSpec := testVolumeClaimStorageClassInSpec("foo", "ns", "fast2", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadOnlyMany,
|
||||||
|
},
|
||||||
|
Resources: core.ResourceRequirements{
|
||||||
|
Requests: core.ResourceList{
|
||||||
|
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validClaimStorageClassInAnnotationAndSpec := testVolumeClaimStorageClassInAnnotationAndSpec(
|
||||||
|
"foo", "ns", "fast", "fast", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadOnlyMany,
|
||||||
|
},
|
||||||
|
Resources: core.ResourceRequirements{
|
||||||
|
Requests: core.ResourceList{
|
||||||
|
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
invalidClaimStorageClassInAnnotationAndSpec := testVolumeClaimStorageClassInAnnotationAndSpec(
|
||||||
|
"foo", "ns", "fast2", "fast", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadOnlyMany,
|
||||||
|
},
|
||||||
|
Resources: core.ResourceRequirements{
|
||||||
|
Requests: core.ResourceList{
|
||||||
|
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
scenarios := map[string]struct {
|
scenarios := map[string]struct {
|
||||||
isExpectedFailure bool
|
isExpectedFailure bool
|
||||||
oldClaim *core.PersistentVolumeClaim
|
oldClaim *core.PersistentVolumeClaim
|
||||||
@ -1412,6 +1481,48 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
|
|||||||
enableResize: true,
|
enableResize: true,
|
||||||
enableBlock: false,
|
enableBlock: false,
|
||||||
},
|
},
|
||||||
|
"valid-upgrade-storage-class-annotation-to-spec": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaimStorageClass,
|
||||||
|
newClaim: validClaimStorageClassInSpec,
|
||||||
|
enableResize: false,
|
||||||
|
enableBlock: false,
|
||||||
|
},
|
||||||
|
"invalid-upgrade-storage-class-annotation-to-spec": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldClaim: validClaimStorageClass,
|
||||||
|
newClaim: invalidClaimStorageClassInSpec,
|
||||||
|
enableResize: false,
|
||||||
|
enableBlock: false,
|
||||||
|
},
|
||||||
|
"valid-upgrade-storage-class-annotation-to-annotation-and-spec": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaimStorageClass,
|
||||||
|
newClaim: validClaimStorageClassInAnnotationAndSpec,
|
||||||
|
enableResize: false,
|
||||||
|
enableBlock: false,
|
||||||
|
},
|
||||||
|
"invalid-upgrade-storage-class-annotation-to-annotation-and-spec": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldClaim: validClaimStorageClass,
|
||||||
|
newClaim: invalidClaimStorageClassInAnnotationAndSpec,
|
||||||
|
enableResize: false,
|
||||||
|
enableBlock: false,
|
||||||
|
},
|
||||||
|
"invalid-upgrade-storage-class-in-spec": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldClaim: validClaimStorageClassInSpec,
|
||||||
|
newClaim: invalidClaimStorageClassInSpec,
|
||||||
|
enableResize: false,
|
||||||
|
enableBlock: false,
|
||||||
|
},
|
||||||
|
"invalid-downgrade-storage-class-spec-to-annotation": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldClaim: validClaimStorageClassInSpec,
|
||||||
|
newClaim: validClaimStorageClass,
|
||||||
|
enableResize: false,
|
||||||
|
enableBlock: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, scenario := range scenarios {
|
for name, scenario := range scenarios {
|
||||||
|
Loading…
Reference in New Issue
Block a user