diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 9e9f5cf4c4c..8b180554263 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -1147,6 +1147,12 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList { if numVolumes == 0 { allErrs = append(allErrs, field.Required(specPath, "must specify a volume type")) } + + // do not allow hostPath mounts of '/' to have a 'recycle' reclaim policy + if pv.Spec.HostPath != nil && path.Clean(pv.Spec.HostPath.Path) == "/" && pv.Spec.PersistentVolumeReclaimPolicy == api.PersistentVolumeReclaimRecycle { + allErrs = append(allErrs, field.Forbidden(specPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'")) + } + return allErrs } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 334c851c846..5032120b3e1 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -549,6 +549,32 @@ func TestValidatePersistentVolumes(t *testing.T) { }, }), }, + "host mount of / with recycle reclaim policy": { + isExpectedFailure: true, + volume: testVolume("bad-recycle-do-not-want", "", api.PersistentVolumeSpec{ + Capacity: api.ResourceList{ + api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), + }, + AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, + PersistentVolumeSource: api.PersistentVolumeSource{ + HostPath: &api.HostPathVolumeSource{Path: "/"}, + }, + PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle, + }), + }, + "host mount of / with recycle reclaim policy 2": { + isExpectedFailure: true, + volume: testVolume("bad-recycle-do-not-want", "", api.PersistentVolumeSpec{ + Capacity: api.ResourceList{ + api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), + }, + AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, + PersistentVolumeSource: api.PersistentVolumeSource{ + HostPath: &api.HostPathVolumeSource{Path: "/a/.."}, + }, + PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle, + }), + }, } for name, scenario := range scenarios {