Graduate image volume sources to beta

Graduate the feature to beta, by:

- Allowing `subPath`/`subPathExpr` for image volumes
- Modifying the CRI to pass down the (resolved) sub path
- Adding metrics which are outlined in the KEP

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
This commit is contained in:
Sascha Grunert
2025-02-13 12:18:57 +01:00
parent e9a3d99f37
commit f9e5dd84ad
23 changed files with 770 additions and 518 deletions

View File

@@ -220,7 +220,7 @@ type VolumeSource struct {
// The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
// The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
// The volume will be mounted read-only (ro) and non-executable files (noexec).
// Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath).
// Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
// The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
// +featureGate=ImageVolume
// +optional

View File

@@ -2946,16 +2946,6 @@ func ValidateVolumeMounts(mounts []core.VolumeMount, voldevices map[string]strin
allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must not already exist as a path in volumeDevices"))
}
// Disallow subPath/subPathExpr for image volumes
if v, ok := volumes[mnt.Name]; ok && v.Image != nil {
if len(mnt.SubPath) != 0 {
allErrs = append(allErrs, field.Invalid(idxPath.Child("subPath"), mnt.SubPath, "not allowed in image volume sources"))
}
if len(mnt.SubPathExpr) != 0 {
allErrs = append(allErrs, field.Invalid(idxPath.Child("subPathExpr"), mnt.SubPathExpr, "not allowed in image volume sources"))
}
}
if len(mnt.SubPath) > 0 {
allErrs = append(allErrs, validateLocalDescendingPath(mnt.SubPath, fldPath.Child("subPath"))...)
}

View File

@@ -7137,6 +7137,8 @@ func TestValidateVolumeMounts(t *testing.T) {
{Name: "123", MountPath: "/rro-enabled", ReadOnly: true, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyEnabled)},
{Name: "123", MountPath: "/rro-enabled-2", ReadOnly: true, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyEnabled), MountPropagation: ptr.To(core.MountPropagationNone)},
{Name: "image-volume", MountPath: "/image-volume"},
{Name: "image-volume", MountPath: "/image-volume-1", SubPath: "foo"},
{Name: "image-volume", MountPath: "/image-volume-2", SubPathExpr: "$(POD_NAME)"},
}
goodVolumeDevices := []core.VolumeDevice{
{Name: "xyz", DevicePath: "/foofoo"},
@@ -7147,23 +7149,22 @@ func TestValidateVolumeMounts(t *testing.T) {
}
errorCases := map[string][]core.VolumeMount{
"empty name": {{Name: "", MountPath: "/foo"}},
"name not found": {{Name: "", MountPath: "/foo"}},
"empty mountpath": {{Name: "abc", MountPath: ""}},
"mountpath collision": {{Name: "foo", MountPath: "/path/a"}, {Name: "bar", MountPath: "/path/a"}},
"absolute subpath": {{Name: "abc", MountPath: "/bar", SubPath: "/baz"}},
"subpath in ..": {{Name: "abc", MountPath: "/bar", SubPath: "../baz"}},
"subpath contains ..": {{Name: "abc", MountPath: "/bar", SubPath: "baz/../bat"}},
"subpath ends in ..": {{Name: "abc", MountPath: "/bar", SubPath: "./.."}},
"disabled MountPropagation feature gate": {{Name: "abc", MountPath: "/bar", MountPropagation: &propagation}},
"name exists in volumeDevice": {{Name: "xyz", MountPath: "/bar"}},
"mountpath exists in volumeDevice": {{Name: "uvw", MountPath: "/mnt/exists"}},
"both exist in volumeDevice": {{Name: "xyz", MountPath: "/mnt/exists"}},
"rro but not ro": {{Name: "123", MountPath: "/rro-bad1", ReadOnly: false, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyEnabled)}},
"rro with incompatible propagation": {{Name: "123", MountPath: "/rro-bad2", ReadOnly: true, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyEnabled), MountPropagation: ptr.To(core.MountPropagationHostToContainer)}},
"rro-if-possible but not ro": {{Name: "123", MountPath: "/rro-bad1", ReadOnly: false, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyIfPossible)}},
"subPath not allowed for image volume sources": {{Name: "image-volume", MountPath: "/image-volume-err-1", SubPath: "/foo"}},
"subPathExpr not allowed for image volume sources": {{Name: "image-volume", MountPath: "/image-volume-err-2", SubPathExpr: "$(POD_NAME)"}},
"empty name": {{Name: "", MountPath: "/foo"}},
"name not found": {{Name: "", MountPath: "/foo"}},
"empty mountpath": {{Name: "abc", MountPath: ""}},
"mountpath collision": {{Name: "foo", MountPath: "/path/a"}, {Name: "bar", MountPath: "/path/a"}},
"absolute subpath": {{Name: "abc", MountPath: "/bar", SubPath: "/baz"}},
"subpath in ..": {{Name: "abc", MountPath: "/bar", SubPath: "../baz"}},
"subpath contains ..": {{Name: "abc", MountPath: "/bar", SubPath: "baz/../bat"}},
"subpath ends in ..": {{Name: "abc", MountPath: "/bar", SubPath: "./.."}},
"disabled MountPropagation feature gate": {{Name: "abc", MountPath: "/bar", MountPropagation: &propagation}},
"name exists in volumeDevice": {{Name: "xyz", MountPath: "/bar"}},
"mountpath exists in volumeDevice": {{Name: "uvw", MountPath: "/mnt/exists"}},
"both exist in volumeDevice": {{Name: "xyz", MountPath: "/mnt/exists"}},
"rro but not ro": {{Name: "123", MountPath: "/rro-bad1", ReadOnly: false, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyEnabled)}},
"rro with incompatible propagation": {{Name: "123", MountPath: "/rro-bad2", ReadOnly: true, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyEnabled), MountPropagation: ptr.To(core.MountPropagationHostToContainer)}},
"rro-if-possible but not ro": {{Name: "123", MountPath: "/rro-bad1", ReadOnly: false, RecursiveReadOnly: ptr.To(core.RecursiveReadOnlyIfPossible)}},
"subPath for image volume sources should be relative": {{Name: "image-volume", MountPath: "/image-volume-err-1", SubPath: "/foo"}},
}
badVolumeDevice := []core.VolumeDevice{
{Name: "xyz", DevicePath: "/mnt/exists"},