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..18aed3fe3bb 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.NewMounter(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 30c7b7cd3d3..e665748dbe8 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,42 +22,13 @@ 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": [ "//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": [], @@ -74,7 +43,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"], @@ -83,7 +51,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 8017aaf00ad..17e80c0708c 100644 --- a/pkg/util/mount/mount_linux.go +++ b/pkg/util/mount/mount_linux.go @@ -80,7 +80,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 { @@ -103,7 +103,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 @@ -132,7 +132,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. @@ -176,8 +176,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{} @@ -195,8 +196,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...) @@ -215,7 +217,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 { @@ -223,10 +225,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. @@ -256,7 +254,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 @@ -267,7 +265,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) { @@ -306,13 +305,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) @@ -337,7 +341,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 @@ -383,7 +388,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) { @@ -672,11 +677,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 @@ -700,8 +705,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 @@ -735,11 +740,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) { @@ -747,15 +752,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 @@ -763,8 +769,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 @@ -772,14 +778,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/util/mount/nsenter_mount_unsupported.go b/pkg/util/mount/nsenter_mount_unsupported.go deleted file mode 100644 index 4679b7e150c..00000000000 --- a/pkg/util/mount/nsenter_mount_unsupported.go +++ /dev/null @@ -1,110 +0,0 @@ -// +build !linux - -/* -Copyright 2014 The Kubernetes Authors. - -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 ( - "errors" - "os" - - "k8s.io/utils/nsenter" -) - -type NsenterMounter struct{} - -func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter { - return &NsenterMounter{} -} - -var _ = Interface(&NsenterMounter{}) - -func (*NsenterMounter) Mount(source string, target string, fstype string, options []string) error { - return nil -} - -func (*NsenterMounter) Unmount(target string) error { - return nil -} - -func (*NsenterMounter) List() ([]MountPoint, error) { - return []MountPoint{}, nil -} - -func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) { - return isNotMountPoint(m, dir) -} - -func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool { - return (mp.Path == dir) -} - -func (*NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) { - return true, nil -} - -func (*NsenterMounter) DeviceOpened(pathname string) (bool, error) { - return false, nil -} - -func (*NsenterMounter) PathIsDevice(pathname string) (bool, error) { - return true, nil -} - -func (*NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { - return "", nil -} - -func (*NsenterMounter) MakeRShared(path string) error { - return nil -} - -func (*NsenterMounter) GetFileType(_ string) (FileType, error) { - return FileType("fake"), errors.New("not implemented") -} - -func (*NsenterMounter) MakeDir(pathname string) error { - return nil -} - -func (*NsenterMounter) MakeFile(pathname string) error { - return nil -} - -func (*NsenterMounter) ExistsPath(pathname string) (bool, error) { - return true, errors.New("not implemented") -} - -func (*NsenterMounter) EvalHostSymlinks(pathname string) (string, error) { - return "", errors.New("not implemented") -} - -func (*NsenterMounter) GetMountRefs(pathname string) ([]string, error) { - return nil, errors.New("not implemented") -} - -func (*NsenterMounter) GetFSGroup(pathname string) (int64, error) { - return -1, errors.New("not implemented") -} - -func (*NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) { - return false, errors.New("not implemented") -} - -func (*NsenterMounter) GetMode(pathname string) (os.FileMode, error) { - return 0, errors.New("not implemented") -} 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 66% rename from pkg/util/mount/nsenter_mount.go rename to pkg/volume/util/nsenter/nsenter_mount.go index a7407315c48..c4f5f265777 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" ) @@ -36,30 +37,31 @@ const ( hostProcMountinfoPath = "/rootfs/proc/1/mountinfo" ) +// Mounter implements mount.Interface // Currently, all docker containers receive their own mount namespaces. -// NsenterMounter works by executing nsenter to run commands in +// Mounter works by executing nsenter to run commands in // the host's mount namespace. -type NsenterMounter struct { +type Mounter struct { ne *nsenter.Nsenter // rootDir is location of /var/lib/kubelet directory. rootDir string } -// NewNsenterMounter creates a new mounter for kubelet that runs as a container. -func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter { - return &NsenterMounter{ +// NewMounter creates a new mounter for kubelet that runs as a container. +func NewMounter(rootDir string, ne *nsenter.Nsenter) *Mounter { + return &Mounter{ rootDir: rootDir, ne: ne, } } -// NsenterMounter implements mount.Interface -var _ = Interface(&NsenterMounter{}) +// Mounter implements mount.Interface +var _ = mount.Interface(&Mounter{}) // 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) +func (n *Mounter) Mount(source string, target string, fstype string, options []string) error { + bind, bindOpts, bindRemountOpts := mount.IsBind(options) if bind { err := n.doNsenterMount(source, target, fstype, bindOpts) @@ -74,7 +76,7 @@ func (n *NsenterMounter) Mount(source string, target string, fstype string, opti // doNsenterMount nsenters the host's mount namespace and performs the // requested mount. -func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options []string) error { +func (n *Mounter) doNsenterMount(source, target, fstype string, options []string) error { klog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options) cmd, args := n.makeNsenterArgs(source, target, fstype, options) outputBytes, err := n.ne.Exec(cmd, args).CombinedOutput() @@ -86,9 +88,9 @@ func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options [ // makeNsenterArgs makes a list of argument to nsenter in order to do the // requested mount. -func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) (string, []string) { +func (n *Mounter) 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 +108,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: @@ -124,7 +126,7 @@ func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options } // Unmount runs umount(8) in the host's mount namespace. -func (n *NsenterMounter) Unmount(target string) error { +func (n *Mounter) Unmount(target string) error { args := []string{target} // No need to execute systemd-run here, it's enough that unmount is executed // in the host's mount namespace. It will finish appropriate fuse daemon(s) @@ -138,22 +140,19 @@ 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 (*Mounter) 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 { +// IsMountPointMatch tests if dir and mp are the same path +func (*Mounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { deletedDir := fmt.Sprintf("%s\\040(deleted)", dir) return (mp.Path == dir) || (mp.Path == deletedDir) } // IsLikelyNotMountPoint determines whether a path is a mountpoint by calling findmnt // in the host's root mount namespace. -func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) { +func (n *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { file, err := filepath.Abs(file) if err != nil { return true, err @@ -216,30 +215,32 @@ func parseFindMnt(out string) (string, error) { // Returns true if open returns errno EBUSY, and false if errno is nil. // 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) +func (n *Mounter) DeviceOpened(pathname string) (bool, error) { + 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) { +func (n *Mounter) 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) +func (n *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { + return mount.GetDeviceNameFromMountLinux(n, mountPath, pluginDir) } -func (n *NsenterMounter) MakeRShared(path string) error { - return doMakeRShared(path, hostProcMountinfoPath) +// MakeRShared checks if path is shared and bind-mounts it as rshared if needed. +func (n *Mounter) MakeRShared(path string) error { + return mount.DoMakeRShared(path, hostProcMountinfoPath) } -func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) { - var pathType FileType - outputBytes, err := mounter.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput() +// GetFileType checks for file/directory/socket/block/character devices. +func (n *Mounter) GetFileType(pathname string) (mount.FileType, error) { + var pathType mount.FileType + outputBytes, err := n.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput() if err != nil { if strings.Contains(string(outputBytes), "No such file") { err = fmt.Errorf("%s does not exist", pathname) @@ -251,83 +252,94 @@ 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") } -func (mounter *NsenterMounter) MakeDir(pathname string) error { +// MakeDir creates a new directory. +func (n *Mounter) MakeDir(pathname string) error { args := []string{"-p", pathname} - if _, err := mounter.ne.Exec("mkdir", args).CombinedOutput(); err != nil { + if _, err := n.ne.Exec("mkdir", args).CombinedOutput(); err != nil { return err } return nil } -func (mounter *NsenterMounter) MakeFile(pathname string) error { +// MakeFile creates an empty file. +func (n *Mounter) MakeFile(pathname string) error { args := []string{pathname} - if _, err := mounter.ne.Exec("touch", args).CombinedOutput(); err != nil { + if _, err := n.ne.Exec("touch", args).CombinedOutput(); err != nil { return err } return nil } -func (mounter *NsenterMounter) ExistsPath(pathname string) (bool, error) { +// ExistsPath checks if pathname exists. +// Error is returned on any other error than "file not found". +func (n *Mounter) ExistsPath(pathname string) (bool, error) { // Resolve the symlinks but allow the target not to exist. EvalSymlinks // would return an generic error when the target does not exist. - hostPath, err := mounter.ne.EvalSymlinks(pathname, false /* mustExist */) + hostPath, err := n.ne.EvalSymlinks(pathname, false /* mustExist */) if err != nil { return false, err } - kubeletpath := mounter.ne.KubeletPath(hostPath) + kubeletpath := n.ne.KubeletPath(hostPath) return utilpath.Exists(utilpath.CheckFollowSymlink, kubeletpath) } -func (mounter *NsenterMounter) EvalHostSymlinks(pathname string) (string, error) { - return mounter.ne.EvalSymlinks(pathname, true) +// EvalHostSymlinks returns the path name after evaluating symlinks. +func (n *Mounter) EvalHostSymlinks(pathname string) (string, error) { + return n.ne.EvalSymlinks(pathname, true) } -func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) { - pathExists, pathErr := PathExists(pathname) - if !pathExists || IsCorruptedMnt(pathErr) { +// GetMountRefs finds all mount references to the path, returns a +// list of paths. Path could be a mountpoint path, device or a normal +// directory (for bind mount). +func (n *Mounter) GetMountRefs(pathname string) ([]string, error) { + 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) } - hostpath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */) + hostpath, err := n.ne.EvalSymlinks(pathname, true /* mustExist */) if err != nil { return nil, err } - return searchMountPoints(hostpath, hostProcMountinfoPath) + return mount.SearchMountPoints(hostpath, hostProcMountinfoPath) } -func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) { - hostPath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */) +// GetFSGroup returns FSGroup of pathname. +func (n *Mounter) GetFSGroup(pathname string) (int64, error) { + hostPath, err := n.ne.EvalSymlinks(pathname, true /* mustExist */) if err != nil { return -1, err } - kubeletpath := mounter.ne.KubeletPath(hostPath) - return getFSGroup(kubeletpath) + kubeletpath := n.ne.KubeletPath(hostPath) + return mount.GetFSGroupLinux(kubeletpath) } -func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) { - return getSELinuxSupport(pathname, hostProcMountsPath) +// GetSELinuxSupport tests if pathname is on a mount that supports SELinux. +func (n *Mounter) GetSELinuxSupport(pathname string) (bool, error) { + return mount.GetSELinux(pathname, hostProcMountsPath) } -func (mounter *NsenterMounter) GetMode(pathname string) (os.FileMode, error) { - hostPath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */) +// GetMode returns permissions of pathname. +func (n *Mounter) GetMode(pathname string) (os.FileMode, error) { + hostPath, err := n.ne.EvalSymlinks(pathname, true /* mustExist */) if err != nil { return 0, err } - kubeletpath := mounter.ne.KubeletPath(hostPath) - return getMode(kubeletpath) + kubeletpath := n.ne.KubeletPath(hostPath) + 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 98% rename from pkg/util/mount/nsenter_mount_test.go rename to pkg/volume/util/nsenter/nsenter_mount_test.go index 84d04b164d5..6124673a671 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" @@ -74,7 +74,7 @@ func TestParseFindMnt(t *testing.T) { } } -func newFakeNsenterMounter(tmpdir string, t *testing.T) (mounter *NsenterMounter, rootfsPath string, varlibPath string, err error) { +func newFakeNsenterMounter(tmpdir string, t *testing.T) (mounter *Mounter, rootfsPath string, varlibPath string, err error) { rootfsPath = filepath.Join(tmpdir, "rootfs") if err := os.Mkdir(rootfsPath, 0755); err != nil { return nil, "", "", err @@ -89,7 +89,7 @@ func newFakeNsenterMounter(tmpdir string, t *testing.T) (mounter *NsenterMounter return nil, "", "", err } - return NewNsenterMounter(varlibPath, ne), rootfsPath, varlibPath, nil + return NewMounter(varlibPath, ne), rootfsPath, varlibPath, nil } func TestNsenterExistsFile(t *testing.T) { diff --git a/pkg/volume/util/nsenter/nsenter_mount_unsupported.go b/pkg/volume/util/nsenter/nsenter_mount_unsupported.go new file mode 100644 index 00000000000..bfa784529b6 --- /dev/null +++ b/pkg/volume/util/nsenter/nsenter_mount_unsupported.go @@ -0,0 +1,139 @@ +// +build !linux + +/* +Copyright 2014 The Kubernetes Authors. + +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 nsenter + +import ( + "errors" + "os" + + "k8s.io/utils/nsenter" + + "k8s.io/kubernetes/pkg/util/mount" +) + +// Mounter provides the mount.Interface implementation for unsupported +// platforms. +type Mounter struct{} + +// NewMounter returns a new Mounter for the current system +func NewMounter(rootDir string, ne *nsenter.Nsenter) *Mounter { + return &Mounter{} +} + +var _ = mount.Interface(&Mounter{}) + +// Mount mounts the source to the target. It is a noop for unsupported systems +func (*Mounter) Mount(source string, target string, fstype string, options []string) error { + return nil +} + +// Unmount unmounts the target path from the system. it is a noop for unsupported +// systems +func (*Mounter) Unmount(target string) error { + return nil +} + +// List returns a list of all mounted filesystems. It is a noop for unsupported systems +func (*Mounter) List() ([]mount.MountPoint, error) { + return []mount.MountPoint{}, nil +} + +// IsMountPointMatch tests if dir and mp are the same path +func (*Mounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { + return (mp.Path == dir) +} + +// IsLikelyNotMountPoint determines if a directory is not a mountpoint. +// It is a noop on unsupported systems +func (*Mounter) IsLikelyNotMountPoint(file string) (bool, error) { + return true, nil +} + +// DeviceOpened checks if block device in use. I tis a noop for unsupported systems +func (*Mounter) DeviceOpened(pathname string) (bool, error) { + return false, nil +} + +// PathIsDevice checks if pathname refers to a device. It is a noop for unsupported +// systems +func (*Mounter) PathIsDevice(pathname string) (bool, error) { + return true, nil +} + +// GetDeviceNameFromMount finds the device name from its global mount point using the +// given mountpath and plugin location. It is a noop of unsupported platforms +func (*Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { + return "", nil +} + +// MakeRShared checks if path is shared and bind-mounts it as rshared if needed. +// It is a noop on unsupported platforms +func (*Mounter) MakeRShared(path string) error { + return nil +} + +// GetFileType checks for file/directory/socket/block/character devices. +// Always returns an error and "fake" filetype on unsupported platforms +func (*Mounter) GetFileType(_ string) (mount.FileType, error) { + return mount.FileType("fake"), errors.New("not implemented") +} + +// MakeDir creates a new directory. Noop on unsupported platforms +func (*Mounter) MakeDir(pathname string) error { + return nil +} + +// MakeFile creats an empty file. Noop on unsupported platforms +func (*Mounter) MakeFile(pathname string) error { + return nil +} + +// ExistsPath checks if pathname exists. Always returns an error on unsupported +// platforms +func (*Mounter) ExistsPath(pathname string) (bool, error) { + return true, errors.New("not implemented") +} + +// EvalHostSymlinks returns the path name after evaluating symlinks. Always +// returns an error on unsupported platforms +func (*Mounter) EvalHostSymlinks(pathname string) (string, error) { + return "", errors.New("not implemented") +} + +// GetMountRefs finds all mount references to the path, returns a +// list of paths. Always returns an error on unsupported platforms +func (*Mounter) GetMountRefs(pathname string) ([]string, error) { + return nil, errors.New("not implemented") +} + +// GetFSGroup returns FSGroup of pathname. Always returns an error on unsupported platforms +func (*Mounter) GetFSGroup(pathname string) (int64, error) { + return -1, errors.New("not implemented") +} + +// GetSELinuxSupport tests if pathname is on a mount that supports SELinux. +// Always returns an error on unsupported platforms +func (*Mounter) GetSELinuxSupport(pathname string) (bool, error) { + return false, errors.New("not implemented") +} + +// GetMode returns permissions of pathname. Always returns an error on unsupported platforms +func (*Mounter) GetMode(pathname string) (os.FileMode, error) { + return 0, errors.New("not implemented") +} 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..4ecb6916565 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.Mounter, 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.NewMounter(varlibPath, ne), rootfsPath, varlibPath, ne, nil } func TestNsenterSafeMakeDir(t *testing.T) {