Merge pull request #68945 from gnufied/fix-mount-options

Make sure we pass mount options while creating bind mounts
pull/58/head
k8s-ci-robot 2018-10-01 09:27:54 -07:00 committed by GitHub
commit ecfd1a3e56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 162 additions and 40 deletions

View File

@ -83,11 +83,8 @@ func (f *FakeMounter) Mount(source string, target string, fstype string, options
} }
} }
} }
// find 'ro' option
if option == "ro" {
// reuse MountPoint.Opts field to mark mount as readonly // reuse MountPoint.Opts field to mark mount as readonly
opts = append(opts, "ro") opts = append(opts, option)
}
} }
// If target is a symlink, get its absolute path // If target is a symlink, get its absolute path
@ -95,7 +92,6 @@ func (f *FakeMounter) Mount(source string, target string, fstype string, options
if err != nil { if err != nil {
absTarget = target absTarget = target
} }
f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: opts}) f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: opts})
glog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget) glog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget)
f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype}) f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype})

View File

@ -177,7 +177,9 @@ func (plugin *awsElasticBlockStorePlugin) newMounterInternal(spec *volume.Spec,
}, },
fsType: fsType, fsType: fsType,
readOnly: readOnly, readOnly: readOnly,
diskMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host)}, nil diskMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
mountOptions: util.MountOptionFromSpec(spec),
}, nil
} }
func (plugin *awsElasticBlockStorePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { func (plugin *awsElasticBlockStorePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
@ -344,6 +346,7 @@ type awsElasticBlockStoreMounter struct {
readOnly bool readOnly bool
// diskMounter provides the interface that is used to mount the actual block device. // diskMounter provides the interface that is used to mount the actual block device.
diskMounter *mount.SafeFormatAndMount diskMounter *mount.SafeFormatAndMount
mountOptions []string
} }
var _ volume.Mounter = &awsElasticBlockStoreMounter{} var _ volume.Mounter = &awsElasticBlockStoreMounter{}
@ -392,7 +395,8 @@ func (b *awsElasticBlockStoreMounter) SetUpAt(dir string, fsGroup *int64) error
if b.readOnly { if b.readOnly {
options = append(options, "ro") options = append(options, "ro")
} }
err = b.mounter.Mount(globalPDPath, dir, "", options) mountOptions := util.JoinMountOptions(options, b.mountOptions)
err = b.mounter.Mount(globalPDPath, dir, "", mountOptions)
if err != nil { if err != nil {
notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
if mntErr != nil { if mntErr != nil {

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"testing" "testing"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
@ -325,3 +326,53 @@ func TestMounterAndUnmounterTypeAssert(t *testing.T) {
t.Errorf("Volume Unmounter can be type-assert to Mounter") t.Errorf("Volume Unmounter can be type-assert to Mounter")
} }
} }
func TestMountOptions(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("aws-ebs")
if err != nil {
t.Fatalf("can't make a temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/aws-ebs")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pvA",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{},
},
ClaimRef: &v1.ObjectReference{
Name: "claimA",
},
MountOptions: []string{"_netdev"},
},
}
fakeManager := &fakePDManager{}
fakeMounter := &mount.FakeMounter{}
mounter, err := plug.(*awsElasticBlockStorePlugin).newMounterInternal(volume.NewSpecFromPersistentVolume(pv, false), types.UID("poduid"), fakeManager, fakeMounter)
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Errorf("Got a nil Mounter")
}
if err := mounter.SetUp(nil); err != nil {
t.Errorf("Expected success, got: %v", err)
}
mountOptions := fakeMounter.MountPoints[0].Opts
expectedMountOptions := []string{"bind", "_netdev"}
if !reflect.DeepEqual(mountOptions, expectedMountOptions) {
t.Errorf("Expected mount options to be %v got %v", expectedMountOptions, mountOptions)
}
}

View File

