Merge pull request #65447 from wongma7/mapvolume-symlink

Automatic merge from submit-queue (batch tested with PRs 65492, 65516, 65447). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Resolve potential devicePath symlink when MapVolume in containerized kubelet

**What this PR does / why we need it**: Ensures local block volumes will work in case kubelet is running in a container

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #65445

**Special notes for your reviewer**: Code is mostly plumbing. If there is a better way to do it, let me know :)

I assume there will be e2e tests for the non-containerized case. I will need to test the containerized case myself, which may take a while.
**Release note**:

```release-note
NONE
```
pull/8/head
Kubernetes Submit Queue 2018-06-27 02:15:12 -07:00 committed by GitHub
commit 24ab69d358
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 46 additions and 0 deletions

View File

@ -140,6 +140,10 @@ func (m *execMounter) ExistsPath(pathname string) (bool, error) {
return m.wrappedMounter.ExistsPath(pathname)
}
func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) {
return m.wrappedMounter.EvalHostSymlinks(pathname)
}
func (m *execMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return m.wrappedMounter.PrepareSafeSubpath(subPath)
}

View File

@ -87,6 +87,10 @@ func (mounter *execMounter) ExistsPath(pathname string) (bool, error) {
return true, errors.New("not implemented")
}
func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) {
return "", errors.New("not implemented")
}
func (mounter *execMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return subPath.Path, nil, nil
}

View File

@ -212,6 +212,10 @@ func (f *FakeMounter) ExistsPath(pathname string) (bool, error) {
return false, nil
}
func (f *FakeMounter) EvalHostSymlinks(pathname string) (string, error) {
return pathname, nil
}
func (f *FakeMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return subPath.Path, nil, nil
}

View File

@ -96,6 +96,9 @@ type Interface interface {
// Will operate in the host mount namespace if kubelet is running in a container.
// Error is returned on any other error than "file not found".
ExistsPath(pathname string) (bool, error)
// EvalHostSymlinks returns the path name after evaluating symlinks.
// Will operate in the host mount namespace if kubelet is running in a container.
EvalHostSymlinks(pathname string) (string, error)
// CleanSubPaths removes any bind-mounts created by PrepareSafeSubpath in given
// pod volume directory.
CleanSubPaths(podDir string, volumeName string) error

View File

@ -419,6 +419,10 @@ func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
return utilfile.FileExists(pathname)
}
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
return filepath.EvalSymlinks(pathname)
}
// formatAndMount uses unix utils to format and mount the given disk
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
readOnly := false

View File

@ -106,6 +106,10 @@ func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
return true, errors.New("not implemented")
}
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
return "", unsupportedErr
}
func (mounter *Mounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return subPath.Path, nil, unsupportedErr
}

View File

@ -232,6 +232,11 @@ func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
return utilfile.FileExists(pathname)
}
// EvalHostSymlinks returns the path name after evaluating symlinks
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
return filepath.EvalSymlinks(pathname)
}
// check whether hostPath is within volume path
// this func will lock all intermediate subpath directories, need to close handle outside of this func after container started
func lockAndCheckSubPath(volumePath, hostPath string) ([]uintptr, error) {

View File

@ -287,6 +287,10 @@ func (mounter *NsenterMounter) ExistsPath(pathname string) (bool, error) {
return utilfile.FileExists(kubeletpath)
}
func (mounter *NsenterMounter) EvalHostSymlinks(pathname string) (string, error) {
return mounter.ne.EvalSymlinks(pathname, true)
}
func (mounter *NsenterMounter) CleanSubPaths(podDir string, volumeName string) error {
return doCleanSubPaths(mounter, podDir, volumeName)
}

View File

@ -89,6 +89,10 @@ 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) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil
}

View File

@ -866,6 +866,16 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
return volumeToMount.GenerateError("MapVolume failed", fmt.Errorf("Device path of the volume is empty"))
}
// When kubelet is containerized, devicePath may be a symlink at a place unavailable to
// kubelet, so evaluate it on the host and expect that it links to a device in /dev,
// which will be available to containerized kubelet. If still it does not exist,
// AttachFileDevice will fail. If kubelet is not containerized, eval it anyway.
mounter := og.GetVolumePluginMgr().Host.GetMounter(blockVolumePlugin.GetPluginName())
devicePath, err = mounter.EvalHostSymlinks(devicePath)
if err != nil {
return volumeToMount.GenerateError("MapVolume.EvalHostSymlinks failed", err)
}
// Map device to global and pod device map path
volumeMapPath, volName := blockVolumeMapper.GetPodDeviceMapPath()
mapErr = blockVolumeMapper.MapDevice(devicePath, globalMapPath, volumeMapPath, volName, volumeToMount.Pod.UID)