From 1c045a09db662c6660562d88deff2733ca17dcf8 Mon Sep 17 00:00:00 2001 From: Travis Rhoden Date: Tue, 2 Apr 2019 13:19:27 -0600 Subject: [PATCH] Move nsenter mounter to pkg/volume/util/nsenter As part of moving pkg/util/mount out of tree, the NSEnter implementation of mount.Interface needs to be relocated out of pkg/util/mount, as it is K8s specific. This patch relocates that mounter implementation to pkg/volume/util/nsenter. Since the NSEnter mounter shares a lot of its logic with the Linux mounter implementation, many of the previously private methods of the Linux mounter are now made public to maintain that shared code. Additionaly, it was observed that *all* mount.Interface implemenations were using the same common method for IsNotMountPoint, so this patch removes that method from the mount.Interface definition and just exports the common implementation instead. --- cmd/kubelet/app/BUILD | 1 + cmd/kubelet/app/server.go | 3 +- pkg/util/mount/BUILD | 33 ------- pkg/util/mount/exec_mount.go | 8 +- pkg/util/mount/exec_mount_unsupported.go | 4 - pkg/util/mount/fake.go | 4 - pkg/util/mount/mount.go | 23 +++-- pkg/util/mount/mount_helper_common.go | 2 +- pkg/util/mount/mount_linux.go | 74 ++++++++-------- pkg/util/mount/mount_linux_test.go | 4 +- pkg/util/mount/mount_test.go | 2 +- pkg/util/mount/mount_unsupported.go | 4 - pkg/util/mount/mount_windows.go | 7 +- pkg/volume/local/local.go | 6 +- pkg/volume/nfs/nfs.go | 6 +- pkg/volume/util/BUILD | 1 + pkg/volume/util/nsenter/BUILD | 86 +++++++++++++++++++ .../util/nsenter}/nsenter_mount.go | 55 ++++++------ .../util/nsenter}/nsenter_mount_test.go | 2 +- .../nsenter}/nsenter_mount_unsupported.go | 20 ++--- pkg/volume/util/subpath/BUILD | 1 + pkg/volume/util/subpath/subpath_linux.go | 2 +- .../util/subpath/subpath_nsenter_test.go | 6 +- 23 files changed, 194 insertions(+), 160 deletions(-) create mode 100644 pkg/volume/util/nsenter/BUILD rename pkg/{util/mount => volume/util/nsenter}/nsenter_mount.go (88%) rename pkg/{util/mount => volume/util/nsenter}/nsenter_mount_test.go (99%) rename pkg/{util/mount => volume/util/nsenter}/nsenter_mount_unsupported.go (84%) diff --git a/cmd/kubelet/app/BUILD b/cmd/kubelet/app/BUILD index 5e9cf6fc816..6395f9d30f3 100644 --- a/cmd/kubelet/app/BUILD +++ b/cmd/kubelet/app/BUILD @@ -108,6 +108,7 @@ go_library( "//pkg/volume/scaleio:go_default_library", "//pkg/volume/secret:go_default_library", "//pkg/volume/storageos:go_default_library", + "//pkg/volume/util/nsenter:go_default_library", "//pkg/volume/util/subpath:go_default_library", "//pkg/volume/vsphere_volume:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index 420c585fdaf..ff9907e703d 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -96,6 +96,7 @@ import ( "k8s.io/kubernetes/pkg/util/rlimit" "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/version/verflag" + nsutil "k8s.io/kubernetes/pkg/volume/util/nsenter" "k8s.io/kubernetes/pkg/volume/util/subpath" "k8s.io/utils/exec" "k8s.io/utils/nsenter" @@ -373,7 +374,7 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err if err != nil { return nil, err } - mounter = mount.NewNsenterMounter(s.RootDirectory, ne) + mounter = nsutil.NewNsenterMounter(s.RootDirectory, ne) // NSenter only valid on Linux subpather = subpath.NewNSEnter(mounter, ne, s.RootDirectory) // an exec interface which can use nsenter for flex plugin calls diff --git a/pkg/util/mount/BUILD b/pkg/util/mount/BUILD index 3a61d016a81..d677306752b 100644 --- a/pkg/util/mount/BUILD +++ b/pkg/util/mount/BUILD @@ -15,8 +15,6 @@ go_library( "mount_linux.go", "mount_unsupported.go", "mount_windows.go", - "nsenter_mount.go", - "nsenter_mount_unsupported.go", ], importpath = "k8s.io/kubernetes/pkg/util/mount", visibility = ["//visibility:public"], @@ -24,43 +22,14 @@ go_library( "//vendor/k8s.io/klog:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", ] + select({ - "@io_bazel_rules_go//go/platform:android": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:darwin": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:dragonfly": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:freebsd": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], "@io_bazel_rules_go//go/platform:linux": [ "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/golang.org/x/sys/unix:go_default_library", "//vendor/k8s.io/utils/io:go_default_library", - "//vendor/k8s.io/utils/nsenter:go_default_library", "//vendor/k8s.io/utils/path:go_default_library", ], - "@io_bazel_rules_go//go/platform:nacl": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:netbsd": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:openbsd": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:plan9": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], - "@io_bazel_rules_go//go/platform:solaris": [ - "//vendor/k8s.io/utils/nsenter:go_default_library", - ], "@io_bazel_rules_go//go/platform:windows": [ "//vendor/k8s.io/utils/keymutex:go_default_library", - "//vendor/k8s.io/utils/nsenter:go_default_library", "//vendor/k8s.io/utils/path:go_default_library", ], "//conditions:default": [], @@ -75,7 +44,6 @@ go_test( "mount_linux_test.go", "mount_test.go", "mount_windows_test.go", - "nsenter_mount_test.go", "safe_format_and_mount_test.go", ], embed = [":go_default_library"], @@ -84,7 +52,6 @@ go_test( ] + select({ "@io_bazel_rules_go//go/platform:linux": [ "//vendor/k8s.io/utils/exec:go_default_library", - "//vendor/k8s.io/utils/nsenter:go_default_library", ], "@io_bazel_rules_go//go/platform:windows": [ "//vendor/github.com/stretchr/testify/assert:go_default_library", diff --git a/pkg/util/mount/exec_mount.go b/pkg/util/mount/exec_mount.go index b30f6f0218f..cdddb635989 100644 --- a/pkg/util/mount/exec_mount.go +++ b/pkg/util/mount/exec_mount.go @@ -44,7 +44,7 @@ var _ Interface = &execMounter{} // Mount runs mount(8) using given exec interface. func (m *execMounter) Mount(source string, target string, fstype string, options []string) error { - bind, bindOpts, bindRemountOpts := isBind(options) + bind, bindOpts, bindRemountOpts := IsBind(options) if bind { err := m.doExecMount(source, target, fstype, bindOpts) @@ -60,7 +60,7 @@ func (m *execMounter) Mount(source string, target string, fstype string, options // doExecMount calls exec(mount ) using given exec interface. func (m *execMounter) doExecMount(source, target, fstype string, options []string) error { klog.V(5).Infof("Exec Mounting %s %s %s %v", source, target, fstype, options) - mountArgs := makeMountArgs(source, target, fstype, options) + mountArgs := MakeMountArgs(source, target, fstype, options) output, err := m.exec.Run("mount", mountArgs...) klog.V(5).Infof("Exec mounted %v: %v: %s", mountArgs, err, string(output)) if err != nil { @@ -116,10 +116,6 @@ func (m *execMounter) IsMountPointMatch(mp MountPoint, dir string) bool { return m.wrappedMounter.IsMountPointMatch(mp, dir) } -func (m *execMounter) IsNotMountPoint(dir string) (bool, error) { - return m.wrappedMounter.IsNotMountPoint(dir) -} - func (m *execMounter) MakeRShared(path string) error { return m.wrappedMounter.MakeRShared(path) } diff --git a/pkg/util/mount/exec_mount_unsupported.go b/pkg/util/mount/exec_mount_unsupported.go index 698c136e019..328b383fd4d 100644 --- a/pkg/util/mount/exec_mount_unsupported.go +++ b/pkg/util/mount/exec_mount_unsupported.go @@ -47,10 +47,6 @@ func (mounter *execMounter) IsMountPointMatch(mp MountPoint, dir string) bool { return (mp.Path == dir) } -func (mounter *execMounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(mounter, dir) -} - func (mounter *execMounter) IsLikelyNotMountPoint(file string) (bool, error) { return true, nil } diff --git a/pkg/util/mount/fake.go b/pkg/util/mount/fake.go index f8abc216b87..29ffbc98238 100644 --- a/pkg/util/mount/fake.go +++ b/pkg/util/mount/fake.go @@ -136,10 +136,6 @@ func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool { return mp.Path == dir } -func (f *FakeMounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(f, dir) -} - func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) { f.mutex.Lock() defer f.mutex.Unlock() diff --git a/pkg/util/mount/mount.go b/pkg/util/mount/mount.go index b0ad41ceffd..40de6ed7c96 100644 --- a/pkg/util/mount/mount.go +++ b/pkg/util/mount/mount.go @@ -50,14 +50,6 @@ type Interface interface { List() ([]MountPoint, error) // IsMountPointMatch determines if the mountpoint matches the dir IsMountPointMatch(mp MountPoint, dir string) bool - // IsNotMountPoint determines if a directory is a mountpoint. - // It should return ErrNotExist when the directory does not exist. - // IsNotMountPoint is more expensive than IsLikelyNotMountPoint. - // IsNotMountPoint detects bind mounts in linux. - // IsNotMountPoint enumerates all the mountpoints using List() and - // the list of mountpoints may be large, then it uses - // IsMountPointMatch to evaluate whether the directory is a mountpoint - IsNotMountPoint(file string) (bool, error) // IsLikelyNotMountPoint uses heuristics to determine if a directory // is a mountpoint. // It should return ErrNotExist when the directory does not exist. @@ -222,9 +214,14 @@ func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, e return device, refCount, nil } -// isNotMountPoint implements Mounter.IsNotMountPoint and is shared by mounter -// implementations. -func isNotMountPoint(mounter Interface, file string) (bool, error) { +// IsNotMountPoint determines if a directory is a mountpoint. +// It should return ErrNotExist when the directory does not exist. +// IsNotMountPoint is more expensive than IsLikelyNotMountPoint. +// IsNotMountPoint detects bind mounts in linux. +// IsNotMountPoint enumerates all the mountpoints using List() and +// the list of mountpoints may be large, then it uses +// IsMountPointMatch to evaluate whether the directory is a mountpoint +func IsNotMountPoint(mounter Interface, file string) (bool, error) { // IsLikelyNotMountPoint provides a quick check // to determine whether file IS A mountpoint notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file) @@ -263,11 +260,11 @@ func isNotMountPoint(mounter Interface, file string) (bool, error) { return notMnt, nil } -// isBind detects whether a bind mount is being requested and makes the remount options to +// IsBind detects whether a bind mount is being requested and makes the remount options to // use in case of bind mount, due to the fact that bind mount doesn't respect mount options. // The list equals: // options - 'bind' + 'remount' (no duplicate) -func isBind(options []string) (bool, []string, []string) { +func IsBind(options []string) (bool, []string, []string) { // Because we have an FD opened on the subpath bind mount, the "bind" option // needs to be included, otherwise the mount target will error as busy if you // remount as readonly. diff --git a/pkg/util/mount/mount_helper_common.go b/pkg/util/mount/mount_helper_common.go index cff1d89588e..75b128473cb 100644 --- a/pkg/util/mount/mount_helper_common.go +++ b/pkg/util/mount/mount_helper_common.go @@ -55,7 +55,7 @@ func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPoin var notMnt bool var err error if extensiveMountPointCheck { - notMnt, err = mounter.IsNotMountPoint(mountPath) + notMnt, err = IsNotMountPoint(mounter, mountPath) } else { notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) } diff --git a/pkg/util/mount/mount_linux.go b/pkg/util/mount/mount_linux.go index 9ffd766a51b..5b661fab7c8 100644 --- a/pkg/util/mount/mount_linux.go +++ b/pkg/util/mount/mount_linux.go @@ -81,7 +81,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio // Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty. // All Linux distros are expected to be shipped with a mount utility that a support bind mounts. mounterPath := "" - bind, bindOpts, bindRemountOpts := isBind(options) + bind, bindOpts, bindRemountOpts := IsBind(options) if bind { err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts) if err != nil { @@ -99,7 +99,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio // doMount runs the mount command. mounterPath is the path to mounter binary if containerized mounter is used. func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, target string, fstype string, options []string) error { - mountArgs := makeMountArgs(source, target, fstype, options) + mountArgs := MakeMountArgs(source, target, fstype, options) if len(mounterPath) > 0 { mountArgs = append([]string{mountCmd}, mountArgs...) mountCmd = mounterPath @@ -128,7 +128,7 @@ func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, ta // // systemd-mount is not used because it's too new for older distros // (CentOS 7, Debian Jessie). - mountCmd, mountArgs = addSystemdScope("systemd-run", target, mountCmd, mountArgs) + mountCmd, mountArgs = AddSystemdScope("systemd-run", target, mountCmd, mountArgs) } else { // No systemd-run on the host (or we failed to check it), assume kubelet // does not run as a systemd service. @@ -172,8 +172,9 @@ func detectSystemd() bool { return true } -// makeMountArgs makes the arguments to the mount(8) command. -func makeMountArgs(source, target, fstype string, options []string) []string { +// MakeMountArgs makes the arguments to the mount(8) command. +// Implementation is shared with NsEnterMounter +func MakeMountArgs(source, target, fstype string, options []string) []string { // Build mount command as follows: // mount [-t $fstype] [-o $options] [$source] $target mountArgs := []string{} @@ -191,8 +192,9 @@ func makeMountArgs(source, target, fstype string, options []string) []string { return mountArgs } -// addSystemdScope adds "system-run --scope" to given command line -func addSystemdScope(systemdRunPath, mountName, command string, args []string) (string, []string) { +// AddSystemdScope adds "system-run --scope" to given command line +// implementation is shared with NsEnterMounter +func AddSystemdScope(systemdRunPath, mountName, command string, args []string) (string, []string) { descriptionArg := fmt.Sprintf("--description=Kubernetes transient mount for %s", mountName) systemdRunArgs := []string{descriptionArg, "--scope", "--", command} return systemdRunPath, append(systemdRunArgs, args...) @@ -211,7 +213,7 @@ func (mounter *Mounter) Unmount(target string) error { // List returns a list of all mounted filesystems. func (*Mounter) List() ([]MountPoint, error) { - return listProcMounts(procMountsPath) + return ListProcMounts(procMountsPath) } func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool { @@ -219,10 +221,6 @@ func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool { return ((mp.Path == dir) || (mp.Path == deletedDir)) } -func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(mounter, dir) -} - // IsLikelyNotMountPoint determines if a directory is not a mountpoint. // It is fast but not necessarily ALWAYS correct. If the path is in fact // a bind mount from one part of a mount to another it will not be detected. @@ -252,7 +250,7 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { // If open returns nil, return false with nil error. // Otherwise, return false with error func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) { - return exclusiveOpenFailsOnDevice(pathname) + return ExclusiveOpenFailsOnDevice(pathname) } // PathIsDevice uses FileInfo returned from os.Stat to check if path refers @@ -263,7 +261,8 @@ func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) { return isDevice, err } -func exclusiveOpenFailsOnDevice(pathname string) (bool, error) { +// ExclusiveOpenFailsOnDevice is shared with NsEnterMounter +func ExclusiveOpenFailsOnDevice(pathname string) (bool, error) { var isDevice bool finfo, err := os.Stat(pathname) if os.IsNotExist(err) { @@ -302,13 +301,18 @@ func exclusiveOpenFailsOnDevice(pathname string) (bool, error) { //GetDeviceNameFromMount: given a mount point, find the device name from its global mount point func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { - return getDeviceNameFromMount(mounter, mountPath, pluginDir) + return GetDeviceNameFromMountLinux(mounter, mountPath, pluginDir) } -// getDeviceNameFromMount find the device name from /proc/mounts in which +func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) { + return GetDeviceNameFromMountLinux(mounter, mountPath, pluginDir) +} + +// GetDeviceNameFromMountLinux find the device name from /proc/mounts in which // the mount path reference should match the given plugin directory. In case no mount path reference // matches, returns the volume name taken from its given mountPath -func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) { +// This implementation is shared with NsEnterMounter +func GetDeviceNameFromMountLinux(mounter Interface, mountPath, pluginDir string) (string, error) { refs, err := mounter.GetMountRefs(mountPath) if err != nil { klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err) @@ -333,7 +337,8 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str return path.Base(mountPath), nil } -func listProcMounts(mountFilePath string) ([]MountPoint, error) { +// ListProcMounts is shared with NsEnterMounter +func ListProcMounts(mountFilePath string) ([]MountPoint, error) { content, err := utilio.ConsistentRead(mountFilePath, maxListTries) if err != nil { return nil, err @@ -379,7 +384,7 @@ func parseProcMounts(content []byte) ([]MountPoint, error) { } func (mounter *Mounter) MakeRShared(path string) error { - return doMakeRShared(path, procMountInfoPath) + return DoMakeRShared(path, procMountInfoPath) } func (mounter *Mounter) GetFileType(pathname string) (FileType, error) { @@ -668,11 +673,11 @@ func findMountInfo(path, mountInfoPath string) (mountInfo, error) { return *info, nil } -// doMakeRShared is common implementation of MakeRShared on Linux. It checks if +// DoMakeRShared is common implementation of MakeRShared on Linux. It checks if // path is shared and bind-mounts it as rshared if needed. mountCmd and -// mountArgs are expected to contain mount-like command, doMakeRShared will add +// mountArgs are expected to contain mount-like command, DoMakeRShared will add // '--bind ' and '--make-rshared ' to mountArgs. -func doMakeRShared(path string, mountInfoFilename string) error { +func DoMakeRShared(path string, mountInfoFilename string) error { shared, err := isShared(path, mountInfoFilename) if err != nil { return err @@ -696,8 +701,8 @@ func doMakeRShared(path string, mountInfoFilename string) error { return nil } -// getSELinuxSupport is common implementation of GetSELinuxSupport on Linux. -func getSELinuxSupport(path string, mountInfoFilename string) (bool, error) { +// GetSELinux is common implementation of GetSELinuxSupport on Linux. +func GetSELinux(path string, mountInfoFilename string) (bool, error) { info, err := findMountInfo(path, mountInfoFilename) if err != nil { return false, err @@ -731,11 +736,11 @@ func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) { if err != nil { return nil, err } - return searchMountPoints(realpath, procMountInfoPath) + return SearchMountPoints(realpath, procMountInfoPath) } func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) { - return getSELinuxSupport(pathname, procMountInfoPath) + return GetSELinux(pathname, procMountInfoPath) } func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) { @@ -743,15 +748,16 @@ func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) { if err != nil { return 0, err } - return getFSGroup(realpath) + return GetFSGroupLinux(realpath) } func (mounter *Mounter) GetMode(pathname string) (os.FileMode, error) { - return getMode(pathname) + return GetModeLinux(pathname) } -// This implementation is shared between Linux and NsEnterMounter -func getFSGroup(pathname string) (int64, error) { +// GetFSGroupLinux is shared between Linux and NsEnterMounter +// pathname must already be evaluated for symlinks +func GetFSGroupLinux(pathname string) (int64, error) { info, err := os.Stat(pathname) if err != nil { return 0, err @@ -759,8 +765,8 @@ func getFSGroup(pathname string) (int64, error) { return int64(info.Sys().(*syscall.Stat_t).Gid), nil } -// This implementation is shared between Linux and NsEnterMounter -func getMode(pathname string) (os.FileMode, error) { +// GetModeLinux is shared between Linux and NsEnterMounter +func GetModeLinux(pathname string) (os.FileMode, error) { info, err := os.Stat(pathname) if err != nil { return 0, err @@ -768,14 +774,14 @@ func getMode(pathname string) (os.FileMode, error) { return info.Mode(), nil } -// searchMountPoints finds all mount references to the source, returns a list of +// SearchMountPoints finds all mount references to the source, returns a list of // mountpoints. // This function assumes source cannot be device. // Some filesystems may share a source name, e.g. tmpfs. And for bind mounting, // it's possible to mount a non-root path of a filesystem, so we need to use // root path and major:minor to represent mount source uniquely. // This implementation is shared between Linux and NsEnterMounter -func searchMountPoints(hostSource, mountInfoPath string) ([]string, error) { +func SearchMountPoints(hostSource, mountInfoPath string) ([]string, error) { mis, err := parseMountInfo(mountInfoPath) if err != nil { return nil, err diff --git a/pkg/util/mount/mount_linux_test.go b/pkg/util/mount/mount_linux_test.go index ee2769a8270..6a53e266239 100644 --- a/pkg/util/mount/mount_linux_test.go +++ b/pkg/util/mount/mount_linux_test.go @@ -631,7 +631,7 @@ func TestGetSELinuxSupport(t *testing.T) { } for _, test := range tests { - out, err := getSELinuxSupport(test.mountPoint, filename) + out, err := GetSELinux(test.mountPoint, filename) if err != nil { t.Errorf("Test %s failed with error: %s", test.name, err) } @@ -907,7 +907,7 @@ func TestSearchMountPoints(t *testing.T) { tmpFile.Seek(0, 0) tmpFile.WriteString(v.mountInfos) tmpFile.Sync() - refs, err := searchMountPoints(v.source, tmpFile.Name()) + refs, err := SearchMountPoints(v.source, tmpFile.Name()) if !reflect.DeepEqual(refs, v.expectedRefs) { t.Errorf("test %q: expected Refs: %#v, got %#v", v.name, v.expectedRefs, refs) } diff --git a/pkg/util/mount/mount_test.go b/pkg/util/mount/mount_test.go index 26ba8d79d36..6479bd759cc 100644 --- a/pkg/util/mount/mount_test.go +++ b/pkg/util/mount/mount_test.go @@ -43,7 +43,7 @@ func TestIsBind(t *testing.T) { }, } for _, test := range tests { - bind, bindOpts, bindRemountOpts := isBind(test.mountOption) + bind, bindOpts, bindRemountOpts := IsBind(test.mountOption) if bind != test.isBind { t.Errorf("Expected bind to be %v but got %v", test.isBind, bind) } diff --git a/pkg/util/mount/mount_unsupported.go b/pkg/util/mount/mount_unsupported.go index 58f1acc7299..638b941e2fa 100644 --- a/pkg/util/mount/mount_unsupported.go +++ b/pkg/util/mount/mount_unsupported.go @@ -54,10 +54,6 @@ func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool { return (mp.Path == dir) } -func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(mounter, dir) -} - func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { return true, unsupportedErr } diff --git a/pkg/util/mount/mount_windows.go b/pkg/util/mount/mount_windows.go index 4e2efbffb15..026d42196c5 100644 --- a/pkg/util/mount/mount_windows.go +++ b/pkg/util/mount/mount_windows.go @@ -72,7 +72,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio bindSource := source // tell it's going to mount azure disk or azure file according to options - if bind, _, _ := isBind(options); bind { + if bind, _, _ := IsBind(options); bind { // mount azure disk bindSource = normalizeWindowsPath(source) } else { @@ -173,11 +173,6 @@ func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool { return mp.Path == dir } -// IsNotMountPoint determines if a directory is a mountpoint. -func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(mounter, dir) -} - // IsLikelyNotMountPoint determines if a directory is not a mountpoint. func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { stat, err := os.Lstat(file) diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index c6a6a5fa889..72915cc2f47 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -441,7 +441,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { return fmt.Errorf("invalid path: %s %v", m.globalPath, err) } - notMnt, err := m.mounter.IsNotMountPoint(dir) + notMnt, err := mount.IsNotMountPoint(m.mounter, dir) klog.V(4).Infof("LocalVolume mount setup: PodDir(%s) VolDir(%s) Mounted(%t) Error(%v), ReadOnly(%t)", dir, m.globalPath, !notMnt, err, m.readOnly) if err != nil && !os.IsNotExist(err) { klog.Errorf("cannot validate mount point: %s %v", dir, err) @@ -492,7 +492,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { err = m.mounter.Mount(globalPath, dir, "", mountOptions) if err != nil { klog.Errorf("Mount of volume %s failed: %v", dir, err) - notMnt, mntErr := m.mounter.IsNotMountPoint(dir) + notMnt, mntErr := mount.IsNotMountPoint(m.mounter, dir) if mntErr != nil { klog.Errorf("IsNotMountPoint check failed: %v", mntErr) return err @@ -502,7 +502,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { klog.Errorf("Failed to unmount: %v", mntErr) return err } - notMnt, mntErr = m.mounter.IsNotMountPoint(dir) + notMnt, mntErr = mount.IsNotMountPoint(m.mounter, dir) if mntErr != nil { klog.Errorf("IsNotMountPoint check failed: %v", mntErr) return err diff --git a/pkg/volume/nfs/nfs.go b/pkg/volume/nfs/nfs.go index 5a7eeed98da..4390bb0ec55 100644 --- a/pkg/volume/nfs/nfs.go +++ b/pkg/volume/nfs/nfs.go @@ -238,7 +238,7 @@ func (b *nfsMounter) SetUp(fsGroup *int64) error { } func (b *nfsMounter) SetUpAt(dir string, fsGroup *int64) error { - notMnt, err := b.mounter.IsNotMountPoint(dir) + notMnt, err := mount.IsNotMountPoint(b.mounter, dir) klog.V(4).Infof("NFS mount set up: %s %v %v", dir, !notMnt, err) if err != nil && !os.IsNotExist(err) { return err @@ -257,7 +257,7 @@ func (b *nfsMounter) SetUpAt(dir string, fsGroup *int64) error { mountOptions := util.JoinMountOptions(b.mountOptions, options) err = b.mounter.Mount(source, dir, "nfs", mountOptions) if err != nil { - notMnt, mntErr := b.mounter.IsNotMountPoint(dir) + notMnt, mntErr := mount.IsNotMountPoint(b.mounter, dir) if mntErr != nil { klog.Errorf("IsNotMountPoint check failed: %v", mntErr) return err @@ -267,7 +267,7 @@ func (b *nfsMounter) SetUpAt(dir string, fsGroup *int64) error { klog.Errorf("Failed to unmount: %v", mntErr) return err } - notMnt, mntErr := b.mounter.IsNotMountPoint(dir) + notMnt, mntErr := mount.IsNotMountPoint(b.mounter, dir) if mntErr != nil { klog.Errorf("IsNotMountPoint check failed: %v", mntErr) return err diff --git a/pkg/volume/util/BUILD b/pkg/volume/util/BUILD index 0dec3818138..dac92b53ea1 100644 --- a/pkg/volume/util/BUILD +++ b/pkg/volume/util/BUILD @@ -86,6 +86,7 @@ filegroup( ":package-srcs", "//pkg/volume/util/fs:all-srcs", "//pkg/volume/util/nestedpendingoperations:all-srcs", + "//pkg/volume/util/nsenter:all-srcs", "//pkg/volume/util/operationexecutor:all-srcs", "//pkg/volume/util/recyclerclient:all-srcs", "//pkg/volume/util/subpath:all-srcs", diff --git a/pkg/volume/util/nsenter/BUILD b/pkg/volume/util/nsenter/BUILD new file mode 100644 index 00000000000..ab5b6aa7a8b --- /dev/null +++ b/pkg/volume/util/nsenter/BUILD @@ -0,0 +1,86 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "nsenter_mount.go", + "nsenter_mount_unsupported.go", + ], + importpath = "k8s.io/kubernetes/pkg/volume/util/nsenter", + visibility = ["//visibility:public"], + deps = select({ + "@io_bazel_rules_go//go/platform:android": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:darwin": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:dragonfly": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:freebsd": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:linux": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + "//vendor/k8s.io/utils/path:go_default_library", + ], + "@io_bazel_rules_go//go/platform:nacl": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:netbsd": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:openbsd": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:plan9": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:solaris": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "@io_bazel_rules_go//go/platform:windows": [ + "//pkg/util/mount:go_default_library", + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "//conditions:default": [], + }), +) + +go_test( + name = "go_default_test", + srcs = ["nsenter_mount_test.go"], + embed = [":go_default_library"], + deps = select({ + "@io_bazel_rules_go//go/platform:linux": [ + "//vendor/k8s.io/utils/nsenter:go_default_library", + ], + "//conditions:default": [], + }), +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/pkg/util/mount/nsenter_mount.go b/pkg/volume/util/nsenter/nsenter_mount.go similarity index 88% rename from pkg/util/mount/nsenter_mount.go rename to pkg/volume/util/nsenter/nsenter_mount.go index a7407315c48..8ab76f256e4 100644 --- a/pkg/util/mount/nsenter_mount.go +++ b/pkg/volume/util/nsenter/nsenter_mount.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mount +package nsenter import ( "fmt" @@ -25,6 +25,7 @@ import ( "strings" "k8s.io/klog" + "k8s.io/kubernetes/pkg/util/mount" "k8s.io/utils/nsenter" utilpath "k8s.io/utils/path" ) @@ -54,12 +55,12 @@ func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter { } // NsenterMounter implements mount.Interface -var _ = Interface(&NsenterMounter{}) +var _ = mount.Interface(&NsenterMounter{}) // Mount runs mount(8) in the host's root mount namespace. Aside from this // aspect, Mount has the same semantics as the mounter returned by mount.New() func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error { - bind, bindOpts, bindRemountOpts := isBind(options) + bind, bindOpts, bindRemountOpts := mount.IsBind(options) if bind { err := n.doNsenterMount(source, target, fstype, bindOpts) @@ -88,7 +89,7 @@ func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options [ // requested mount. func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) (string, []string) { mountCmd := n.ne.AbsHostPath("mount") - mountArgs := makeMountArgs(source, target, fstype, options) + mountArgs := mount.MakeMountArgs(source, target, fstype, options) if systemdRunPath, hasSystemd := n.ne.SupportsSystemd(); hasSystemd { // Complete command line: @@ -106,7 +107,7 @@ func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options // Kubelet container can be restarted and the fuse daemon survives. // * When the daemon dies (e.g. during unmount) systemd removes the // scope automatically. - mountCmd, mountArgs = addSystemdScope(systemdRunPath, target, mountCmd, mountArgs) + mountCmd, mountArgs = mount.AddSystemdScope(systemdRunPath, target, mountCmd, mountArgs) } else { // Fall back to simple mount when the host has no systemd. // Complete command line: @@ -138,15 +139,11 @@ func (n *NsenterMounter) Unmount(target string) error { } // List returns a list of all mounted filesystems in the host's mount namespace. -func (*NsenterMounter) List() ([]MountPoint, error) { - return listProcMounts(hostProcMountsPath) +func (*NsenterMounter) List() ([]mount.MountPoint, error) { + return mount.ListProcMounts(hostProcMountsPath) } -func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(m, dir) -} - -func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool { +func (*NsenterMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { deletedDir := fmt.Sprintf("%s\\040(deleted)", dir) return (mp.Path == dir) || (mp.Path == deletedDir) } @@ -217,28 +214,28 @@ func parseFindMnt(out string) (string, error) { // Returns an error if errno is any error other than EBUSY. // Returns with error if pathname is not a device. func (n *NsenterMounter) DeviceOpened(pathname string) (bool, error) { - return exclusiveOpenFailsOnDevice(pathname) + return mount.ExclusiveOpenFailsOnDevice(pathname) } // PathIsDevice uses FileInfo returned from os.Stat to check if path refers // to a device. func (n *NsenterMounter) PathIsDevice(pathname string) (bool, error) { pathType, err := n.GetFileType(pathname) - isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev + isDevice := pathType == mount.FileTypeCharDev || pathType == mount.FileTypeBlockDev return isDevice, err } //GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts func (n *NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { - return getDeviceNameFromMount(n, mountPath, pluginDir) + return mount.GetDeviceNameFromMountLinux(n, mountPath, pluginDir) } func (n *NsenterMounter) MakeRShared(path string) error { - return doMakeRShared(path, hostProcMountinfoPath) + return mount.DoMakeRShared(path, hostProcMountinfoPath) } -func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) { - var pathType FileType +func (mounter *NsenterMounter) GetFileType(pathname string) (mount.FileType, error) { + var pathType mount.FileType outputBytes, err := mounter.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput() if err != nil { if strings.Contains(string(outputBytes), "No such file") { @@ -251,15 +248,15 @@ func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) { switch string(outputBytes) { case "socket": - return FileTypeSocket, nil + return mount.FileTypeSocket, nil case "character special file": - return FileTypeCharDev, nil + return mount.FileTypeCharDev, nil case "block special file": - return FileTypeBlockDev, nil + return mount.FileTypeBlockDev, nil case "directory": - return FileTypeDirectory, nil + return mount.FileTypeDirectory, nil case "regular file": - return FileTypeFile, nil + return mount.FileTypeFile, nil } return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device") @@ -297,8 +294,8 @@ func (mounter *NsenterMounter) EvalHostSymlinks(pathname string) (string, error) } func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) { - pathExists, pathErr := PathExists(pathname) - if !pathExists || IsCorruptedMnt(pathErr) { + pathExists, pathErr := mount.PathExists(pathname) + if !pathExists || mount.IsCorruptedMnt(pathErr) { return []string{}, nil } else if pathErr != nil { return nil, fmt.Errorf("Error checking path %s: %v", pathname, pathErr) @@ -307,7 +304,7 @@ func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) { if err != nil { return nil, err } - return searchMountPoints(hostpath, hostProcMountinfoPath) + return mount.SearchMountPoints(hostpath, hostProcMountinfoPath) } func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) { @@ -316,11 +313,11 @@ func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) { return -1, err } kubeletpath := mounter.ne.KubeletPath(hostPath) - return getFSGroup(kubeletpath) + return mount.GetFSGroupLinux(kubeletpath) } func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) { - return getSELinuxSupport(pathname, hostProcMountsPath) + return mount.GetSELinux(pathname, hostProcMountsPath) } func (mounter *NsenterMounter) GetMode(pathname string) (os.FileMode, error) { @@ -329,5 +326,5 @@ func (mounter *NsenterMounter) GetMode(pathname string) (os.FileMode, error) { return 0, err } kubeletpath := mounter.ne.KubeletPath(hostPath) - return getMode(kubeletpath) + return mount.GetModeLinux(kubeletpath) } diff --git a/pkg/util/mount/nsenter_mount_test.go b/pkg/volume/util/nsenter/nsenter_mount_test.go similarity index 99% rename from pkg/util/mount/nsenter_mount_test.go rename to pkg/volume/util/nsenter/nsenter_mount_test.go index 84d04b164d5..8ec03a12286 100644 --- a/pkg/util/mount/nsenter_mount_test.go +++ b/pkg/volume/util/nsenter/nsenter_mount_test.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mount +package nsenter import ( "io/ioutil" diff --git a/pkg/util/mount/nsenter_mount_unsupported.go b/pkg/volume/util/nsenter/nsenter_mount_unsupported.go similarity index 84% rename from pkg/util/mount/nsenter_mount_unsupported.go rename to pkg/volume/util/nsenter/nsenter_mount_unsupported.go index 4679b7e150c..34dfde51ee6 100644 --- a/pkg/util/mount/nsenter_mount_unsupported.go +++ b/pkg/volume/util/nsenter/nsenter_mount_unsupported.go @@ -16,13 +16,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mount +package nsenter import ( "errors" "os" "k8s.io/utils/nsenter" + + "k8s.io/kubernetes/pkg/util/mount" ) type NsenterMounter struct{} @@ -31,7 +33,7 @@ func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter { return &NsenterMounter{} } -var _ = Interface(&NsenterMounter{}) +var _ = mount.Interface(&NsenterMounter{}) func (*NsenterMounter) Mount(source string, target string, fstype string, options []string) error { return nil @@ -41,15 +43,11 @@ func (*NsenterMounter) Unmount(target string) error { return nil } -func (*NsenterMounter) List() ([]MountPoint, error) { - return []MountPoint{}, nil +func (*NsenterMounter) List() ([]mount.MountPoint, error) { + return []mount.MountPoint{}, nil } -func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(m, dir) -} - -func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool { +func (*NsenterMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { return (mp.Path == dir) } @@ -73,8 +71,8 @@ func (*NsenterMounter) MakeRShared(path string) error { return nil } -func (*NsenterMounter) GetFileType(_ string) (FileType, error) { - return FileType("fake"), errors.New("not implemented") +func (*NsenterMounter) GetFileType(_ string) (mount.FileType, error) { + return mount.FileType("fake"), errors.New("not implemented") } func (*NsenterMounter) MakeDir(pathname string) error { diff --git a/pkg/volume/util/subpath/BUILD b/pkg/volume/util/subpath/BUILD index ebbbd4d138e..a5b54c47dea 100644 --- a/pkg/volume/util/subpath/BUILD +++ b/pkg/volume/util/subpath/BUILD @@ -74,6 +74,7 @@ go_test( deps = select({ "@io_bazel_rules_go//go/platform:linux": [ "//pkg/util/mount:go_default_library", + "//pkg/volume/util/nsenter:go_default_library", "//vendor/golang.org/x/sys/unix:go_default_library", "//vendor/k8s.io/klog:go_default_library", "//vendor/k8s.io/utils/nsenter:go_default_library", diff --git a/pkg/volume/util/subpath/subpath_linux.go b/pkg/volume/util/subpath/subpath_linux.go index 977f7d2da4d..cd99c9131f2 100644 --- a/pkg/volume/util/subpath/subpath_linux.go +++ b/pkg/volume/util/subpath/subpath_linux.go @@ -101,7 +101,7 @@ func safeOpenSubPath(mounter mount.Interface, subpath Subpath) (int, error) { func prepareSubpathTarget(mounter mount.Interface, subpath Subpath) (bool, string, error) { // Early check for already bind-mounted subpath. bindPathTarget := getSubpathBindTarget(subpath) - notMount, err := mounter.IsNotMountPoint(bindPathTarget) + notMount, err := mount.IsNotMountPoint(mounter, bindPathTarget) if err != nil { if !os.IsNotExist(err) { return false, "", fmt.Errorf("error checking path %s for mount: %s", bindPathTarget, err) diff --git a/pkg/volume/util/subpath/subpath_nsenter_test.go b/pkg/volume/util/subpath/subpath_nsenter_test.go index 865d449f5c9..c8e6270dc95 100644 --- a/pkg/volume/util/subpath/subpath_nsenter_test.go +++ b/pkg/volume/util/subpath/subpath_nsenter_test.go @@ -29,7 +29,7 @@ import ( "k8s.io/utils/nsenter" - "k8s.io/kubernetes/pkg/util/mount" + nsutil "k8s.io/kubernetes/pkg/volume/util/nsenter" ) func TestCheckDeviceInode(t *testing.T) { @@ -106,7 +106,7 @@ func TestCheckDeviceInode(t *testing.T) { } } -func newFakeNsenterMounter(tmpdir string, t *testing.T) (*mount.NsenterMounter, string, string, *nsenter.Nsenter, error) { +func newFakeNsenterMounter(tmpdir string, t *testing.T) (*nsutil.NsenterMounter, string, string, *nsenter.Nsenter, error) { rootfsPath := filepath.Join(tmpdir, "rootfs") if err := os.Mkdir(rootfsPath, 0755); err != nil { return nil, "", "", nil, err @@ -121,7 +121,7 @@ func newFakeNsenterMounter(tmpdir string, t *testing.T) (*mount.NsenterMounter, return nil, "", "", nil, err } - return mount.NewNsenterMounter(varlibPath, ne), rootfsPath, varlibPath, ne, nil + return nsutil.NewNsenterMounter(varlibPath, ne), rootfsPath, varlibPath, ne, nil } func TestNsenterSafeMakeDir(t *testing.T) {