diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index f29e04e58da..895c5600080 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -1638,6 +1638,10 @@ var allowedPVCTemplateObjectMetaFields = map[string]bool{ "Labels": true, } +// PersistentVolumeSpecValidationOptions contains the different settings for PeristentVolume validation +type PersistentVolumeSpecValidationOptions struct { +} + // ValidatePersistentVolumeName checks that a name is appropriate for a // PersistentVolumeName object. var ValidatePersistentVolumeName = apimachineryvalidation.NameIsDNSSubdomain @@ -1648,7 +1652,11 @@ var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimD var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem)) -func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path) field.ErrorList { +func ValidationOptionsForPersistentVolume(pv, oldPv *core.PersistentVolume) PersistentVolumeSpecValidationOptions { + return PersistentVolumeSpecValidationOptions{} +} + +func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path, opts PersistentVolumeSpecValidationOptions) field.ErrorList { allErrs := field.ErrorList{} if validateInlinePersistentVolumeSpec { @@ -1922,17 +1930,17 @@ func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName stri return allErrs } -func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList { +func ValidatePersistentVolume(pv *core.PersistentVolume, opts PersistentVolumeSpecValidationOptions) field.ErrorList { metaPath := field.NewPath("metadata") allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, metaPath) - allErrs = append(allErrs, ValidatePersistentVolumeSpec(&pv.Spec, pv.ObjectMeta.Name, false, field.NewPath("spec"))...) + allErrs = append(allErrs, ValidatePersistentVolumeSpec(&pv.Spec, pv.ObjectMeta.Name, false, field.NewPath("spec"), opts)...) return allErrs } // ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make. // newPv is updated with fields that cannot be changed. -func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume) field.ErrorList { - allErrs := ValidatePersistentVolume(newPv) +func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume, opts PersistentVolumeSpecValidationOptions) field.ErrorList { + allErrs := ValidatePersistentVolume(newPv, opts) // if oldPV does not have ControllerExpandSecretRef then allow it to be set if (oldPv.Spec.CSI != nil && oldPv.Spec.CSI.ControllerExpandSecretRef == nil) && diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 6f165887391..d98518e7d6f 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -415,7 +415,8 @@ func TestValidatePersistentVolumes(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { - errs := ValidatePersistentVolume(scenario.volume) + opts := ValidationOptionsForPersistentVolume(scenario.volume, nil) + errs := ValidatePersistentVolume(scenario.volume, opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -558,7 +559,8 @@ func TestValidatePersistentVolumeSpec(t *testing.T) { }, } for name, scenario := range scenarios { - errs := ValidatePersistentVolumeSpec(scenario.pvSpec, "", scenario.isInlineSpec, field.NewPath("field")) + opts := PersistentVolumeSpecValidationOptions{} + errs := ValidatePersistentVolumeSpec(scenario.pvSpec, "", scenario.isInlineSpec, field.NewPath("field"), opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -655,7 +657,8 @@ func TestValidatePersistentVolumeSourceUpdate(t *testing.T) { }, } for name, scenario := range scenarios { - errs := ValidatePersistentVolumeUpdate(scenario.newVolume, scenario.oldVolume) + opts := ValidationOptionsForPersistentVolume(scenario.newVolume, scenario.oldVolume) + errs := ValidatePersistentVolumeUpdate(scenario.newVolume, scenario.oldVolume, opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -665,6 +668,14 @@ func TestValidatePersistentVolumeSourceUpdate(t *testing.T) { } } +func TestValidationOptionsForPersistentVolume(t *testing.T) { + expectedValidationOpts := PersistentVolumeSpecValidationOptions{} + opts := ValidationOptionsForPersistentVolume(nil, nil) + if opts != expectedValidationOpts { + t.Errorf("Expected opts: %+v, received: %+v", opts, expectedValidationOpts) + } +} + func getCSIVolumeWithSecret(pv *core.PersistentVolume, secret *core.SecretReference) *core.PersistentVolume { pvCopy := pv.DeepCopy() if secret != nil { @@ -729,7 +740,8 @@ func TestValidateLocalVolumes(t *testing.T) { } for name, scenario := range scenarios { - errs := ValidatePersistentVolume(scenario.volume) + opts := ValidationOptionsForPersistentVolume(scenario.volume, nil) + errs := ValidatePersistentVolume(scenario.volume, opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -808,7 +820,8 @@ func TestValidateVolumeNodeAffinityUpdate(t *testing.T) { } for name, scenario := range scenarios { - errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV) + opts := ValidationOptionsForPersistentVolume(scenario.newPV, scenario.oldPV) + errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV, opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -1393,8 +1406,9 @@ func TestAlphaPVVolumeModeUpdate(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { + opts := ValidationOptionsForPersistentVolume(scenario.newPV, scenario.oldPV) // ensure we have a resource version specified for updates - errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV) + errs := ValidatePersistentVolumeUpdate(scenario.newPV, scenario.oldPV, opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -4337,7 +4351,8 @@ func TestPVVolumeMode(t *testing.T) { "valid nil value": createTestVolModePV(nil), } for k, v := range successCasesPV { - if errs := ValidatePersistentVolume(v); len(errs) != 0 { + opts := ValidationOptionsForPersistentVolume(v, nil) + if errs := ValidatePersistentVolume(v, opts); len(errs) != 0 { t.Errorf("expected success for %s", k) } } @@ -4348,7 +4363,8 @@ func TestPVVolumeMode(t *testing.T) { "empty value": createTestVolModePV(&empty), } for k, v := range errorCasesPV { - if errs := ValidatePersistentVolume(v); len(errs) == 0 { + opts := ValidationOptionsForPersistentVolume(v, nil) + if errs := ValidatePersistentVolume(v, opts); len(errs) == 0 { t.Errorf("expected failure for %s", k) } } diff --git a/pkg/apis/storage/validation/validation.go b/pkg/apis/storage/validation/validation.go index f96c7e33f50..7c6ec5daac6 100644 --- a/pkg/apis/storage/validation/validation.go +++ b/pkg/apis/storage/validation/validation.go @@ -192,7 +192,8 @@ func validateVolumeAttachmentSource(source *storage.VolumeAttachmentSource, fldP allErrs = append(allErrs, field.Required(fldPath.Child("persistentVolumeName"), "must specify non empty persistentVolumeName")) } case source.InlineVolumeSpec != nil: - allErrs = append(allErrs, apivalidation.ValidatePersistentVolumeSpec(source.InlineVolumeSpec, "", true, fldPath.Child("inlineVolumeSpec"))...) + opts := apivalidation.PersistentVolumeSpecValidationOptions{} + allErrs = append(allErrs, apivalidation.ValidatePersistentVolumeSpec(source.InlineVolumeSpec, "", true, fldPath.Child("inlineVolumeSpec"), opts)...) } return allErrs } diff --git a/pkg/registry/core/persistentvolume/strategy.go b/pkg/registry/core/persistentvolume/strategy.go index 6a8f805df4f..89b5a0332fd 100644 --- a/pkg/registry/core/persistentvolume/strategy.go +++ b/pkg/registry/core/persistentvolume/strategy.go @@ -71,7 +71,8 @@ func (persistentvolumeStrategy) PrepareForCreate(ctx context.Context, obj runtim func (persistentvolumeStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { persistentvolume := obj.(*api.PersistentVolume) - errorList := validation.ValidatePersistentVolume(persistentvolume) + opts := validation.ValidationOptionsForPersistentVolume(persistentvolume, nil) + errorList := validation.ValidatePersistentVolume(persistentvolume, opts) return append(errorList, volumevalidation.ValidatePersistentVolume(persistentvolume)...) } @@ -99,9 +100,11 @@ func (persistentvolumeStrategy) PrepareForUpdate(ctx context.Context, obj, old r func (persistentvolumeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newPv := obj.(*api.PersistentVolume) - errorList := validation.ValidatePersistentVolume(newPv) + oldPv := old.(*api.PersistentVolume) + opts := validation.ValidationOptionsForPersistentVolume(newPv, oldPv) + errorList := validation.ValidatePersistentVolume(newPv, opts) errorList = append(errorList, volumevalidation.ValidatePersistentVolume(newPv)...) - return append(errorList, validation.ValidatePersistentVolumeUpdate(newPv, old.(*api.PersistentVolume))...) + return append(errorList, validation.ValidatePersistentVolumeUpdate(newPv, oldPv, opts)...) } // WarningsOnUpdate returns warnings for the given update.