mirror of https://github.com/k3s-io/k3s
Abstract ismountpoint and use platform mounter for NFS volume
parent
2de37624e8
commit
d62afa85ff
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue