Commit ee98731a authored by Vish Kannan's avatar Vish Kannan

Merge pull request #6269 from ddysher/extend-mount

Abstract IsMountPoint and improve FakeMounter
parents c627a359 d62afa85
...@@ -39,11 +39,19 @@ func (f *FakeMounter) ResetLog() { ...@@ -39,11 +39,19 @@ func (f *FakeMounter) ResetLog() {
} }
func (f *FakeMounter) Mount(source string, target string, fstype string, flags uintptr, data string) error { 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}) f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: target, Source: source, FSType: fstype})
return nil return nil
} }
func (f *FakeMounter) Unmount(target string, flags int) error { 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}) f.Log = append(f.Log, FakeAction{Action: FakeActionUnmount, Target: target})
return nil return nil
} }
...@@ -51,3 +59,12 @@ func (f *FakeMounter) Unmount(target string, flags int) error { ...@@ -51,3 +59,12 @@ func (f *FakeMounter) Unmount(target string, flags int) error {
func (f *FakeMounter) List() ([]MountPoint, error) { func (f *FakeMounter) List() ([]MountPoint, error) {
return f.MountPoints, nil 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
}
...@@ -24,20 +24,15 @@ package mount ...@@ -24,20 +24,15 @@ package mount
type Interface interface { type Interface interface {
// Mount wraps syscall.Mount(). // Mount wraps syscall.Mount().
Mount(source string, target string, fstype string, flags uintptr, data string) error Mount(source string, target string, fstype string, flags uintptr, data string) error
// Umount wraps syscall.Mount(). // Umount wraps syscall.Mount().
Unmount(target string, flags int) error Unmount(target string, flags int) error
// List returns a list of all mounted filesystems. This can be large. // List returns a list of all mounted filesystems. This can be large.
// On some platforms, reading mounts is not guaranteed consistent (i.e. // On some platforms, reading mounts is not guaranteed consistent (i.e.
// it could change between chunked reads). This is guaranteed to be // it could change between chunked reads). This is guaranteed to be
// consistent. // consistent.
List() ([]MountPoint, error) List() ([]MountPoint, error)
} // IsMountPoint determines if a directory is a mountpoint.
IsMountPoint(file string) (bool, error)
// New returns a mount.Interface for the current system.
func New() Interface {
return &Mounter{}
} }
// This represents a single line in /proc/mounts or /etc/fstab. // This represents a single line in /proc/mounts or /etc/fstab.
...@@ -50,7 +45,12 @@ type MountPoint struct { ...@@ -50,7 +45,12 @@ type MountPoint struct {
Pass int 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. // by mountPath; returns a list of paths.
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) { func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
mps, err := mounter.List() mps, err := mounter.List()
......
...@@ -34,15 +34,16 @@ import ( ...@@ -34,15 +34,16 @@ import (
const FlagBind = syscall.MS_BIND const FlagBind = syscall.MS_BIND
const FlagReadOnly = syscall.MS_RDONLY const FlagReadOnly = syscall.MS_RDONLY
// Mounter implements mount.Interface for linux platform.
type Mounter struct{} 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 { 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) glog.V(5).Infof("Mounting %s %s %s %d %s", source, target, fstype, flags, data)
return syscall.Mount(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 { func (mounter *Mounter) Unmount(target string, flags int) error {
return syscall.Unmount(target, flags) return syscall.Unmount(target, flags)
} }
...@@ -50,6 +51,7 @@ func (mounter *Mounter) Unmount(target string, flags int) error { ...@@ -50,6 +51,7 @@ func (mounter *Mounter) Unmount(target string, flags int) error {
// How many times to retry for a consistent read of /proc/mounts. // How many times to retry for a consistent read of /proc/mounts.
const maxListTries = 3 const maxListTries = 3
// List returns a list of all mounted filesystems.
func (*Mounter) List() ([]MountPoint, error) { func (*Mounter) List() ([]MountPoint, error) {
hash1, err := readProcMounts(nil) hash1, err := readProcMounts(nil)
if err != nil { if err != nil {
...@@ -71,11 +73,27 @@ func (*Mounter) List() ([]MountPoint, error) { ...@@ -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) 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. // As per the fstab man page.
const expectedNumFieldsPerLine = 6 const expectedNumFieldsPerLine = 6
// Read /proc/mounts and produces a hash of the contents. If the out argument // readProcMounts reads /proc/mounts and produces a hash of the contents. If the out
// is not nil, this fills it with MountPoint structs. // argument is not nil, this fills it with MountPoint structs.
func readProcMounts(out *[]MountPoint) (uint32, error) { func readProcMounts(out *[]MountPoint) (uint32, error) {
file, err := os.Open("/proc/mounts") file, err := os.Open("/proc/mounts")
if err != nil { if err != nil {
......
...@@ -34,3 +34,7 @@ func (mounter *Mounter) Unmount(target string, flags int) error { ...@@ -34,3 +34,7 @@ func (mounter *Mounter) Unmount(target string, flags int) error {
func (mounter *Mounter) List() ([]MountPoint, error) { func (mounter *Mounter) List() ([]MountPoint, error) {
return []MountPoint{}, nil return []MountPoint{}, nil
} }
func (mounter *Mounter) IsMountPoint(file string) (bool, error) {
return false, nil
}
// +build !windows
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import (
"os"
"syscall"
)
// Determine 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 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
}
// +build windows
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import (
"fmt"
)
// Dummy implementation for Windows
func IsMountPoint(file string) (bool, error) {
return false, fmt.Errorf("unimplemented")
}
...@@ -82,7 +82,7 @@ func (plugin *emptyDirPlugin) CanSupport(spec *api.Volume) bool { ...@@ -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) { func (plugin *emptyDirPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference) (volume.Builder, error) {
// Inject real implementations here, test through the internal function. // 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) { func (plugin *emptyDirPlugin) newBuilderInternal(spec *api.Volume, podRef *api.ObjectReference, mounter mount.Interface, mountDetector mountDetector) (volume.Builder, error) {
...@@ -107,7 +107,7 @@ func (plugin *emptyDirPlugin) newBuilderInternal(spec *api.Volume, podRef *api.O ...@@ -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) { func (plugin *emptyDirPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {
// Inject real implementations here, test through the internal function. // 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) { func (plugin *emptyDirPlugin) newCleanerInternal(volName string, podUID types.UID, mounter mount.Interface, mountDetector mountDetector) (volume.Cleaner, error) {
......
...@@ -27,10 +27,12 @@ import ( ...@@ -27,10 +27,12 @@ import (
const linuxTmpfsMagic = 0x01021994 const linuxTmpfsMagic = 0x01021994
// realMountDetector implements mountDetector in terms of syscalls. // 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) { func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
isMnt, err := mount.IsMountPoint(path) isMnt, err := m.mounter.IsMountPoint(path)
if err != nil { if err != nil {
return 0, false, fmt.Errorf("IsMountPoint(%q): %v", path, err) return 0, false, fmt.Errorf("IsMountPoint(%q): %v", path, err)
} }
......
...@@ -18,8 +18,12 @@ limitations under the License. ...@@ -18,8 +18,12 @@ limitations under the License.
package empty_dir package empty_dir
import "github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
// realMountDetector pretends to implement mediumer. // realMountDetector pretends to implement mediumer.
type realMountDetector struct{} type realMountDetector struct {
mounter mount.Interface
}
func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) { func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
return mediumUnknown, false, nil return mediumUnknown, false, nil
......
...@@ -183,7 +183,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error { ...@@ -183,7 +183,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error {
} }
// TODO: handle failed mounts here. // 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) glog.V(4).Infof("PersistentDisk set up: %s %v %v", dir, mountpoint, err)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return err
...@@ -211,7 +211,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error { ...@@ -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. // 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, "") err = pd.mounter.Mount(globalPDPath, dir, "", mount.FlagBind|flags, "")
if err != nil { if err != nil {
mountpoint, mntErr := mount.IsMountPoint(dir) mountpoint, mntErr := pd.mounter.IsMountPoint(dir)
if mntErr != nil { if mntErr != nil {
glog.Errorf("isMountpoint check failed: %v", mntErr) glog.Errorf("isMountpoint check failed: %v", mntErr)
return err return err
...@@ -221,7 +221,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error { ...@@ -221,7 +221,7 @@ func (pd *gcePersistentDisk) SetUpAt(dir string) error {
glog.Errorf("Failed to unmount: %v", mntErr) glog.Errorf("Failed to unmount: %v", mntErr)
return err return err
} }
mountpoint, mntErr := mount.IsMountPoint(dir) mountpoint, mntErr := pd.mounter.IsMountPoint(dir)
if mntErr != nil { if mntErr != nil {
glog.Errorf("isMountpoint check failed: %v", mntErr) glog.Errorf("isMountpoint check failed: %v", mntErr)
return err return err
...@@ -262,7 +262,7 @@ func (pd *gcePersistentDisk) TearDown() error { ...@@ -262,7 +262,7 @@ func (pd *gcePersistentDisk) TearDown() error {
// Unmounts the bind mount, and detaches the disk only if the PD // Unmounts the bind mount, and detaches the disk only if the PD
// resource was the last reference to that disk on the kubelet. // resource was the last reference to that disk on the kubelet.
func (pd *gcePersistentDisk) TearDownAt(dir string) error { func (pd *gcePersistentDisk) TearDownAt(dir string) error {
mountpoint, err := mount.IsMountPoint(dir) mountpoint, err := pd.mounter.IsMountPoint(dir)
if err != nil { if err != nil {
return err return err
} }
...@@ -287,7 +287,7 @@ func (pd *gcePersistentDisk) TearDownAt(dir string) error { ...@@ -287,7 +287,7 @@ func (pd *gcePersistentDisk) TearDownAt(dir string) error {
return err return err
} }
} }
mountpoint, mntErr := mount.IsMountPoint(dir) mountpoint, mntErr := pd.mounter.IsMountPoint(dir)
if mntErr != nil { if mntErr != nil {
glog.Errorf("isMountpoint check failed: %v", mntErr) glog.Errorf("isMountpoint check failed: %v", mntErr)
return err return err
......
...@@ -68,7 +68,7 @@ func (util *GCEDiskUtil) AttachAndMountDisk(pd *gcePersistentDisk, globalPDPath ...@@ -68,7 +68,7 @@ func (util *GCEDiskUtil) AttachAndMountDisk(pd *gcePersistentDisk, globalPDPath
} }
// Only mount the PD globally once. // Only mount the PD globally once.
mountpoint, err := mount.IsMountPoint(globalPDPath) mountpoint, err := pd.mounter.IsMountPoint(globalPDPath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
if err := os.MkdirAll(globalPDPath, 0750); err != nil { if err := os.MkdirAll(globalPDPath, 0750); err != nil {
......
...@@ -67,5 +67,6 @@ func (mounter *nfsMounter) List() ([]mount.MountPoint, error) { ...@@ -67,5 +67,6 @@ func (mounter *nfsMounter) List() ([]mount.MountPoint, error) {
} }
func (mounter *nfsMounter) IsMountPoint(dir string) (bool, error) { func (mounter *nfsMounter) IsMountPoint(dir string) (bool, error) {
return mount.IsMountPoint(dir) isMounter := mount.New()
return isMounter.IsMountPoint(dir)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment