Skip to content

Commit

Permalink
Merge pull request kubernetes#6269 from ddysher/extend-mount
Browse files Browse the repository at this point in the history
Abstract IsMountPoint and improve FakeMounter
  • Loading branch information
vishh committed Apr 2, 2015
2 parents c627a35 + d62afa8 commit ee98731
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 92 deletions.
17 changes: 17 additions & 0 deletions pkg/util/mount/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,32 @@ func (f *FakeMounter) ResetLog() {
}

func (f *FakeMounter) Mount(source string, target string, fstype string, flags uintptr, data string) error {
f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: target, Type: fstype})
f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: target, Source: source, FSType: fstype})
return nil
}

func (f *FakeMounter) Unmount(target string, flags int) error {
newMountpoints := []MountPoint{}
for _, mp := range f.MountPoints {
if mp.Path != target {
newMountpoints = append(newMountpoints, MountPoint{Device: mp.Device, Path: mp.Path, Type: mp.Type})
}
}
f.MountPoints = newMountpoints
f.Log = append(f.Log, FakeAction{Action: FakeActionUnmount, Target: target})
return nil
}

func (f *FakeMounter) List() ([]MountPoint, error) {
return f.MountPoints, nil
}

func (f *FakeMounter) IsMountPoint(file string) (bool, error) {
for _, mp := range f.MountPoints {
if mp.Path == file {
return true, nil
}
}
return false, nil
}
16 changes: 8 additions & 8 deletions pkg/util/mount/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,15 @@ package mount
type Interface interface {
// Mount wraps syscall.Mount().
Mount(source string, target string, fstype string, flags uintptr, data string) error

// Umount wraps syscall.Mount().
Unmount(target string, flags int) error

// List returns a list of all mounted filesystems. This can be large.
// On some platforms, reading mounts is not guaranteed consistent (i.e.
// it could change between chunked reads). This is guaranteed to be
// consistent.
List() ([]MountPoint, error)
}

// New returns a mount.Interface for the current system.
func New() Interface {
return &Mounter{}
// IsMountPoint determines if a directory is a mountpoint.
IsMountPoint(file string) (bool, error)
}

// This represents a single line in /proc/mounts or /etc/fstab.
Expand All @@ -50,7 +45,12 @@ type MountPoint struct {
Pass int
}

// Examines /proc/mounts to find all other references to the device referenced
// New returns a mount.Interface for the current system.
func New() Interface {
return &Mounter{}
}

