From b396cd6f8ffbe07bf6a23b259b3063dec496dfe9 Mon Sep 17 00:00:00 2001 From: Ian Chakeres Date: Sun, 29 Oct 2017 07:09:00 -0700 Subject: [PATCH] Validate that PersistentVolumeSource is not changed during PV Update. --- pkg/api/validation/validation.go | 6 +++ pkg/api/validation/validation_test.go | 61 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 1de41a9024..6ab5178857 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -1554,6 +1554,12 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList { func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) field.ErrorList { allErrs := field.ErrorList{} allErrs = ValidatePersistentVolume(newPv) + + // PersistentVolumeSource should be immutable after creation. + if !apiequality.Semantic.DeepEqual(newPv.Spec.PersistentVolumeSource, oldPv.Spec.PersistentVolumeSource) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "persistentvolumesource"), "is immutable after creation")) + } + newPv.Status = oldPv.Status return allErrs } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 6f2a523544..224651cdc9 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -349,6 +349,67 @@ func TestValidatePersistentVolumes(t *testing.T) { } +func TestValidatePersistentVolumeSourceUpdate(t *testing.T) { + validVolume := testVolume("foo", "", api.PersistentVolumeSpec{ + Capacity: api.ResourceList{ + api.ResourceName(api.ResourceStorage): resource.MustParse("1G"), + }, + AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, + PersistentVolumeSource: api.PersistentVolumeSource{ + HostPath: &api.HostPathVolumeSource{ + Path: "/foo", + Type: newHostPathType(string(api.HostPathDirectory)), + }, + }, + StorageClassName: "valid", + }) + validPvSourceNoUpdate := validVolume.DeepCopy() + invalidPvSourceUpdateType := validVolume.DeepCopy() + invalidPvSourceUpdateType.Spec.PersistentVolumeSource = api.PersistentVolumeSource{ + FlexVolume: &api.FlexVolumeSource{ + Driver: "kubernetes.io/blue", + FSType: "ext4", + }, + } + invalidPvSourceUpdateDeep := validVolume.DeepCopy() + invalidPvSourceUpdateDeep.Spec.PersistentVolumeSource = api.PersistentVolumeSource{ + HostPath: &api.HostPathVolumeSource{ + Path: "/updated", + Type: newHostPathType(string(api.HostPathDirectory)), + }, + } + scenarios := map[string]struct { + isExpectedFailure bool + oldVolume *api.PersistentVolume + newVolume *api.PersistentVolume + }{ + "condition-no-update": { + isExpectedFailure: false, + oldVolume: validVolume, + newVolume: validPvSourceNoUpdate, + }, + "condition-update-source-type": { + isExpectedFailure: true, + oldVolume: validVolume, + newVolume: invalidPvSourceUpdateType, + }, + "condition-update-source-deep": { + isExpectedFailure: true, + oldVolume: validVolume, + newVolume: invalidPvSourceUpdateDeep, + }, + } + for name, scenario := range scenarios { + errs := ValidatePersistentVolumeUpdate(scenario.newVolume, scenario.oldVolume) + if len(errs) == 0 && scenario.isExpectedFailure { + t.Errorf("Unexpected success for scenario: %s", name) + } + if len(errs) > 0 && !scenario.isExpectedFailure { + t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs) + } + } +} + func TestValidateLocalVolumes(t *testing.T) { scenarios := map[string]struct { isExpectedFailure bool