diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index ff9907e703d..18aed3fe3bb 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -374,7 +374,7 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err if err != nil { return nil, err } - mounter = nsutil.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/volume/util/nsenter/nsenter_mount.go b/pkg/volume/util/nsenter/nsenter_mount.go index 8ab76f256e4..c4f5f265777 100644 --- a/pkg/volume/util/nsenter/nsenter_mount.go +++ b/pkg/volume/util/nsenter/nsenter_mount.go @@ -37,29 +37,30 @@ 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 _ = mount.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 { +func (n *Mounter) Mount(source string, target string, fstype string, options []string) error { bind, bindOpts, bindRemountOpts := mount.IsBind(options) if bind { @@ -75,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() @@ -87,7 +88,7 @@ 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 := mount.MakeMountArgs(source, target, fstype, options) @@ -125,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) @@ -139,18 +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() ([]mount.MountPoint, error) { +func (*Mounter) List() ([]mount.MountPoint, error) { return mount.ListProcMounts(hostProcMountsPath) } -func (*NsenterMounter) IsMountPointMatch(mp mount.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 @@ -213,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) { +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 == 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) { +func (n *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { return mount.GetDeviceNameFromMountLinux(n, mountPath, pluginDir) } -func (n *NsenterMounter) MakeRShared(path string) error { +// 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) (mount.FileType, error) { +// GetFileType checks for file/directory/socket/block/character devices. +func (n *Mounter) GetFileType(pathname string) (mount.FileType, error) { var pathType mount.FileType - outputBytes, err := mounter.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput() + 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) @@ -262,69 +266,80 @@ func (mounter *NsenterMounter) GetFileType(pathname string) (mount.FileType, err 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) { +// 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 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) + kubeletpath := n.ne.KubeletPath(hostPath) return mount.GetFSGroupLinux(kubeletpath) } -func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) { +// 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) + kubeletpath := n.ne.KubeletPath(hostPath) return mount.GetModeLinux(kubeletpath) } diff --git a/pkg/volume/util/nsenter/nsenter_mount_test.go b/pkg/volume/util/nsenter/nsenter_mount_test.go index 8ec03a12286..6124673a671 100644 --- a/pkg/volume/util/nsenter/nsenter_mount_test.go +++ b/pkg/volume/util/nsenter/nsenter_mount_test.go @@ -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 index 34dfde51ee6..bfa784529b6 100644 --- a/pkg/volume/util/nsenter/nsenter_mount_unsupported.go +++ b/pkg/volume/util/nsenter/nsenter_mount_unsupported.go @@ -27,82 +27,113 @@ import ( "k8s.io/kubernetes/pkg/util/mount" ) -type NsenterMounter struct{} +// Mounter provides the mount.Interface implementation for unsupported +// platforms. +type Mounter struct{} -func NewNsenterMounter(rootDir string, ne *nsenter.Nsenter) *NsenterMounter { - return &NsenterMounter{} +// NewMounter returns a new Mounter for the current system +func NewMounter(rootDir string, ne *nsenter.Nsenter) *Mounter { + return &Mounter{} } -var _ = mount.Interface(&NsenterMounter{}) +var _ = mount.Interface(&Mounter{}) -func (*NsenterMounter) Mount(source string, target string, fstype string, options []string) error { +// 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 } -func (*NsenterMounter) Unmount(target string) error { +// Unmount unmounts the target path from the system. it is a noop for unsupported +// systems +func (*Mounter) Unmount(target string) error { return nil } -func (*NsenterMounter) List() ([]mount.MountPoint, error) { +// 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 } -func (*NsenterMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { +// IsMountPointMatch tests if dir and mp are the same path +func (*Mounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { return (mp.Path == dir) } -func (*NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) { +// 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 } -func (*NsenterMounter) DeviceOpened(pathname string) (bool, error) { +// DeviceOpened checks if block device in use. I tis a noop for unsupported systems +func (*Mounter) DeviceOpened(pathname string) (bool, error) { return false, nil } -func (*NsenterMounter) PathIsDevice(pathname string) (bool, error) { +// 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 } -func (*NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { +// 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 } -func (*NsenterMounter) MakeRShared(path string) error { +// 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 } -func (*NsenterMounter) GetFileType(_ string) (mount.FileType, error) { +// 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") } -func (*NsenterMounter) MakeDir(pathname string) error { +// MakeDir creates a new directory. Noop on unsupported platforms +func (*Mounter) MakeDir(pathname string) error { return nil } -func (*NsenterMounter) MakeFile(pathname string) error { +// MakeFile creats an empty file. Noop on unsupported platforms +func (*Mounter) MakeFile(pathname string) error { return nil } -func (*NsenterMounter) ExistsPath(pathname string) (bool, error) { +// 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") } -func (*NsenterMounter) EvalHostSymlinks(pathname string) (string, error) { +// 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") } -func (*NsenterMounter) GetMountRefs(pathname string) ([]string, error) { +// 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") } -func (*NsenterMounter) GetFSGroup(pathname string) (int64, error) { +// 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") } -func (*NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) { +// 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") } -func (*NsenterMounter) GetMode(pathname string) (os.FileMode, error) { +// 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/subpath_nsenter_test.go b/pkg/volume/util/subpath/subpath_nsenter_test.go index c8e6270dc95..4ecb6916565 100644 --- a/pkg/volume/util/subpath/subpath_nsenter_test.go +++ b/pkg/volume/util/subpath/subpath_nsenter_test.go @@ -106,7 +106,7 @@ func TestCheckDeviceInode(t *testing.T) { } } -func newFakeNsenterMounter(tmpdir string, t *testing.T) (*nsutil.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) (*nsutil.NsenterMounter, return nil, "", "", nil, err } - return nsutil.NewNsenterMounter(varlibPath, ne), rootfsPath, varlibPath, ne, nil + return nsutil.NewMounter(varlibPath, ne), rootfsPath, varlibPath, ne, nil } func TestNsenterSafeMakeDir(t *testing.T) {