From dba8ee229eaa20b80a352be0f3c69b453049a9a5 Mon Sep 17 00:00:00 2001 From: Chris Henzie Date: Tue, 8 Jun 2021 13:30:55 -0700 Subject: [PATCH] Add validation options for PersistentVolumeClaims These options provide an extensible way of configuring how PVCs are validated --- pkg/apis/core/validation/validation.go | 29 ++++++++++---- pkg/apis/core/validation/validation_test.go | 40 +++++++++++++++---- .../core/persistentvolumeclaim/strategy.go | 10 +++-- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 895c5600080..3c1e3e9c5b2 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -1608,16 +1608,17 @@ func validateEphemeralVolumeSource(ephemeral *core.EphemeralVolumeSource, fldPat if ephemeral.VolumeClaimTemplate == nil { allErrs = append(allErrs, field.Required(fldPath.Child("volumeClaimTemplate"), "")) } else { - allErrs = append(allErrs, ValidatePersistentVolumeClaimTemplate(ephemeral.VolumeClaimTemplate, fldPath.Child("volumeClaimTemplate"))...) + opts := ValidationOptionsForPersistentVolumeClaimTemplate(ephemeral.VolumeClaimTemplate, nil) + allErrs = append(allErrs, ValidatePersistentVolumeClaimTemplate(ephemeral.VolumeClaimTemplate, fldPath.Child("volumeClaimTemplate"), opts)...) } return allErrs } // ValidatePersistentVolumeClaimTemplate verifies that the embedded object meta and spec are valid. // Checking of the object data is very minimal because only labels and annotations are used. -func ValidatePersistentVolumeClaimTemplate(claimTemplate *core.PersistentVolumeClaimTemplate, fldPath *field.Path) field.ErrorList { +func ValidatePersistentVolumeClaimTemplate(claimTemplate *core.PersistentVolumeClaimTemplate, fldPath *field.Path, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { allErrs := validatePersistentVolumeClaimTemplateObjectMeta(&claimTemplate.ObjectMeta, fldPath.Child("metadata")) - allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&claimTemplate.Spec, fldPath.Child("spec"))...) + allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&claimTemplate.Spec, fldPath.Child("spec"), opts)...) return allErrs } @@ -1973,15 +1974,27 @@ func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) f return allErrs } +// PersistentVolumeClaimSpecValidationOptions contains the different settings for PersistentVolumeClaim validation +type PersistentVolumeClaimSpecValidationOptions struct { +} + +func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions { + return PersistentVolumeClaimSpecValidationOptions{} +} + +func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTemplate *core.PersistentVolumeClaimTemplate) PersistentVolumeClaimSpecValidationOptions { + return PersistentVolumeClaimSpecValidationOptions{} +} + // ValidatePersistentVolumeClaim validates a PersistentVolumeClaim -func ValidatePersistentVolumeClaim(pvc *core.PersistentVolumeClaim) field.ErrorList { +func ValidatePersistentVolumeClaim(pvc *core.PersistentVolumeClaim, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName, field.NewPath("metadata")) - allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&pvc.Spec, field.NewPath("spec"))...) + allErrs = append(allErrs, ValidatePersistentVolumeClaimSpec(&pvc.Spec, field.NewPath("spec"), opts)...) return allErrs } // ValidatePersistentVolumeClaimSpec validates a PersistentVolumeClaimSpec -func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fldPath *field.Path) field.ErrorList { +func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fldPath *field.Path, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { allErrs := field.ErrorList{} if len(spec.AccessModes) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "at least 1 access mode is required")) @@ -2032,9 +2045,9 @@ func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fld } // ValidatePersistentVolumeClaimUpdate validates an update to a PersistentVolumeClaim -func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeClaim) field.ErrorList { +func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeClaim, opts PersistentVolumeClaimSpecValidationOptions) field.ErrorList { allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata")) - allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...) + allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc, opts)...) newPvcClone := newPvc.DeepCopy() oldPvcClone := oldPvc.DeepCopy() diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index d98518e7d6f..6bacdc76b93 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -922,12 +922,14 @@ func TestAlphaVolumeSnapshotDataSource(t *testing.T) { } for _, tc := range successTestCases { - if errs := ValidatePersistentVolumeClaimSpec(&tc, field.NewPath("spec")); len(errs) != 0 { + opts := PersistentVolumeClaimSpecValidationOptions{} + if errs := ValidatePersistentVolumeClaimSpec(&tc, field.NewPath("spec"), opts); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } for _, tc := range failedTestCases { - if errs := ValidatePersistentVolumeClaimSpec(&tc, field.NewPath("spec")); len(errs) == 0 { + opts := PersistentVolumeClaimSpecValidationOptions{} + if errs := ValidatePersistentVolumeClaimSpec(&tc, field.NewPath("spec"), opts); len(errs) == 0 { t.Errorf("expected failure: %v", errs) } } @@ -1323,7 +1325,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) { opts := PodValidationOptions{} _, errs = ValidateVolumes(volumes, nil, field.NewPath(""), opts) } else { - errs = ValidatePersistentVolumeClaim(scenario.claim) + opts := ValidationOptionsForPersistentVolumeClaim(scenario.claim, nil) + errs = ValidatePersistentVolumeClaim(scenario.claim, opts) } if len(errs) == 0 && scenario.isExpectedFailure { t.Error("Unexpected success for scenario") @@ -1826,7 +1829,8 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, scenario.enableResize)() scenario.oldClaim.ResourceVersion = "1" scenario.newClaim.ResourceVersion = "1" - errs := ValidatePersistentVolumeClaimUpdate(scenario.newClaim, scenario.oldClaim) + opts := ValidationOptionsForPersistentVolumeClaim(scenario.newClaim, scenario.oldClaim) + errs := ValidatePersistentVolumeClaimUpdate(scenario.newClaim, scenario.oldClaim, opts) if len(errs) == 0 && scenario.isExpectedFailure { t.Errorf("Unexpected success for scenario: %s", name) } @@ -1837,6 +1841,22 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) { } } +func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) { + expectedValidationOpts := PersistentVolumeClaimSpecValidationOptions{} + opts := ValidationOptionsForPersistentVolumeClaim(nil, nil) + if opts != expectedValidationOpts { + t.Errorf("Expected opts: %+v, received: %+v", opts, expectedValidationOpts) + } +} + +func TestValidationOptionsForPersistentVolumeClaimTemplate(t *testing.T) { + expectedValidationOpts := PersistentVolumeClaimSpecValidationOptions{} + opts := ValidationOptionsForPersistentVolumeClaimTemplate(nil, nil) + if opts != expectedValidationOpts { + t.Errorf("Expected opts: %+v, received: %+v", opts, expectedValidationOpts) + } +} + func TestValidateKeyToPath(t *testing.T) { testCases := []struct { kp core.KeyToPath @@ -4321,7 +4341,8 @@ func TestPVCVolumeMode(t *testing.T) { "valid nil value": createTestVolModePVC(nil), } for k, v := range successCasesPVC { - if errs := ValidatePersistentVolumeClaim(v); len(errs) != 0 { + opts := ValidationOptionsForPersistentVolumeClaim(v, nil) + if errs := ValidatePersistentVolumeClaim(v, opts); len(errs) != 0 { t.Errorf("expected success for %s", k) } } @@ -4332,7 +4353,8 @@ func TestPVCVolumeMode(t *testing.T) { "empty value": createTestVolModePVC(&empty), } for k, v := range errorCasesPVC { - if errs := ValidatePersistentVolumeClaim(v); len(errs) == 0 { + opts := ValidationOptionsForPersistentVolumeClaim(v, nil) + if errs := ValidatePersistentVolumeClaim(v, opts); len(errs) == 0 { t.Errorf("expected failure for %s", k) } } @@ -16585,12 +16607,14 @@ func TestAlphaVolumePVCDataSource(t *testing.T) { for _, tc := range testCases { if tc.expectedFail { - if errs := ValidatePersistentVolumeClaimSpec(&tc.claimSpec, field.NewPath("spec")); len(errs) == 0 { + opts := PersistentVolumeClaimSpecValidationOptions{} + if errs := ValidatePersistentVolumeClaimSpec(&tc.claimSpec, field.NewPath("spec"), opts); len(errs) == 0 { t.Errorf("expected failure: %v", errs) } } else { - if errs := ValidatePersistentVolumeClaimSpec(&tc.claimSpec, field.NewPath("spec")); len(errs) != 0 { + opts := PersistentVolumeClaimSpecValidationOptions{} + if errs := ValidatePersistentVolumeClaimSpec(&tc.claimSpec, field.NewPath("spec"), opts); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } diff --git a/pkg/registry/core/persistentvolumeclaim/strategy.go b/pkg/registry/core/persistentvolumeclaim/strategy.go index 688db9cd9f8..c8f2025311f 100644 --- a/pkg/registry/core/persistentvolumeclaim/strategy.go +++ b/pkg/registry/core/persistentvolumeclaim/strategy.go @@ -72,7 +72,8 @@ func (persistentvolumeclaimStrategy) PrepareForCreate(ctx context.Context, obj r func (persistentvolumeclaimStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { pvc := obj.(*api.PersistentVolumeClaim) - return validation.ValidatePersistentVolumeClaim(pvc) + opts := validation.ValidationOptionsForPersistentVolumeClaim(pvc, nil) + return validation.ValidatePersistentVolumeClaim(pvc, opts) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -98,8 +99,11 @@ func (persistentvolumeclaimStrategy) PrepareForUpdate(ctx context.Context, obj, } func (persistentvolumeclaimStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - errorList := validation.ValidatePersistentVolumeClaim(obj.(*api.PersistentVolumeClaim)) - return append(errorList, validation.ValidatePersistentVolumeClaimUpdate(obj.(*api.PersistentVolumeClaim), old.(*api.PersistentVolumeClaim))...) + newPvc := obj.(*api.PersistentVolumeClaim) + oldPvc := old.(*api.PersistentVolumeClaim) + opts := validation.ValidationOptionsForPersistentVolumeClaim(newPvc, oldPvc) + errorList := validation.ValidatePersistentVolumeClaim(newPvc, opts) + return append(errorList, validation.ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc, opts)...) } // WarningsOnUpdate returns warnings for the given update.