diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 781e9787e8e..d8fb8935ee7 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -416,9 +416,12 @@ func IsMatchedVolume(name string, volumes map[string]core.VolumeSource) bool { return false } -func isMatchedDevice(name string, volumes map[string]core.VolumeSource) (bool, bool) { +// isMatched checks whether the volume with the given name is used by a +// container and if so, if it involves a PVC. +func isMatchedDevice(name string, volumes map[string]core.VolumeSource) (isMatched bool, isPVC bool) { if source, ok := volumes[name]; ok { - if source.PersistentVolumeClaim != nil { + if source.PersistentVolumeClaim != nil || + source.Ephemeral != nil { return true, true } return true, false @@ -2609,9 +2612,9 @@ func ValidateVolumeDevices(devices []core.VolumeDevice, volmounts map[string]str if devicename.Has(devName) { allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "must be unique")) } - // Must be PersistentVolumeClaim volume source + // Must be based on PersistentVolumeClaim (PVC reference or generic ephemeral inline volume) if didMatch && !isPVC { - allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "can only use volume source type of PersistentVolumeClaim for block mode")) + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), devName, "can only use volume source type of PersistentVolumeClaim or Ephemeral for block mode")) } if !didMatch { allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), devName)) diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 76c995ed2fb..4943f2defa3 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -5532,6 +5532,18 @@ func TestValidateVolumeMounts(t *testing.T) { {Name: "abc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim1"}}}, {Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}}, {Name: "123", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}}, + {Name: "ephemeral", VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &core.PersistentVolumeClaimTemplate{ + Spec: core.PersistentVolumeClaimSpec{ + AccessModes: []core.PersistentVolumeAccessMode{ + core.ReadWriteOnce, + }, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), + }, + }, + }, + }}}}, } vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{}) if len(v1err) > 0 { @@ -5554,6 +5566,7 @@ func TestValidateVolumeMounts(t *testing.T) { {Name: "abc-123", MountPath: "G:\\mount", SubPath: ""}, {Name: "abc-123", MountPath: "/bac", SubPath: ".baz"}, {Name: "abc-123", MountPath: "/bad", SubPath: "..baz"}, + {Name: "ephemeral", MountPath: "/foobar"}, } goodVolumeDevices := []core.VolumeDevice{ {Name: "xyz", DevicePath: "/foofoo"}, @@ -5851,6 +5864,18 @@ func TestAlphaValidateVolumeDevices(t *testing.T) { {Name: "abc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim1"}}}, {Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}}, {Name: "def", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}}, + {Name: "ephemeral", VolumeSource: core.VolumeSource{Ephemeral: &core.EphemeralVolumeSource{VolumeClaimTemplate: &core.PersistentVolumeClaimTemplate{ + Spec: core.PersistentVolumeClaimSpec{ + AccessModes: []core.PersistentVolumeAccessMode{ + core.ReadWriteOnce, + }, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), + }, + }, + }, + }}}}, } vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{}) @@ -5862,6 +5887,7 @@ func TestAlphaValidateVolumeDevices(t *testing.T) { successCase := []core.VolumeDevice{ {Name: "abc", DevicePath: "/foo"}, {Name: "abc-123", DevicePath: "/usr/share/test"}, + {Name: "ephemeral", DevicePath: "/disk"}, } goodVolumeMounts := []core.VolumeMount{ {Name: "xyz", MountPath: "/foofoo"}, @@ -5887,7 +5913,7 @@ func TestAlphaValidateVolumeDevices(t *testing.T) { } // Success Cases: - // Validate normal success cases - only PVC volumeSource + // Validate normal success cases - only PVC volumeSource or generic ephemeral volume if errs := ValidateVolumeDevices(successCase, GetVolumeMountMap(goodVolumeMounts), vols, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) }