diff --git a/pkg/util/mount/fake.go b/pkg/util/mount/fake.go index 9377c6c780f..a744c40d291 100644 --- a/pkg/util/mount/fake.go +++ b/pkg/util/mount/fake.go @@ -39,11 +39,19 @@ 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 } @@ -51,3 +59,12 @@ func (f *FakeMounter) Unmount(target string, flags int) error { 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 +} diff --git a/pkg/util/mount/mount.go b/pkg/util/mount/mount.go index 0526b9c71b8..78be52843de 100644 --- a/pkg/util/mount/mount.go +++ b/pkg/util/mount/mount.go @@ -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. @@ -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() diff --git a/pkg/util/mount/mount_linux.go b/pkg/util/mount/mount_linux.go index 24e219f9427..e2d292af364 100644 --- a/pkg/util/mount/mount_linux.go +++ b/pkg/util/mount/mount_linux.go @@ -34,15 +34,16 @@ 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) } @@ -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. const maxListTries = 3 +// List returns a list of all mounted filesystems. func (*Mounter) List() ([]MountPoint, error) { hash1, err := readProcMounts(nil) if err != nil { @@ -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 { diff --git a/pkg/util/mount/mount_unsupported.go b/pkg/util/mount/mount_unsupported.go index 51fb03c6f82..c8c7645ff0e 100644 --- a/pkg/util/mount/mount_unsupported.go +++ b/pkg/util/mount/mount_unsupported.go @@ -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 +} diff --git a/pkg/util/mount/mountpoint_unix.go b/pkg/util/mount/mountpoint_unix.go deleted file mode 100644 index cf0d82def44..00000000000 --- a/pkg/util/mount/mountpoint_unix.go +++ /dev/null @@ -1,40 +0,0 @@ -// +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 -} diff --git a/pkg/util/mount/mountpoint_unsupported.go b/pkg/util/mount/mountpoint_unsupported.go deleted file mode 100644 index 714f843397c..00000000000 --- a/pkg/util/mount/mountpoint_unsupported.go +++ /dev/null @@ -1,28 +0,0 @@ -// +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") -} diff --git a/pkg/volume/empty_dir/empty_dir.go b/pkg/volume/empty_dir/empty_dir.go index 68b15a8bbe3..bcaab71d83d 100644 --- a/pkg/volume/empty_dir/empty_dir.go +++ b/pkg/volume/empty_dir/empty_dir.go @@ -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) { @@ -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) { diff --git a/pkg/volume/empty_dir/empty_dir_linux.go b/pkg/volume/empty_dir/empty_dir_linux.go index 56bae2aa4b7..9f2eb59d80e 100644 --- a/pkg/volume/empty_dir/empty_dir_linux.go +++ b/pkg/volume/empty_dir/empty_dir_linux.go @@ -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) } diff --git a/pkg/volume/empty_dir/empty_dir_unsupported.go b/pkg/volume/empty_dir/empty_dir_unsupported.go index ff2adc262ff..df2c4b9d376 100644 --- a/pkg/volume/empty_dir/empty_dir_unsupported.go +++ b/pkg/volume/empty_dir/empty_dir_unsupported.go @@ -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 diff --git a/pkg/volume/gce_pd/gce_pd.go b/pkg/volume/gce_pd/gce_pd.go index 44d73e5c727..b4e61906031 100644 --- a/pkg/volume/gce_pd/gce_pd.go +++ b/pkg/volume/gce_pd/gce_pd.go @@ -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 @@ -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 @@ -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 @@ -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 } @@ -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 diff --git a/pkg/volume/gce_pd/gce_util.go b/pkg/volume/gce_pd/gce_util.go index 845b27ac7fa..e37d75496a8 100644 --- a/pkg/volume/gce_pd/gce_util.go +++ b/pkg/volume/gce_pd/gce_util.go @@ -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 { diff --git a/pkg/volume/nfs/nfs_mount.go b/pkg/volume/nfs/nfs_mount.go index 03ea1a9ccdd..9c3c2b4050d 100644 --- a/pkg/volume/nfs/nfs_mount.go +++ b/pkg/volume/nfs/nfs_mount.go @@ -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) }