Abstract ismountpoint and use platform mounter for NFS volume

pull/6/head
Deyuan Deng 2015-03-31 22:08:33 -04:00 committed by Deyuan Deng
parent 2de37624e8
commit d62afa85ff
12 changed files with 70 additions and 92 deletions

View File

@ -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
}

View File

@ -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()

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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) {

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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)
}