From b376b31ee077860b97ca8207e37e75df1fca510d Mon Sep 17 00:00:00 2001 From: Matthew Wong Date: Tue, 26 Jun 2018 11:57:34 -0400 Subject: [PATCH] Resolve potential devicePath symlink when MapVolume in containerized kubelet --- pkg/util/mount/exec_mount.go | 4 ++++ pkg/util/mount/exec_mount_unsupported.go | 4 ++++ pkg/util/mount/fake.go | 4 ++++ pkg/util/mount/mount.go | 3 +++ pkg/util/mount/mount_linux.go | 4 ++++ pkg/util/mount/mount_unsupported.go | 4 ++++ pkg/util/mount/mount_windows.go | 5 +++++ pkg/util/mount/nsenter_mount.go | 4 ++++ pkg/util/mount/nsenter_mount_unsupported.go | 4 ++++ .../util/operationexecutor/operation_generator.go | 10 ++++++++++ 10 files changed, 46 insertions(+) diff --git a/pkg/util/mount/exec_mount.go b/pkg/util/mount/exec_mount.go index fe7dcbd7ef9..3c6638328f6 100644 --- a/pkg/util/mount/exec_mount.go +++ b/pkg/util/mount/exec_mount.go @@ -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) } diff --git a/pkg/util/mount/exec_mount_unsupported.go b/pkg/util/mount/exec_mount_unsupported.go index 6854b32b26c..d5a1fdc58c6 100644 --- a/pkg/util/mount/exec_mount_unsupported.go +++ b/pkg/util/mount/exec_mount_unsupported.go @@ -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 } diff --git a/pkg/util/mount/fake.go b/pkg/util/mount/fake.go index 55c99c9fe3d..a354ca99fd8 100644 --- a/pkg/util/mount/fake.go +++ b/pkg/util/mount/fake.go @@ -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 } diff --git a/pkg/util/mount/mount.go b/pkg/util/mount/mount.go index f5ce194cac6..ea9cbe1c690 100644 --- a/pkg/util/mount/mount.go +++ b/pkg/util/mount/mount.go @@ -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 diff --git a/pkg/util/mount/mount_linux.go b/pkg/util/mount/mount_linux.go index 43a150fc026..5f8e3905211 100644 --- a/pkg/util/mount/mount_linux.go +++ b/pkg/util/mount/mount_linux.go @@ -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 diff --git a/pkg/util/mount/mount_unsupported.go b/pkg/util/mount/mount_unsupported.go index b2edebb5662..cd6f1a28f28 100644 --- a/pkg/util/mount/mount_unsupported.go +++ b/pkg/util/mount/mount_unsupported.go @@ -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 } diff --git a/pkg/util/mount/mount_windows.go b/pkg/util/mount/mount_windows.go index 28d41038269..2aa92ca1df2 100644 --- a/pkg/util/mount/mount_windows.go +++ b/pkg/util/mount/mount_windows.go @@ -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) { diff --git a/pkg/util/mount/nsenter_mount.go b/pkg/util/mount/nsenter_mount.go index a122411cec2..bf2dbf630b1 100644 --- a/pkg/util/mount/nsenter_mount.go +++ b/pkg/util/mount/nsenter_mount.go @@ -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) } diff --git a/pkg/util/mount/nsenter_mount_unsupported.go b/pkg/util/mount/nsenter_mount_unsupported.go index f417ba9bc15..87c2e9ec73d 100644 --- a/pkg/util/mount/nsenter_mount_unsupported.go +++ b/pkg/util/mount/nsenter_mount_unsupported.go @@ -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 } diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 51f321ae9d4..68085163701 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -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)