@ -148,7 +148,9 @@ func (plugin *cinderPlugin) newMounterInternal(spec *volume.Spec, podUID types.U
}, },
fsType: fsType, fsType: fsType,
readOnly: readOnly, readOnly: readOnly,
blockDeviceMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host)}, nil blockDeviceMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
mountOptions: util.MountOptionFromSpec(spec),
}, nil
} }
func (plugin *cinderPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { func (plugin *cinderPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
@ -288,6 +290,7 @@ type cinderVolumeMounter struct {
fsType string fsType string
readOnly bool readOnly bool
blockDeviceMounter *mount.SafeFormatAndMount blockDeviceMounter *mount.SafeFormatAndMount
mountOptions []string
} }
// cinderPersistentDisk volumes are disk resources provided by C3 // cinderPersistentDisk volumes are disk resources provided by C3
@ -358,8 +361,9 @@ func (b *cinderVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
return err return err
} }
mountOptions := util.JoinMountOptions(options, b.mountOptions)
// Perform a bind mount to the full path to allow duplicate mounts of the same PD. // Perform a bind mount to the full path to allow duplicate mounts of the same PD.
glog.V(4).Infof("Attempting to mount cinder volume %s to %s with options %v", b.pdName, dir, options) glog.V(4).Infof("Attempting to mount cinder volume %s to %s with options %v", b.pdName, dir, mountOptions)
err = b.mounter.Mount(globalPDPath, dir, "", options) err = b.mounter.Mount(globalPDPath, dir, "", options)
if err != nil { if err != nil {
glog.V(4).Infof("Mount failed: %v", err) glog.V(4).Infof("Mount failed: %v", err)

View File

@ -22,6 +22,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
) )
// Abstract interface to disk operations. // Abstract interface to disk operations.
@ -57,7 +58,8 @@ func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mou
if b.readOnly { if b.readOnly {
options = append(options, "ro") options = append(options, "ro")
} }
err = mounter.Mount(globalPDPath, volPath, "", options) mountOptions := util.JoinMountOptions(options, b.mountOptions)
err = mounter.Mount(globalPDPath, volPath, "", mountOptions)
if err != nil { if err != nil {
glog.Errorf("Failed to bind mount: source:%s, target:%s, err:%v", globalPDPath, volPath, err) glog.Errorf("Failed to bind mount: source:%s, target:%s, err:%v", globalPDPath, volPath, err)
noMnt, mntErr := b.mounter.IsLikelyNotMountPoint(volPath) noMnt, mntErr := b.mounter.IsLikelyNotMountPoint(volPath)

View File

@ -145,6 +145,7 @@ func (plugin *fcPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID,
readOnly: readOnly, readOnly: readOnly,
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec}, mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()), deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
mountOptions: []string{},
}, nil }, nil
} }
return &fcDiskMounter{ return &fcDiskMounter{
@ -153,6 +154,7 @@ func (plugin *fcPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID,
readOnly: readOnly, readOnly: readOnly,
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec}, mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
deviceUtil: util.NewDeviceHandler(util.NewIOHandler()), deviceUtil: util.NewDeviceHandler(util.NewIOHandler()),
mountOptions: util.MountOptionFromSpec(spec),
}, nil }, nil
} }
@ -379,6 +381,7 @@ type fcDiskMounter struct {
volumeMode v1.PersistentVolumeMode volumeMode v1.PersistentVolumeMode
mounter *mount.SafeFormatAndMount mounter *mount.SafeFormatAndMount
deviceUtil util.DeviceUtil deviceUtil util.DeviceUtil
mountOptions []string
} }
var _ volume.Mounter = &fcDiskMounter{} var _ volume.Mounter = &fcDiskMounter{}

View File

