Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private mount propagation #62462

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/apis/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/core/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/core/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4704,6 +4704,7 @@ func TestValidateMountPropagation(t *testing.T) {

propagationBidirectional := core.MountPropagationBidirectional
propagationHostToContainer := core.MountPropagationHostToContainer
propagationNone := core.MountPropagationNone
propagationInvalid := core.MountPropagationMode("invalid")

tests := []struct {
Expand All @@ -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},
Expand Down
6 changes: 4 additions & 2 deletions pkg/kubelet/kubelet_pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/kubelet/kubelet_pods_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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",
Expand Down Expand Up @@ -110,23 +112,23 @@ 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",
ContainerPath: "/mnt/path4",
HostPath: "/mnt/host",
ReadOnly: false,
SELinuxRelabel: false,
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
Propagation: runtimeapi.MountPropagation_PROPAGATION_PRIVATE,
},
{
Name: "disk5",
ContainerPath: "/mnt/path5",
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,
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions staging/src/k8s.io/api/core/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 16 additions & 5 deletions test/e2e/node/mount_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down