// GetMountRefs finds all other references to the device referenced
// by mountPath; returns a list of paths.
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
mps, err := mounter.List()
Expand Down
26 changes: 22 additions & 4 deletions pkg/util/mount/mount_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,24 @@ import (
const FlagBind = syscall.MS_BIND
const FlagReadOnly = syscall.MS_RDONLY

// Mounter implements mount.Interface for linux platform.
type Mounter struct{}

// Wraps syscall.Mount()
// Mount wraps syscall.Mount()
func (mounter *Mounter) Mount(source string, target string, fstype string, flags uintptr, data string) error {
glog.V(5).Infof("Mounting %s %s %s %d %s", source, target, fstype, flags, data)
return syscall.Mount(source, target, fstype, flags, data)
}

// Wraps syscall.Unmount()
// Unmount wraps syscall.Unmount()
func (mounter *Mounter) Unmount(target string, flags int) error {
return syscall.Unmount(target, flags)
}

// How many times to retry for a consistent read of /proc/mounts.
const maxListTries = 3

// List returns a list of all mounted filesystems.
func (*Mounter) List() ([]MountPoint, error) {
hash1, err := readProcMounts(nil)
if err != nil {
Expand All @@ -71,11 +73,27 @@ func (*Mounter) List() ([]MountPoint, error) {
return nil, fmt.Errorf("failed to get a consistent snapshot of /proc/mounts after %d tries", maxListTries)
}

// IsMountPoint determines if a directory is a mountpoint, by comparing the device for the
// directory with the device for it's parent. If they are the same, it's not a mountpoint,
// if they're different, it is.
func (mounter *Mounter) IsMountPoint(file string) (bool, error) {
stat, err := os.Stat(file)
if err != nil {
return false, err
}
rootStat, err := os.Lstat(file + "/..")
if err != nil {
return false, err
}
// If the directory has the same device as parent, then it's not a mountpoint.
return stat.Sys().(*syscall.Stat_t).Dev != rootStat.Sys().(*syscall.Stat_t).Dev, nil
}

// As per the fstab man page.
const expectedNumFieldsPerLine = 6

// Read /proc/mounts and produces a hash of the contents. If the out argument
// is not nil, this fills it with MountPoint structs.
// readProcMounts reads /proc/mounts and produces a hash of the contents. If the out
// argument is not nil, this fills it with MountPoint structs.
func readProcMounts(out *[]MountPoint) (uint32, error) {
file, err := os.Open("/proc/mounts")
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions pkg/util/mount/mount_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ func (mounter *Mounter) Unmount(target string, flags int) error {
func (mounter *Mounter) List() ([]MountPoint, error) {
return []MountPoint{}, nil
}

func (mounter *Mounter) IsMountPoint(file string) (bool, error) {
return false, nil
}
40 changes: 0 additions & 40 deletions pkg/util/mount/mountpoint_unix.go

This file was deleted.

28 changes: 0 additions & 28 deletions pkg/util/mount/mountpoint_unsupported.go

This file was deleted.

4 changes: 2 additions & 2 deletions pkg/volume/empty_dir/empty_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (plugin *emptyDirPlugin) CanSupport(spec *api.Volume) bool {

func (plugin *emptyDirPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference) (volume.Builder, error) {
// Inject real implementations here, test through the internal function.
return plugin.newBuilderInternal(spec, podRef, plugin.mounter, &realMountDetector{})
return plugin.newBuilderInternal(spec, podRef, plugin.mounter, &realMountDetector{plugin.mounter})
}

func (plugin *emptyDirPlugin) newBuilderInternal(spec *api.Volume, podRef *api.ObjectReference, mounter mount.Interface, mountDetector mountDetector) (volume.Builder, error) {
Expand All @@ -107,7 +107,7 @@ func (plugin *emptyDirPlugin) newBuilderInternal(spec *api.Volume, podRef *api.O

func (plugin *emptyDirPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {
// Inject real implementations here, test through the internal function.
return plugin.newCleanerInternal(volName, podUID, plugin.mounter, &realMountDetector{})
return plugin.newCleanerInternal(volName, podUID, plugin.mounter, &realMountDetector{plugin.mounter})
}

func (plugin *emptyDirPlugin) newCleanerInternal(volName string, podUID types.UID, mounter mount.Interface, mountDetector mountDetector) (volume.Cleaner, error) {
Expand Down
6 changes: 4 additions & 2 deletions pkg/volume/empty_dir/empty_dir_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import (
const linuxTmpfsMagic = 0x01021994

// realMountDetector implements mountDetector in terms of syscalls.
type realMountDetector struct{}
type realMountDetector struct {
mounter mount.Interface
}

func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
isMnt, err := mount.IsMountPoint(path)
isMnt, err := m.mounter.IsMountPoint(path)
if err != nil {
return 0, false, fmt.Errorf("IsMountPoint(%q): %v", path, err)
}
Expand Down
6 changes: 5 additions & 1 deletion pkg/volume/empty_dir/empty_dir_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ limitations under the License.

package empty_dir

import "github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"

// realMountDetector pretends to implement mediumer.
type realMountDetector struct{}
type realMountDetector struct {
mounter mount.Interface
}

func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
return mediumUnknown, false, nil
Expand Down
10 changes: 5 additions & 5 deletions pkg/volume/gce_pd/gce_pd.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error {
}

// TODO: handle failed mounts here.
mountpoint, err := mount.IsMountPoint(dir)
mountpoint, err := pd.mounter.IsMountPoint(dir)
glog.V(4).Infof("PersistentDisk set up: %s %v %v", dir, mountpoint, err)
if err != nil && !os.IsNotExist(err) {
return err
Expand Down Expand Up @@ -211,7 +211,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error {
// Perform a bind mount to the full path to allow duplicate mounts of the same PD.
err = pd.mounter.Mount(globalPDPath, dir, "", mount.FlagBind|flags, "")
if err != nil {
mountpoint, mntErr := mount.IsMountPoint(dir)
mountpoint, mntErr := pd.mounter.IsMountPoint(dir)
if mntErr != nil {
glog.Errorf("isMountpoint check failed: %v", mntErr)
return err
Expand All @@ -221,7 +221,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error {
glog.Errorf("Failed to unmount: %v", mntErr)
return err
}
mountpoint, mntErr := mount.IsMountPoint(dir)
mountpoint, mntErr := pd.mounter.IsMountPoint(dir)
if mntErr != nil {
glog.Errorf("isMountpoint check failed: %v", mntErr)
return err
Expand Down Expand Up @@ -262,7 +262,7 @@ func (pd *gcePersistentDisk) TearDown() error {
// Unmounts the bind mount, and detaches the disk only if the PD
// resource was the last reference to that disk on the kubelet.
func (pd *gcePersistentDisk) TearDownAt(dir string) error {
mountpoint, err := mount.IsMountPoint(dir)
mountpoint, err := pd.mounter.IsMountPoint(dir)
if err != nil {
return err
}
Expand All @@ -287,7 +287,7 @@ func (pd *gcePersistentDisk) TearDownAt(dir string) error {
return err
}
}
mountpoint, mntErr := mount.IsMountPoint(dir)
mountpoint, mntErr := pd.mounter.IsMountPoint(dir)
if mntErr != nil {
glog.Errorf("isMountpoint check failed: %v", mntErr)
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/volume/gce_pd/gce_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (util *GCEDiskUtil) AttachAndMountDisk(pd *gcePersistentDisk, globalPDPath
}

// Only mount the PD globally once.
mountpoint, err := mount.IsMountPoint(globalPDPath)
mountpoint, err := pd.mounter.IsMountPoint(globalPDPath)
if err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(globalPDPath, 0750); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion pkg/volume/nfs/nfs_mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,6 @@ func (mounter *nfsMounter) List() ([]mount.MountPoint, error) {
}

func (mounter *nfsMounter) IsMountPoint(dir string) (bool, error) {
return mount.IsMountPoint(dir)
isMounter := mount.New()
return isMounter.IsMountPoint(dir)
}

0 comments on commit ee98731

Please sign in to comment.