@ -211,6 +211,7 @@ func (plugin *gcePersistentDiskPlugin) newMounterInternal(spec *volume.Spec, pod
plugin: plugin, plugin: plugin,
MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)), MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)),
}, },
mountOptions: util.MountOptionFromSpec(spec),
readOnly: readOnly}, nil readOnly: readOnly}, nil
} }
@ -330,6 +331,7 @@ type gcePersistentDiskMounter struct {
*gcePersistentDisk *gcePersistentDisk
// Specifies whether the disk will be mounted as read-only. // Specifies whether the disk will be mounted as read-only.
readOnly bool readOnly bool
mountOptions []string
} }
var _ volume.Mounter = &gcePersistentDiskMounter{} var _ volume.Mounter = &gcePersistentDiskMounter{}
@ -381,7 +383,9 @@ func (b *gcePersistentDiskMounter) SetUpAt(dir string, fsGroup *int64) error {
globalPDPath := makeGlobalPDName(b.plugin.host, b.pdName) globalPDPath := makeGlobalPDName(b.plugin.host, b.pdName)
glog.V(4).Infof("attempting to mount %s", dir) glog.V(4).Infof("attempting to mount %s", dir)
err = b.mounter.Mount(globalPDPath, dir, "", options) mountOptions := util.JoinMountOptions(b.mountOptions, options)
err = b.mounter.Mount(globalPDPath, dir, "", mountOptions)
if err != nil { if err != nil {
notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
if mntErr != nil { if mntErr != nil {

View File

@ -241,6 +241,56 @@ func TestPlugin(t *testing.T) {
} }
} }
func TestMountOptions(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("gcepdTest")
if err != nil {
t.Fatalf("can't make a temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/gce-pd")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pvA",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{},
},
ClaimRef: &v1.ObjectReference{
Name: "claimA",
},
MountOptions: []string{"_netdev"},
},
}
fakeManager := &fakePDManager{}
fakeMounter := &mount.FakeMounter{}
mounter, err := plug.(*gcePersistentDiskPlugin).newMounterInternal(volume.NewSpecFromPersistentVolume(pv, false), types.UID("poduid"), fakeManager, fakeMounter)
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Errorf("Got a nil Mounter")
}
if err := mounter.SetUp(nil); err != nil {
t.Errorf("Expected success, got: %v", err)
}
mountOptions := fakeMounter.MountPoints[0].Opts
expectedMountOptions := []string{"_netdev", "bind"}
if !reflect.DeepEqual(mountOptions, expectedMountOptions) {
t.Errorf("Expected mount options to be %v got %v", expectedMountOptions, mountOptions)
}
}
func TestPersistentClaimReadOnlyFlag(t *testing.T) { func TestPersistentClaimReadOnlyFlag(t *testing.T) {
pv := &v1.PersistentVolume{ pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{

View File

@ -114,7 +114,9 @@ func (plugin *photonPersistentDiskPlugin) newMounterInternal(spec *volume.Spec,
plugin: plugin, plugin: plugin,
}, },
fsType: fsType, fsType: fsType,
diskMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host)}, nil diskMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
mountOption: util.MountOptionFromSpec(spec),
}, nil
} }
func (plugin *photonPersistentDiskPlugin) newUnmounterInternal(volName string, podUID types.UID, manager pdManager, mounter mount.Interface) (volume.Unmounter, error) { func (plugin *photonPersistentDiskPlugin) newUnmounterInternal(volName string, podUID types.UID, manager pdManager, mounter mount.Interface) (volume.Unmounter, error) {
@ -177,6 +179,7 @@ type photonPersistentDiskMounter struct {
*photonPersistentDisk *photonPersistentDisk
fsType string fsType string
diskMounter *mount.SafeFormatAndMount diskMounter *mount.SafeFormatAndMount
mountOption []string
} }
func (b *photonPersistentDiskMounter) GetAttributes() volume.Attributes { func (b *photonPersistentDiskMounter) GetAttributes() volume.Attributes {
@ -222,7 +225,8 @@ func (b *photonPersistentDiskMounter) SetUpAt(dir string, fsGroup *int64) error
globalPDPath := makeGlobalPDPath(b.plugin.host, b.pdID) globalPDPath := makeGlobalPDPath(b.plugin.host, b.pdID)
glog.V(4).Infof("attempting to mount %s", dir) glog.V(4).Infof("attempting to mount %s", dir)
err = b.mounter.Mount(globalPDPath, dir, "", options) mountOptions := util.JoinMountOptions(options, b.mountOption)
err = b.mounter.Mount(globalPDPath, dir, "", mountOptions)
if err != nil { if err != nil {
notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
if mntErr != nil { if mntErr != nil {

View File

@ -119,7 +119,9 @@ func (plugin *vsphereVolumePlugin) newMounterInternal(spec *volume.Spec, podUID
MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)), MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)),
}, },
fsType: fsType, fsType: fsType,
diskMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host)}, nil diskMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
mountOptions: util.MountOptionFromSpec(spec),
}, nil
} }
func (plugin *vsphereVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, manager vdManager, mounter mount.Interface) (volume.Unmounter, error) { func (plugin *vsphereVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, manager vdManager, mounter mount.Interface) (volume.Unmounter, error) {
@ -188,6 +190,7 @@ type vsphereVolumeMounter struct {
*vsphereVolume *vsphereVolume
fsType string fsType string
diskMounter *mount.SafeFormatAndMount diskMounter *mount.SafeFormatAndMount
mountOptions []string
} }
func (b *vsphereVolumeMounter) GetAttributes() volume.Attributes { func (b *vsphereVolumeMounter) GetAttributes() volume.Attributes {
@ -233,7 +236,8 @@ func (b *vsphereVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
// Perform a bind mount to the full path to allow duplicate mounts of the same PD. // Perform a bind mount to the full path to allow duplicate mounts of the same PD.
globalPDPath := makeGlobalPDPath(b.plugin.host, b.volPath) globalPDPath := makeGlobalPDPath(b.plugin.host, b.volPath)
err = b.mounter.Mount(globalPDPath, dir, "", options) mountOptions := util.JoinMountOptions(options, b.mountOptions)
err = b.mounter.Mount(globalPDPath, dir, "", mountOptions)
if err != nil { if err != nil {
notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
if mntErr != nil { if mntErr != nil {