diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go index 7cef78b8f3..c2b429ccb5 100644 --- a/pkg/apis/core/types.go +++ b/pkg/apis/core/types.go @@ -1540,6 +1540,12 @@ type VolumeMount struct { type MountPropagationMode string const ( + // MountPropagationNone means that the volume in a container will + // not receive new mounts from the host or other containers, and filesystems + // mounted inside the container won't be propagated to the host or other + // containers. + // Note that this mode corresponds to "private" in Linux terminology. + MountPropagationNone MountPropagationMode = "None" // MountPropagationHostToContainer means that the volume in a container will // receive new mounts from the host or other containers, but filesystems // mounted inside the container won't be propagated to the host or other diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index fd3d63a348..006bae7bdf 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -1140,7 +1140,7 @@ func validateMountPropagation(mountPropagation *core.MountPropagationMode, conta return allErrs } - supportedMountPropagations := sets.NewString(string(core.MountPropagationBidirectional), string(core.MountPropagationHostToContainer)) + supportedMountPropagations := sets.NewString(string(core.MountPropagationBidirectional), string(core.MountPropagationHostToContainer), string(core.MountPropagationNone)) if !supportedMountPropagations.Has(string(*mountPropagation)) { allErrs = append(allErrs, field.NotSupported(fldPath, *mountPropagation, supportedMountPropagations.List())) } diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 2fac66f74a..fabd63a72f 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -4704,6 +4704,7 @@ func TestValidateMountPropagation(t *testing.T) { propagationBidirectional := core.MountPropagationBidirectional propagationHostToContainer := core.MountPropagationHostToContainer + propagationNone := core.MountPropagationNone propagationInvalid := core.MountPropagationMode("invalid") tests := []struct { @@ -4723,6 +4724,12 @@ func TestValidateMountPropagation(t *testing.T) { defaultContainer, false, }, + { + // non-privileged container + None + core.VolumeMount{Name: "foo", MountPath: "/foo", MountPropagation: &propagationNone}, + defaultContainer, + false, + }, { // error: implicitly non-privileged container + Bidirectional core.VolumeMount{Name: "foo", MountPath: "/foo", MountPropagation: &propagationBidirectional}, diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index e5cd102651..6411848fe2 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -269,12 +269,14 @@ func translateMountPropagation(mountMode *v1.MountPropagationMode) (runtimeapi.M } switch { case mountMode == nil: - // HostToContainer is the default - return runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, nil + // PRIVATE is the default + return runtimeapi.MountPropagation_PROPAGATION_PRIVATE, nil case *mountMode == v1.MountPropagationHostToContainer: return runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, nil case *mountMode == v1.MountPropagationBidirectional: return runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL, nil + case *mountMode == v1.MountPropagationNone: + return runtimeapi.MountPropagation_PROPAGATION_PRIVATE, nil default: return 0, fmt.Errorf("invalid MountPropagation mode: %q", mountMode) } diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go index 3f2a00870e..0dba688b8e 100644 --- a/pkg/kubelet/kubelet_pods_test.go +++ b/pkg/kubelet/kubelet_pods_test.go @@ -55,6 +55,7 @@ func TestMakeMounts(t *testing.T) { bTrue := true propagationHostToContainer := v1.MountPropagationHostToContainer propagationBidirectional := v1.MountPropagationBidirectional + propagationNone := v1.MountPropagationNone testCases := map[string]struct { container v1.Container @@ -79,9 +80,10 @@ func TestMakeMounts(t *testing.T) { MountPropagation: &propagationHostToContainer, }, { - MountPath: "/mnt/path3", - Name: "disk", - ReadOnly: true, + MountPath: "/mnt/path3", + Name: "disk", + ReadOnly: true, + MountPropagation: &propagationNone, }, { MountPath: "/mnt/path4", @@ -110,7 +112,7 @@ func TestMakeMounts(t *testing.T) { HostPath: "/mnt/disk", ReadOnly: true, SELinuxRelabel: false, - Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE, }, { Name: "disk4", @@ -118,7 +120,7 @@ func TestMakeMounts(t *testing.T) { HostPath: "/mnt/host", ReadOnly: false, SELinuxRelabel: false, - Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE, }, { Name: "disk5", @@ -126,7 +128,7 @@ func TestMakeMounts(t *testing.T) { HostPath: "/var/lib/kubelet/podID/volumes/empty/disk5", ReadOnly: false, SELinuxRelabel: false, - Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE, }, }, expectErr: false, @@ -185,7 +187,7 @@ func TestMakeMounts(t *testing.T) { HostPath: "/mnt/host", ReadOnly: false, SELinuxRelabel: false, - Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE, }, }, expectErr: false, diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index 90f012d50a..73f35c8117 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -1624,6 +1624,12 @@ type VolumeMount struct { type MountPropagationMode string const ( + // MountPropagationNone means that the volume in a container will + // not receive new mounts from the host or other containers, and filesystems + // mounted inside the container won't be propagated to the host or other + // containers. + // Note that this mode corresponds to "private" in Linux terminology. + MountPropagationNone MountPropagationMode = "None" // MountPropagationHostToContainer means that the volume in a container will // receive new mounts from the host or other containers, but filesystems // mounted inside the container won't be propagated to the host or other diff --git a/test/e2e/node/mount_propagation.go b/test/e2e/node/mount_propagation.go index e9c1c06d9d..776603a9e5 100644 --- a/test/e2e/node/mount_propagation.go +++ b/test/e2e/node/mount_propagation.go @@ -28,7 +28,7 @@ import ( . "github.com/onsi/gomega" ) -func preparePod(name string, node *v1.Node, propagation v1.MountPropagationMode, hostDir string) *v1.Pod { +func preparePod(name string, node *v1.Node, propagation *v1.MountPropagationMode, hostDir string) *v1.Pod { const containerName = "cntr" bTrue := true var oneSecond int64 = 1 @@ -49,7 +49,7 @@ func preparePod(name string, node *v1.Node, propagation v1.MountPropagationMode, { Name: "host", MountPath: "/mnt/test", - MountPropagation: &propagation, + MountPropagation: propagation, }, }, SecurityContext: &v1.SecurityContext{ @@ -105,12 +105,19 @@ var _ = SIGDescribe("Mount propagation", func() { }() podClient := f.PodClient() - master := podClient.CreateSync(preparePod("master", node, v1.MountPropagationBidirectional, hostDir)) - slave := podClient.CreateSync(preparePod("slave", node, v1.MountPropagationHostToContainer, hostDir)) + bidirectional := v1.MountPropagationBidirectional + master := podClient.CreateSync(preparePod("master", node, &bidirectional, hostDir)) + + hostToContainer := v1.MountPropagationHostToContainer + slave := podClient.CreateSync(preparePod("slave", node, &hostToContainer, hostDir)) + + none := v1.MountPropagationNone + private := podClient.CreateSync(preparePod("private", node, &none, hostDir)) + defaultPropagation := podClient.CreateSync(preparePod("default", node, nil, hostDir)) // Check that the pods sees directories of each other. This just checks // that they have the same HostPath, not the mount propagation. - podNames := []string{master.Name, slave.Name} + podNames := []string{master.Name, slave.Name, private.Name, defaultPropagation.Name} for _, podName := range podNames { for _, dirName := range podNames { cmd := fmt.Sprintf("test -d /mnt/test/%s", dirName) @@ -147,6 +154,10 @@ var _ = SIGDescribe("Mount propagation", func() { "master": sets.NewString("master", "host"), // Slave sees master's mount + itself. "slave": sets.NewString("master", "slave", "host"), + // Private sees only its own mount + "private": sets.NewString("private"), + // Default (=private) sees only its own mount + "default": sets.NewString("default"), } dirNames := append(podNames, "host") for podName, mounts := range expectedMounts {