Merge pull request #68513 from codenrhoden/mount-refactor
Refactor util/mount interface in prep for moving out of k/k
This commit is contained in:
commit
2501a9083d
@ -372,6 +372,7 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err
|
||||
|
||||
mounter := mount.New(s.ExperimentalMounterPath)
|
||||
subpather := subpath.New(mounter)
|
||||
hu := mount.NewHostUtil()
|
||||
var pluginRunner = exec.New()
|
||||
if s.Containerized {
|
||||
klog.V(2).Info("Running kubelet in containerized mode")
|
||||
@ -382,6 +383,7 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err
|
||||
mounter = nsutil.NewMounter(s.RootDirectory, ne)
|
||||
// NSenter only valid on Linux
|
||||
subpather = subpath.NewNSEnter(mounter, ne, s.RootDirectory)
|
||||
hu = nsutil.NewHostUtil(ne, s.RootDirectory)
|
||||
// an exec interface which can use nsenter for flex plugin calls
|
||||
pluginRunner, err = nsenter.NewNsenter(nsenter.DefaultHostRootFsPath, exec.New())
|
||||
if err != nil {
|
||||
@ -407,6 +409,7 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err
|
||||
KubeClient: nil,
|
||||
HeartbeatClient: nil,
|
||||
EventClient: nil,
|
||||
HostUtil: hu,
|
||||
Mounter: mounter,
|
||||
Subpather: subpather,
|
||||
OOMAdjuster: oom.NewOOMAdjuster(),
|
||||
|
@ -250,6 +250,7 @@ type Dependencies struct {
|
||||
OnHeartbeatFailure func()
|
||||
KubeClient clientset.Interface
|
||||
Mounter mount.Interface
|
||||
HostUtil mount.HostUtils
|
||||
OOMAdjuster *oom.OOMAdjuster
|
||||
OSInterface kubecontainer.OSInterface
|
||||
PodConfig *config.PodConfig
|
||||
@ -518,6 +519,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
||||
cgroupsPerQOS: kubeCfg.CgroupsPerQOS,
|
||||
cgroupRoot: kubeCfg.CgroupRoot,
|
||||
mounter: kubeDeps.Mounter,
|
||||
hostutil: kubeDeps.HostUtil,
|
||||
subpather: kubeDeps.Subpather,
|
||||
maxPods: int(kubeCfg.MaxPods),
|
||||
podsPerCore: int(kubeCfg.PodsPerCore),
|
||||
@ -809,6 +811,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
||||
klet.volumePluginMgr,
|
||||
klet.containerRuntime,
|
||||
kubeDeps.Mounter,
|
||||
kubeDeps.HostUtil,
|
||||
klet.getPodsDir(),
|
||||
kubeDeps.Recorder,
|
||||
experimentalCheckNodeCapabilitiesBeforeMount,
|
||||
@ -1093,6 +1096,9 @@ type Kubelet struct {
|
||||
// Mounter to use for volumes.
|
||||
mounter mount.Interface
|
||||
|
||||
// hostutil to interact with filesystems
|
||||
hostutil mount.HostUtils
|
||||
|
||||
// subpather to execute subpath actions
|
||||
subpather subpath.Interface
|
||||
|
||||
@ -1223,7 +1229,7 @@ func (kl *Kubelet) setupDataDirs() error {
|
||||
if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
|
||||
return fmt.Errorf("error creating root directory: %v", err)
|
||||
}
|
||||
if err := kl.mounter.MakeRShared(kl.getRootDir()); err != nil {
|
||||
if err := kl.hostutil.MakeRShared(kl.getRootDir()); err != nil {
|
||||
return fmt.Errorf("error configuring root directory: %v", err)
|
||||
}
|
||||
if err := os.MkdirAll(kl.getPodsDir(), 0750); err != nil {
|
||||
|
@ -128,7 +128,7 @@ func (kl *Kubelet) makeBlockVolumes(pod *v1.Pod, container *v1.Container, podVol
|
||||
}
|
||||
|
||||
// makeMounts determines the mount points for the given container.
|
||||
func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, hostDomain, podIP string, podVolumes kubecontainer.VolumeMap, mounter mountutil.Interface, subpather subpath.Interface, expandEnvs []kubecontainer.EnvVar) ([]kubecontainer.Mount, func(), error) {
|
||||
func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, hostDomain, podIP string, podVolumes kubecontainer.VolumeMap, hu mountutil.HostUtils, subpather subpath.Interface, expandEnvs []kubecontainer.EnvVar) ([]kubecontainer.Mount, func(), error) {
|
||||
// Kubernetes only mounts on /etc/hosts if:
|
||||
// - container is not an infrastructure (pause) container
|
||||
// - container is not already mounting on /etc/hosts
|
||||
@ -195,7 +195,7 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
|
||||
volumePath := hostPath
|
||||
hostPath = filepath.Join(volumePath, subPath)
|
||||
|
||||
if subPathExists, err := mounter.ExistsPath(hostPath); err != nil {
|
||||
if subPathExists, err := hu.ExistsPath(hostPath); err != nil {
|
||||
klog.Errorf("Could not determine if subPath %s exists; will not attempt to change its permissions", hostPath)
|
||||
} else if !subPathExists {
|
||||
// Create the sub path now because if it's auto-created later when referenced, it may have an
|
||||
@ -203,7 +203,7 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
|
||||
// when the pod specifies an fsGroup, and if the directory is not created here, Docker will
|
||||
// later auto-create it with the incorrect mode 0750
|
||||
// Make extra care not to escape the volume!
|
||||
perm, err := mounter.GetMode(volumePath)
|
||||
perm, err := hu.GetMode(volumePath)
|
||||
if err != nil {
|
||||
return nil, cleanupAction, err
|
||||
}
|
||||
@ -465,7 +465,7 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Contai
|
||||
}
|
||||
opts.Envs = append(opts.Envs, envs...)
|
||||
|
||||
mounts, cleanupAction, err := makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes, kl.mounter, kl.subpather, opts.Envs)
|
||||
mounts, cleanupAction, err := makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes, kl.hostutil, kl.subpather, opts.Envs)
|
||||
if err != nil {
|
||||
return nil, cleanupAction, err
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fm := &mount.FakeMounter{}
|
||||
fhu := &mount.FakeHostUtil{}
|
||||
fsp := &subpath.FakeSubpath{}
|
||||
pod := v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
@ -249,7 +249,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
mounts, _, err := makeMounts(&pod, "/pod", &tc.container, "fakepodname", "", "", tc.podVolumes, fm, fsp, nil)
|
||||
mounts, _, err := makeMounts(&pod, "/pod", &tc.container, "fakepodname", "", "", tc.podVolumes, fhu, fsp, nil)
|
||||
|
||||
// validate only the error if we expect an error
|
||||
if tc.expectErr {
|
||||
|
@ -53,7 +53,7 @@ import (
|
||||
)
|
||||
|
||||
func TestDisabledSubpath(t *testing.T) {
|
||||
fm := &mount.FakeMounter{}
|
||||
fhu := &mount.FakeHostUtil{}
|
||||
fsp := &subpath.FakeSubpath{}
|
||||
pod := v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
@ -97,7 +97,7 @@ func TestDisabledSubpath(t *testing.T) {
|
||||
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, false)()
|
||||
for name, test := range cases {
|
||||
_, _, err := makeMounts(&pod, "/pod", &test.container, "fakepodname", "", "", podVolumes, fm, fsp, nil)
|
||||
_, _, err := makeMounts(&pod, "/pod", &test.container, "fakepodname", "", "", podVolumes, fhu, fsp, nil)
|
||||
if err != nil && !test.expectError {
|
||||
t.Errorf("test %v failed: %v", name, err)
|
||||
}
|
||||
|
@ -82,9 +82,9 @@ func TestMakeMountsWindows(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
fm := &mount.FakeMounter{}
|
||||
fhu := &mount.FakeHostUtil{}
|
||||
fsp := &subpath.FakeSubpath{}
|
||||
mounts, _, _ := makeMounts(&pod, "/pod", &container, "fakepodname", "", "", podVolumes, fm, fsp, nil)
|
||||
mounts, _, _ := makeMounts(&pod, "/pod", &container, "fakepodname", "", "", podVolumes, fhu, fsp, nil)
|
||||
|
||||
expectedMounts := []kubecontainer.Mount{
|
||||
{
|
||||
|
@ -162,6 +162,7 @@ func newTestKubeletWithImageList(
|
||||
kubelet.heartbeatClient = fakeKubeClient
|
||||
kubelet.os = &containertest.FakeOS{}
|
||||
kubelet.mounter = &mount.FakeMounter{}
|
||||
kubelet.hostutil = &mount.FakeHostUtil{}
|
||||
kubelet.subpather = &subpath.FakeSubpath{}
|
||||
|
||||
kubelet.hostname = testKubeletHostname
|
||||
@ -312,7 +313,6 @@ func newTestKubeletWithImageList(
|
||||
NewInitializedVolumePluginMgr(kubelet, kubelet.secretManager, kubelet.configMapManager, token.NewManager(kubelet.kubeClient), allPlugins, prober)
|
||||
require.NoError(t, err, "Failed to initialize VolumePluginMgr")
|
||||
|
||||
kubelet.mounter = &mount.FakeMounter{}
|
||||
kubelet.volumeManager = kubeletvolume.NewVolumeManager(
|
||||
controllerAttachDetachEnabled,
|
||||
kubelet.nodeName,
|
||||
@ -322,6 +322,7 @@ func newTestKubeletWithImageList(
|
||||
kubelet.volumePluginMgr,
|
||||
fakeRuntime,
|
||||
kubelet.mounter,
|
||||
kubelet.hostutil,
|
||||
kubelet.getPodsDir(),
|
||||
kubelet.recorder,
|
||||
false, /* experimentalCheckNodeCapabilitiesBeforeMount*/
|
||||
|
@ -85,6 +85,7 @@ func TestRunOnce(t *testing.T) {
|
||||
hostname: testKubeletHostname,
|
||||
nodeName: testKubeletHostname,
|
||||
runtimeState: newRuntimeState(time.Second),
|
||||
hostutil: &mount.FakeHostUtil{},
|
||||
}
|
||||
kb.containerManager = cm.NewStubContainerManager()
|
||||
|
||||
@ -103,6 +104,7 @@ func TestRunOnce(t *testing.T) {
|
||||
kb.volumePluginMgr,
|
||||
fakeRuntime,
|
||||
kb.mounter,
|
||||
kb.hostutil,
|
||||
kb.getPodsDir(),
|
||||
kb.recorder,
|
||||
false, /* experimentalCheckNodeCapabilitiesBeforeMount */
|
||||
|
@ -160,6 +160,10 @@ func (kvh *kubeletVolumeHost) GetSubpather() subpath.Interface {
|
||||
return kvh.kubelet.subpather
|
||||
}
|
||||
|
||||
func (kvh *kubeletVolumeHost) GetHostUtil() mount.HostUtils {
|
||||
return kvh.kubelet.hostutil
|
||||
}
|
||||
|
||||
func (kvh *kubeletVolumeHost) GetInformerFactory() informers.SharedInformerFactory {
|
||||
return kvh.informerFactory
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ type Reconciler interface {
|
||||
// safely (prevents more than one operation from being triggered on the same
|
||||
// volume)
|
||||
// mounter - mounter passed in from kubelet, passed down unmount path
|
||||
// hostutil - hostutil passed in from kubelet
|
||||
// volumePluginMgr - volume plugin manager passed from kubelet
|
||||
func NewReconciler(
|
||||
kubeClient clientset.Interface,
|
||||
@ -99,6 +100,7 @@ func NewReconciler(
|
||||
populatorHasAddedPods func() bool,
|
||||
operationExecutor operationexecutor.OperationExecutor,
|
||||
mounter mount.Interface,
|
||||
hostutil mount.HostUtils,
|
||||
volumePluginMgr *volumepkg.VolumePluginMgr,
|
||||
kubeletPodsDir string) Reconciler {
|
||||
return &reconciler{
|
||||
@ -112,6 +114,7 @@ func NewReconciler(
|
||||
populatorHasAddedPods: populatorHasAddedPods,
|
||||
operationExecutor: operationExecutor,
|
||||
mounter: mounter,
|
||||
hostutil: hostutil,
|
||||
volumePluginMgr: volumePluginMgr,
|
||||
kubeletPodsDir: kubeletPodsDir,
|
||||
timeOfLastSync: time.Time{},
|
||||
@ -130,6 +133,7 @@ type reconciler struct {
|
||||
populatorHasAddedPods func() bool
|
||||
operationExecutor operationexecutor.OperationExecutor
|
||||
mounter mount.Interface
|
||||
hostutil mount.HostUtils
|
||||
volumePluginMgr *volumepkg.VolumePluginMgr
|
||||
kubeletPodsDir string
|
||||
timeOfLastSync time.Time
|
||||
@ -278,7 +282,7 @@ func (rc *reconciler) reconcile() {
|
||||
// Volume is globally mounted to device, unmount it
|
||||
klog.V(5).Infof(attachedVolume.GenerateMsgDetailed("Starting operationExecutor.UnmountDevice", ""))
|
||||
err := rc.operationExecutor.UnmountDevice(
|
||||
attachedVolume.AttachedVolume, rc.actualStateOfWorld, rc.mounter)
|
||||
attachedVolume.AttachedVolume, rc.actualStateOfWorld, rc.hostutil)
|
||||
if err != nil &&
|
||||
!nestedpendingoperations.IsAlreadyExists(err) &&
|
||||
!exponentialbackoff.IsExponentialBackoff(err) {
|
||||
|
@ -84,6 +84,7 @@ func Test_Run_Positive_DoNothing(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
|
||||
@ -127,6 +128,7 @@ func Test_Run_Positive_VolumeAttachAndMount(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -204,6 +206,7 @@ func Test_Run_Positive_VolumeMountControllerAttachEnabled(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -282,6 +285,7 @@ func Test_Run_Positive_VolumeAttachMountUnmountDetach(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -371,6 +375,7 @@ func Test_Run_Positive_VolumeUnmountControllerAttachEnabled(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -461,6 +466,7 @@ func Test_Run_Positive_VolumeAttachAndMap(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -545,6 +551,7 @@ func Test_Run_Positive_BlockVolumeMapControllerAttachEnabled(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -630,6 +637,7 @@ func Test_Run_Positive_BlockVolumeAttachMapUnmapDetach(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -725,6 +733,7 @@ func Test_Run_Positive_VolumeUnmapControllerAttachEnabled(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
@ -918,11 +927,11 @@ func Test_GenerateUnmapDeviceFunc_Plugin_Not_Found(t *testing.T) {
|
||||
nil, /* fakeRecorder */
|
||||
false, /* checkNodeCapabilitiesBeforeMount */
|
||||
nil))
|
||||
var mounter mount.Interface
|
||||
var hostutil mount.HostUtils
|
||||
volumeMode := v1.PersistentVolumeBlock
|
||||
tmpSpec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{VolumeMode: &volumeMode}}}
|
||||
deviceToDetach := operationexecutor.AttachedVolume{VolumeSpec: tmpSpec, PluginName: "fake-file-plugin"}
|
||||
err := oex.UnmountDevice(deviceToDetach, asw, mounter)
|
||||
err := oex.UnmountDevice(deviceToDetach, asw, hostutil)
|
||||
// Assert
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), tc.expectedErrMsg)
|
||||
@ -1004,6 +1013,7 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
|
||||
@ -1181,6 +1191,7 @@ func Test_Run_Positive_VolumeMountControllerAttachEnabledRace(t *testing.T) {
|
||||
hasAddedPods,
|
||||
oex,
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
pod := &v1.Pod{
|
||||
|
@ -151,6 +151,7 @@ func NewVolumeManager(
|
||||
volumePluginMgr *volume.VolumePluginMgr,
|
||||
kubeContainerRuntime container.Runtime,
|
||||
mounter mount.Interface,
|
||||
hostutil mount.HostUtils,
|
||||
kubeletPodsDir string,
|
||||
recorder record.EventRecorder,
|
||||
checkNodeCapabilitiesBeforeMount bool,
|
||||
@ -190,6 +191,7 @@ func NewVolumeManager(
|
||||
vm.desiredStateOfWorldPopulator.HasAddedPods,
|
||||
vm.operationExecutor,
|
||||
mounter,
|
||||
hostutil,
|
||||
volumePluginMgr,
|
||||
kubeletPodsDir)
|
||||
|
||||
|
@ -232,6 +232,7 @@ func newTestVolumeManager(tmpDir string, podManager kubepod.Manager, kubeClient
|
||||
plugMgr,
|
||||
&containertest.FakeRuntime{},
|
||||
&mount.FakeMounter{},
|
||||
&mount.FakeHostUtil{},
|
||||
"",
|
||||
fakeRecorder,
|
||||
false, /* experimentalCheckNodeCapabilitiesBeforeMount */
|
||||
|
@ -80,6 +80,7 @@ func NewHollowKubelet(
|
||||
OOMAdjuster: oom.NewFakeOOMAdjuster(),
|
||||
Mounter: mount.New("" /* default mount path */),
|
||||
Subpather: &subpath.FakeSubpath{},
|
||||
HostUtil: &mount.FakeHostUtil{},
|
||||
}
|
||||
|
||||
return &HollowKubelet{
|
||||
|
@ -29,7 +29,6 @@ import (
|
||||
type FakeMounter struct {
|
||||
MountPoints []MountPoint
|
||||
Log []FakeAction
|
||||
Filesystem map[string]FileType
|
||||
// Error to return for a path when calling IsLikelyNotMountPoint
|
||||
MountCheckErrors map[string]error
|
||||
// Some tests run things in parallel, make sure the mounter does not produce
|
||||
@ -166,56 +165,6 @@ func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
for _, mp := range f.MountPoints {
|
||||
if mp.Device == pathname {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return getDeviceNameFromMount(f, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetFileType(pathname string) (FileType, error) {
|
||||
if t, ok := f.Filesystem[pathname]; ok {
|
||||
return t, nil
|
||||
}
|
||||
return FileType("Directory"), nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) ExistsPath(pathname string) (bool, error) {
|
||||
if _, ok := f.Filesystem[pathname]; ok {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return pathname, nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
realpath, err := filepath.EvalSymlinks(pathname)
|
||||
if err != nil {
|
||||
@ -225,14 +174,73 @@ func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return getMountRefsByDev(f, realpath)
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
type FakeHostUtil struct {
|
||||
MountPoints []MountPoint
|
||||
Filesystem map[string]FileType
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
var _ HostUtils = &FakeHostUtil{}
|
||||
|
||||
func (hu *FakeHostUtil) DeviceOpened(pathname string) (bool, error) {
|
||||
hu.mutex.Lock()
|
||||
defer hu.mutex.Unlock()
|
||||
|
||||
for _, mp := range hu.MountPoints {
|
||||
if mp.Device == pathname {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) GetDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) GetFileType(pathname string) (FileType, error) {
|
||||
if t, ok := hu.Filesystem[pathname]; ok {
|
||||
return t, nil
|
||||
}
|
||||
return FileType("Directory"), nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) ExistsPath(pathname string) (bool, error) {
|
||||
if _, ok := hu.Filesystem[pathname]; ok {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return pathname, nil
|
||||
}
|
||||
|
||||
func (hu *FakeHostUtil) GetFSGroup(pathname string) (int64, error) {
|
||||
return -1, errors.New("GetFSGroup not implemented")
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
func (hu *FakeHostUtil) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return false, errors.New("GetSELinuxSupport not implemented")
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
func (hu *FakeHostUtil) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
|
@ -55,6 +55,13 @@ type Interface interface {
|
||||
// IsLikelyNotMountPoint does NOT properly detect all mountpoint types
|
||||
// most notably linux bind mounts and symbolic link.
|
||||
IsLikelyNotMountPoint(file string) (bool, 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).
|
||||
GetMountRefs(pathname string) ([]string, error)
|
||||
}
|
||||
|
||||
type HostUtils interface {
|
||||
// DeviceOpened determines if the device is in use elsewhere
|
||||
// on the system, i.e. still mounted.
|
||||
DeviceOpened(pathname string) (bool, error)
|
||||
@ -62,7 +69,7 @@ type Interface interface {
|
||||
PathIsDevice(pathname string) (bool, error)
|
||||
// GetDeviceNameFromMount finds the device name by checking the mount path
|
||||
// to get the global mount path within its plugin directory
|
||||
GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error)
|
||||
GetDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error)
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. If not, it bind-mounts the path as rshared.
|
||||
MakeRShared(path string) error
|
||||
@ -81,10 +88,6 @@ type Interface interface {
|
||||
// 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)
|
||||
// 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).
|
||||
GetMountRefs(pathname string) ([]string, error)
|
||||
// GetFSGroup returns FSGroup of the path.
|
||||
GetFSGroup(pathname string) (int64, error)
|
||||
// GetSELinuxSupport returns true if given path is on a mount that supports
|
||||
@ -123,6 +126,10 @@ type Exec interface {
|
||||
// the mount interface
|
||||
var _ Interface = &Mounter{}
|
||||
|
||||
// Compile-time check to ensure all HostUtil implementations satisfy
|
||||
// the HostUtils Interface
|
||||
var _ HostUtils = &hostUtil{}
|
||||
|
||||
// This represents a single line in /proc/mounts or /etc/fstab.
|
||||
type MountPoint struct {
|
||||
Device string
|
||||
@ -239,7 +246,8 @@ func IsNotMountPoint(mounter Interface, file string) (bool, error) {
|
||||
}
|
||||
|
||||
// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts
|
||||
resolvedFile, err := mounter.EvalHostSymlinks(file)
|
||||
hu := NewHostUtil()
|
||||
resolvedFile, err := hu.EvalHostSymlinks(file)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
@ -21,11 +21,17 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDoCleanupMountPoint(t *testing.T) {
|
||||
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Skipf("not supported on GOOS=%s", runtime.GOOS)
|
||||
}
|
||||
|
||||
const testMount = "test-mount"
|
||||
const defaultPerm = 0750
|
||||
|
||||
|
@ -249,179 +249,21 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// If pathname is not a device, log and return false with nil error.
|
||||
// If open returns errno EBUSY, return true with nil 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)
|
||||
}
|
||||
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
||||
pathType, err := mounter.GetFileType(pathname)
|
||||
isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
|
||||
return isDevice, err
|
||||
}
|
||||
|
||||
// ExclusiveOpenFailsOnDevice is shared with NsEnterMounter
|
||||
func ExclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
||||
var isDevice bool
|
||||
finfo, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
isDevice = false
|
||||
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
pathExists, pathErr := PathExists(pathname)
|
||||
if !pathExists {
|
||||
return []string{}, nil
|
||||
} else if IsCorruptedMnt(pathErr) {
|
||||
klog.Warningf("GetMountRefs found corrupted mount at %s, treating as unmounted path", pathname)
|
||||
return []string{}, nil
|
||||
} else if pathErr != nil {
|
||||
return nil, fmt.Errorf("error checking path %s: %v", pathname, pathErr)
|
||||
}
|
||||
// err in call to os.Stat
|
||||
if err != nil {
|
||||
return false, fmt.Errorf(
|
||||
"PathIsDevice failed for path %q: %v",
|
||||
pathname,
|
||||
err)
|
||||
}
|
||||
// path refers to a device
|
||||
if finfo.Mode()&os.ModeDevice != 0 {
|
||||
isDevice = true
|
||||
}
|
||||
|
||||
if !isDevice {
|
||||
klog.Errorf("Path %q is not referring to a device.", pathname)
|
||||
return false, nil
|
||||
}
|
||||
fd, errno := unix.Open(pathname, unix.O_RDONLY|unix.O_EXCL, 0)
|
||||
// If the device is in use, open will return an invalid fd.
|
||||
// When this happens, it is expected that Close will fail and throw an error.
|
||||
defer unix.Close(fd)
|
||||
if errno == nil {
|
||||
// device not in use
|
||||
return false, nil
|
||||
} else if errno == unix.EBUSY {
|
||||
// device is in use
|
||||
return true, nil
|
||||
}
|
||||
// error during call to Open
|
||||
return false, errno
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount: given a mount point, find the device name from its global mount point
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMountLinux find the device name from /proc/mounts in which
|
||||
// the mount path reference should match the given plugin mount directory. In case no mount path reference
|
||||
// matches, returns the volume name taken from its given mountPath
|
||||
// This implementation is shared with NsEnterMounter
|
||||
func GetDeviceNameFromMountLinux(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
refs, err := mounter.GetMountRefs(mountPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
if len(refs) == 0 {
|
||||
klog.V(4).Infof("Directory %s is not mounted", mountPath)
|
||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||
}
|
||||
for _, ref := range refs {
|
||||
if strings.HasPrefix(ref, pluginMountDir) {
|
||||
volumeID, err := filepath.Rel(pluginMountDir, ref)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
return volumeID, nil
|
||||
}
|
||||
}
|
||||
|
||||
return path.Base(mountPath), nil
|
||||
}
|
||||
|
||||
// ListProcMounts is shared with NsEnterMounter
|
||||
func ListProcMounts(mountFilePath string) ([]MountPoint, error) {
|
||||
content, err := utilio.ConsistentRead(mountFilePath, maxListTries)
|
||||
realpath, err := filepath.EvalSymlinks(pathname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseProcMounts(content)
|
||||
}
|
||||
|
||||
func parseProcMounts(content []byte) ([]MountPoint, error) {
|
||||
out := []MountPoint{}
|
||||
lines := strings.Split(string(content), "\n")
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
// the last split() item is empty string following the last \n
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != expectedNumFieldsPerLine {
|
||||
return nil, fmt.Errorf("wrong number of fields (expected %d, got %d): %s", expectedNumFieldsPerLine, len(fields), line)
|
||||
}
|
||||
|
||||
mp := MountPoint{
|
||||
Device: fields[0],
|
||||
Path: fields[1],
|
||||
Type: fields[2],
|
||||
Opts: strings.Split(fields[3], ","),
|
||||
}
|
||||
|
||||
freq, err := strconv.Atoi(fields[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Freq = freq
|
||||
|
||||
pass, err := strconv.Atoi(fields[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Pass = pass
|
||||
|
||||
out = append(out, mp)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return DoMakeRShared(path, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
return getFileType(pathname)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeDir(pathname string) error {
|
||||
err := os.MkdirAll(pathname, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeFile(pathname string) error {
|
||||
f, err := os.OpenFile(pathname, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
|
||||
return utilpath.Exists(utilpath.CheckFollowSymlink, pathname)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return filepath.EvalSymlinks(pathname)
|
||||
return SearchMountPoints(realpath, procMountInfoPath)
|
||||
}
|
||||
|
||||
// formatAndMount uses unix utils to format and mount the given disk
|
||||
@ -562,6 +404,188 @@ func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
|
||||
return fstype, nil
|
||||
}
|
||||
|
||||
// ListProcMounts is shared with NsEnterMounter
|
||||
func ListProcMounts(mountFilePath string) ([]MountPoint, error) {
|
||||
content, err := utilio.ConsistentRead(mountFilePath, maxListTries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseProcMounts(content)
|
||||
}
|
||||
|
||||
func parseProcMounts(content []byte) ([]MountPoint, error) {
|
||||
out := []MountPoint{}
|
||||
lines := strings.Split(string(content), "\n")
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
// the last split() item is empty string following the last \n
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != expectedNumFieldsPerLine {
|
||||
return nil, fmt.Errorf("wrong number of fields (expected %d, got %d): %s", expectedNumFieldsPerLine, len(fields), line)
|
||||
}
|
||||
|
||||
mp := MountPoint{
|
||||
Device: fields[0],
|
||||
Path: fields[1],
|
||||
Type: fields[2],
|
||||
Opts: strings.Split(fields[3], ","),
|
||||
}
|
||||
|
||||
freq, err := strconv.Atoi(fields[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Freq = freq
|
||||
|
||||
pass, err := strconv.Atoi(fields[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Pass = pass
|
||||
|
||||
out = append(out, mp)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type hostUtil struct {
|
||||
}
|
||||
|
||||
func NewHostUtil() HostUtils {
|
||||
return &hostUtil{}
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// If pathname is not a device, log and return false with nil error.
|
||||
// If open returns errno EBUSY, return true with nil error.
|
||||
// If open returns nil, return false with nil error.
|
||||
// Otherwise, return false with error
|
||||
func (hu *hostUtil) DeviceOpened(pathname string) (bool, error) {
|
||||
return ExclusiveOpenFailsOnDevice(pathname)
|
||||
}
|
||||
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (hu *hostUtil) PathIsDevice(pathname string) (bool, error) {
|
||||
pathType, err := hu.GetFileType(pathname)
|
||||
isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
|
||||
return isDevice, err
|
||||
}
|
||||
|
||||
// ExclusiveOpenFailsOnDevice is shared with NsEnterMounter
|
||||
func ExclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
||||
var isDevice bool
|
||||
finfo, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
isDevice = false
|
||||
}
|
||||
// err in call to os.Stat
|
||||
if err != nil {
|
||||
return false, fmt.Errorf(
|
||||
"PathIsDevice failed for path %q: %v",
|
||||
pathname,
|
||||
err)
|
||||
}
|
||||
// path refers to a device
|
||||
if finfo.Mode()&os.ModeDevice != 0 {
|
||||
isDevice = true
|
||||
}
|
||||
|
||||
if !isDevice {
|
||||
klog.Errorf("Path %q is not referring to a device.", pathname)
|
||||
return false, nil
|
||||
}
|
||||
fd, errno := unix.Open(pathname, unix.O_RDONLY|unix.O_EXCL, 0)
|
||||
// If the device is in use, open will return an invalid fd.
|
||||
// When this happens, it is expected that Close will fail and throw an error.
|
||||
defer unix.Close(fd)
|
||||
if errno == nil {
|
||||
// device not in use
|
||||
return false, nil
|
||||
} else if errno == unix.EBUSY {
|
||||
// device is in use
|
||||
return true, nil
|
||||
}
|
||||
// error during call to Open
|
||||
return false, errno
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount: given a mount point, find the device name from its global mount point
|
||||
func (hu *hostUtil) GetDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMountLinux find the device name from /proc/mounts in which
|
||||
// the mount path reference should match the given plugin mount directory. In case no mount path reference
|
||||
// matches, returns the volume name taken from its given mountPath
|
||||
// This implementation is shared with NsEnterMounter
|
||||
func GetDeviceNameFromMountLinux(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
refs, err := mounter.GetMountRefs(mountPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
if len(refs) == 0 {
|
||||
klog.V(4).Infof("Directory %s is not mounted", mountPath)
|
||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||
}
|
||||
for _, ref := range refs {
|
||||
if strings.HasPrefix(ref, pluginMountDir) {
|
||||
volumeID, err := filepath.Rel(pluginMountDir, ref)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
return volumeID, nil
|
||||
}
|
||||
}
|
||||
|
||||
return path.Base(mountPath), nil
|
||||
}
|
||||
|
||||
func (hu *hostUtil) MakeRShared(path string) error {
|
||||
return DoMakeRShared(path, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (hu *hostUtil) GetFileType(pathname string) (FileType, error) {
|
||||
return getFileType(pathname)
|
||||
}
|
||||
|
||||
func (hu *hostUtil) MakeDir(pathname string) error {
|
||||
err := os.MkdirAll(pathname, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hu *hostUtil) MakeFile(pathname string) error {
|
||||
f, err := os.OpenFile(pathname, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hu *hostUtil) ExistsPath(pathname string) (bool, error) {
|
||||
return utilpath.Exists(utilpath.CheckFollowSymlink, pathname)
|
||||
}
|
||||
|
||||
func (hu *hostUtil) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return filepath.EvalSymlinks(pathname)
|
||||
}
|
||||
|
||||
// isShared returns true, if given path is on a mount point that has shared
|
||||
// mount propagation.
|
||||
func isShared(mount string, mountInfoPath string) (bool, error) {
|
||||
@ -726,28 +750,11 @@ func GetSELinux(path string, mountInfoFilename string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
pathExists, pathErr := PathExists(pathname)
|
||||
if !pathExists {
|
||||
return []string{}, nil
|
||||
} else if IsCorruptedMnt(pathErr) {
|
||||
klog.Warningf("GetMountRefs found corrupted mount at %s, treating as unmounted path", pathname)
|
||||
return []string{}, nil
|
||||
} else if pathErr != nil {
|
||||
return nil, fmt.Errorf("error checking path %s: %v", pathname, pathErr)
|
||||
}
|
||||
realpath, err := filepath.EvalSymlinks(pathname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return SearchMountPoints(realpath, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
func (hu *hostUtil) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return GetSELinux(pathname, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
func (hu *hostUtil) GetFSGroup(pathname string) (int64, error) {
|
||||
realpath, err := filepath.EvalSymlinks(pathname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@ -755,7 +762,7 @@ func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return GetFSGroupLinux(realpath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
func (hu *hostUtil) GetMode(pathname string) (os.FileMode, error) {
|
||||
return GetModeLinux(pathname)
|
||||
}
|
||||
|
||||
|
@ -661,7 +661,7 @@ func createSocketFile(socketDir string) (string, error) {
|
||||
}
|
||||
|
||||
func TestGetFileType(t *testing.T) {
|
||||
mounter := Mounter{"fake/path", false}
|
||||
hu := NewHostUtil()
|
||||
|
||||
testCase := []struct {
|
||||
name string
|
||||
@ -750,7 +750,7 @@ func TestGetFileType(t *testing.T) {
|
||||
defer os.RemoveAll(cleanUpPath)
|
||||
}
|
||||
|
||||
fileType, err := mounter.GetFileType(path)
|
||||
fileType, err := hu.GetFileType(path)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d-%s] unexpected error : %v", idx, tc.name, err)
|
||||
}
|
||||
|
@ -58,24 +58,8 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return unsupportedErr
|
||||
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
|
||||
@ -86,38 +70,65 @@ func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, erro
|
||||
return true, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
return FileType("fake"), unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeDir(pathname string) error {
|
||||
return unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeFile(pathname string) error {
|
||||
return unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
|
||||
return true, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
type hostUtil struct{}
|
||||
|
||||
func NewHostUtil() HostUtils {
|
||||
return &hostUtil{}
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return -1, errors.New("not implemented")
|
||||
// DeviceOpened determines if the device is in use elsewhere
|
||||
func (hu *hostUtil) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return false, errors.New("not implemented")
|
||||
// PathIsDevice determines if a path is a device.
|
||||
func (hu *hostUtil) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, unsupportedErr
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
// GetDeviceNameFromMount finds the device name by checking the mount path
|
||||
// to get the global mount path within its plugin directory
|
||||
func (hu *hostUtil) GetDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) MakeRShared(path string) error {
|
||||
return unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) GetFileType(pathname string) (FileType, error) {
|
||||
return FileType("fake"), unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) MakeFile(pathname string) error {
|
||||
return unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) MakeDir(pathname string) error {
|
||||
return unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) ExistsPath(pathname string) (bool, error) {
|
||||
return true, unsupportedErr
|
||||
}
|
||||
|
||||
// EvalHostSymlinks returns the path name after evaluating symlinks
|
||||
func (hu *hostUtil) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return "", unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) GetFSGroup(pathname string) (int64, error) {
|
||||
return -1, unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return false, unsupportedErr
|
||||
}
|
||||
|
||||
func (hu *hostUtil) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, unsupportedErr
|
||||
}
|
||||
|
@ -185,7 +185,8 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("readlink error: %v", err)
|
||||
}
|
||||
exists, err := mounter.ExistsPath(target)
|
||||
hu := NewHostUtil()
|
||||
exists, err := hu.ExistsPath(target)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
@ -195,90 +196,19 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMount given a mnt point, find the device
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// getDeviceNameFromMount find the device(drive) name in which
|
||||
// the mount path reference should match the given plugin mount directory. In case no mount path reference
|
||||
// matches, returns the volume name taken from its given mountPath
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
refs, err := mounter.GetMountRefs(mountPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||
return "", err
|
||||
// GetMountRefs : empty implementation here since there is no place to query all mount points on Windows
|
||||
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
windowsPath := normalizeWindowsPath(pathname)
|
||||
pathExists, pathErr := PathExists(windowsPath)
|
||||
if !pathExists {
|
||||
return []string{}, nil
|
||||
} else if IsCorruptedMnt(pathErr) {
|
||||
klog.Warningf("GetMountRefs found corrupted mount at %s, treating as unmounted path", windowsPath)
|
||||
return []string{}, nil
|
||||
} else if pathErr != nil {
|
||||
return nil, fmt.Errorf("error checking path %s: %v", windowsPath, pathErr)
|
||||
}
|
||||
if len(refs) == 0 {
|
||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||
}
|
||||
basemountPath := normalizeWindowsPath(pluginMountDir)
|
||||
for _, ref := range refs {
|
||||
if strings.Contains(ref, basemountPath) {
|
||||
volumeID, err := filepath.Rel(normalizeWindowsPath(basemountPath), ref)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
return volumeID, nil
|
||||
}
|
||||
}
|
||||
|
||||
return path.Base(mountPath), nil
|
||||
}
|
||||
|
||||
// DeviceOpened determines if the device is in use elsewhere
|
||||
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// PathIsDevice determines if a path is a device.
|
||||
func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. Empty implementation here.
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFileType checks for sockets/block/character devices
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
return getFileType(pathname)
|
||||
}
|
||||
|
||||
// MakeFile creates a new directory
|
||||
func (mounter *Mounter) MakeDir(pathname string) error {
|
||||
err := os.MkdirAll(pathname, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeFile creates an empty file
|
||||
func (mounter *Mounter) MakeFile(pathname string) error {
|
||||
f, err := os.OpenFile(pathname, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistsPath checks whether the path exists
|
||||
func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
|
||||
return utilpath.Exists(utilpath.CheckFollowSymlink, pathname)
|
||||
}
|
||||
|
||||
// EvalHostSymlinks returns the path name after evaluating symlinks
|
||||
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return filepath.EvalSymlinks(pathname)
|
||||
return []string{pathname}, nil
|
||||
}
|
||||
|
||||
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
|
||||
@ -379,33 +309,110 @@ func getAllParentLinks(path string) ([]string, error) {
|
||||
return links, nil
|
||||
}
|
||||
|
||||
// GetMountRefs : empty implementation here since there is no place to query all mount points on Windows
|
||||
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
windowsPath := normalizeWindowsPath(pathname)
|
||||
pathExists, pathErr := PathExists(windowsPath)
|
||||
if !pathExists {
|
||||
return []string{}, nil
|
||||
} else if IsCorruptedMnt(pathErr) {
|
||||
klog.Warningf("GetMountRefs found corrupted mount at %s, treating as unmounted path", windowsPath)
|
||||
return []string{}, nil
|
||||
} else if pathErr != nil {
|
||||
return nil, fmt.Errorf("error checking path %s: %v", windowsPath, pathErr)
|
||||
type hostUtil struct{}
|
||||
|
||||
func NewHostUtil() HostUtils {
|
||||
return &hostUtil{}
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMount given a mnt point, find the device
|
||||
func (hu *hostUtil) GetDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// getDeviceNameFromMount find the device(drive) name in which
|
||||
// the mount path reference should match the given plugin mount directory. In case no mount path reference
|
||||
// matches, returns the volume name taken from its given mountPath
|
||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
refs, err := mounter.GetMountRefs(mountPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
return []string{pathname}, nil
|
||||
if len(refs) == 0 {
|
||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||
}
|
||||
basemountPath := normalizeWindowsPath(pluginMountDir)
|
||||
for _, ref := range refs {
|
||||
if strings.Contains(ref, basemountPath) {
|
||||
volumeID, err := filepath.Rel(normalizeWindowsPath(basemountPath), ref)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||
return "", err
|
||||
}
|
||||
return volumeID, nil
|
||||
}
|
||||
}
|
||||
|
||||
return path.Base(mountPath), nil
|
||||
}
|
||||
|
||||
// DeviceOpened determines if the device is in use elsewhere
|
||||
func (hu *hostUtil) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// PathIsDevice determines if a path is a device.
|
||||
func (hu *hostUtil) PathIsDevice(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. Empty implementation here.
|
||||
func (hu *hostUtil) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFileType checks for sockets/block/character devices
|
||||
func (hu *(hostUtil)) GetFileType(pathname string) (FileType, error) {
|
||||
return getFileType(pathname)
|
||||
}
|
||||
|
||||
// MakeFile creates a new directory
|
||||
func (hu *hostUtil) MakeDir(pathname string) error {
|
||||
err := os.MkdirAll(pathname, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeFile creates an empty file
|
||||
func (hu *hostUtil) MakeFile(pathname string) error {
|
||||
f, err := os.OpenFile(pathname, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistsPath checks whether the path exists
|
||||
func (hu *hostUtil) ExistsPath(pathname string) (bool, error) {
|
||||
return utilpath.Exists(utilpath.CheckFollowSymlink, pathname)
|
||||
}
|
||||
|
||||
// EvalHostSymlinks returns the path name after evaluating symlinks
|
||||
func (hu *hostUtil) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return filepath.EvalSymlinks(pathname)
|
||||
}
|
||||
|
||||
// Note that on windows, it always returns 0. We actually don't set FSGroup on
|
||||
// windows platform, see SetVolumeOwnership implementation.
|
||||
func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
func (hu *hostUtil) GetFSGroup(pathname string) (int64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
func (hu *hostUtil) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
// Windows does not support SELinux.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
func (hu *hostUtil) GetMode(pathname string) (os.FileMode, error) {
|
||||
info, err := os.Stat(pathname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -175,7 +175,7 @@ func TestPathWithinBase(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFileType(t *testing.T) {
|
||||
mounter := New("fake/path")
|
||||
hu := NewHostUtil()
|
||||
|
||||
testCase := []struct {
|
||||
name string
|
||||
@ -213,7 +213,7 @@ func TestGetFileType(t *testing.T) {
|
||||
defer os.RemoveAll(cleanUpPath)
|
||||
}
|
||||
|
||||
fileType, err := mounter.GetFileType(path)
|
||||
fileType, err := hu.GetFileType(path)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d-%s] unexpected error : %v", idx, tc.name, err)
|
||||
}
|
||||
|
@ -250,8 +250,13 @@ func getVolumeSource(
|
||||
|
||||
func (plugin *awsElasticBlockStorePlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter(plugin.GetPluginName())
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
|
||||
volumeID, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
|
||||
volumeID, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -309,8 +309,13 @@ var _ volume.NodeExpandableVolumePlugin = &azureDataDiskPlugin{}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter(plugin.GetPluginName())
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
|
||||
sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
|
||||
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -267,8 +267,13 @@ func (plugin *cinderPlugin) getCloudProvider() (BlockStorageProvider, error) {
|
||||
|
||||
func (plugin *cinderPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter(plugin.GetPluginName())
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
|
||||
sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
|
||||
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ type csiMountMgr struct {
|
||||
podUID types.UID
|
||||
options volume.VolumeOptions
|
||||
publishContext map[string]string
|
||||
kubeVolHost volume.KubeletVolumeHost
|
||||
volume.MetricsProvider
|
||||
}
|
||||
|
||||
@ -328,9 +329,9 @@ func (c *csiMountMgr) podAttributes() (map[string]string, error) {
|
||||
}
|
||||
|
||||
func (c *csiMountMgr) GetAttributes() volume.Attributes {
|
||||
mounter := c.plugin.host.GetMounter(c.plugin.GetPluginName())
|
||||
path := c.GetPath()
|
||||
supportSelinux, err := mounter.GetSELinuxSupport(path)
|
||||
hu := c.kubeVolHost.GetHostUtil()
|
||||
supportSelinux, err := hu.GetSELinuxSupport(path)
|
||||
if err != nil {
|
||||
klog.V(2).Info(log("error checking for SELinux support: %s", err))
|
||||
// Best guess
|
||||
|
@ -391,6 +391,12 @@ func (p *csiPlugin) NewMounter(
|
||||
return nil, errors.New("failed to get a Kubernetes client")
|
||||
}
|
||||
|
||||
kvh, ok := p.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
klog.Error(log("cast from VolumeHost to KubeletVolumeHost failed"))
|
||||
return nil, errors.New("cast from VolumeHost to KubeletVolumeHost failed")
|
||||
}
|
||||
|
||||
mounter := &csiMountMgr{
|
||||
plugin: p,
|
||||
k8s: k8s,
|
||||
@ -402,6 +408,7 @@ func (p *csiPlugin) NewMounter(
|
||||
volumeID: volumeHandle,
|
||||
specVolumeID: spec.Name(),
|
||||
readOnly: readOnly,
|
||||
kubeVolHost: kvh,
|
||||
}
|
||||
mounter.csiClientGetter.driverName = csiDriverName(driverName)
|
||||
|
||||
@ -447,10 +454,17 @@ func (p *csiPlugin) NewMounter(
|
||||
func (p *csiPlugin) NewUnmounter(specName string, podUID types.UID) (volume.Unmounter, error) {
|
||||
klog.V(4).Infof(log("setting up unmounter for [name=%v, podUID=%v]", specName, podUID))
|
||||
|
||||
kvh, ok := p.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
klog.Error(log("cast from VolumeHost to KubeletVolumeHost failed"))
|
||||
return nil, errors.New("cast from VolumeHost to KubeletVolumeHost failed")
|
||||
}
|
||||
|
||||
unmounter := &csiMountMgr{
|
||||
plugin: p,
|
||||
podUID: podUID,
|
||||
specVolumeID: specName,
|
||||
kubeVolHost: kvh,
|
||||
}
|
||||
|
||||
// load volume info from file
|
||||
|
@ -288,8 +288,13 @@ var _ volume.NodeExpandableVolumePlugin = &gcePersistentDiskPlugin{}
|
||||
|
||||
func (plugin *gcePersistentDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter(plugin.GetPluginName())
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
|
||||
sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
|
||||
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -118,10 +118,15 @@ func (plugin *hostPathPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts vo
|
||||
} else {
|
||||
pathType = hostPathVolumeSource.Type
|
||||
}
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
return &hostPathMounter{
|
||||
hostPath: &hostPath{path: path, pathType: pathType},
|
||||
readOnly: readOnly,
|
||||
mounter: plugin.host.GetMounter(plugin.GetPluginName()),
|
||||
hu: kvh.GetHostUtil(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -202,6 +207,7 @@ type hostPathMounter struct {
|
||||
*hostPath
|
||||
readOnly bool
|
||||
mounter mount.Interface
|
||||
hu mount.HostUtils
|
||||
}
|
||||
|
||||
var _ volume.Mounter = &hostPathMounter{}
|
||||
@ -231,7 +237,7 @@ func (b *hostPathMounter) SetUp(mounterArgs volume.MounterArgs) error {
|
||||
if *b.pathType == v1.HostPathUnset {
|
||||
return nil
|
||||
}
|
||||
return checkType(b.GetPath(), b.pathType, b.mounter)
|
||||
return checkType(b.GetPath(), b.pathType, b.hu)
|
||||
}
|
||||
|
||||
// SetUpAt does not make sense for host paths - probably programmer error.
|
||||
@ -352,13 +358,13 @@ type hostPathTypeChecker interface {
|
||||
}
|
||||
|
||||
type fileTypeChecker struct {
|
||||
path string
|
||||
exists bool
|
||||
mounter mount.Interface
|
||||
path string
|
||||
exists bool
|
||||
hu mount.HostUtils
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) Exists() bool {
|
||||
exists, err := ftc.mounter.ExistsPath(ftc.path)
|
||||
exists, err := ftc.hu.ExistsPath(ftc.path)
|
||||
return exists && err == nil
|
||||
}
|
||||
|
||||
@ -370,14 +376,14 @@ func (ftc *fileTypeChecker) IsFile() bool {
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) MakeFile() error {
|
||||
return ftc.mounter.MakeFile(ftc.path)
|
||||
return ftc.hu.MakeFile(ftc.path)
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) IsDir() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
pathType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
pathType, err := ftc.hu.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -385,11 +391,11 @@ func (ftc *fileTypeChecker) IsDir() bool {
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) MakeDir() error {
|
||||
return ftc.mounter.MakeDir(ftc.path)
|
||||
return ftc.hu.MakeDir(ftc.path)
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) IsBlock() bool {
|
||||
blkDevType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
blkDevType, err := ftc.hu.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -397,7 +403,7 @@ func (ftc *fileTypeChecker) IsBlock() bool {
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) IsChar() bool {
|
||||
charDevType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
charDevType, err := ftc.hu.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -405,7 +411,7 @@ func (ftc *fileTypeChecker) IsChar() bool {
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) IsSocket() bool {
|
||||
socketType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
socketType, err := ftc.hu.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@ -416,13 +422,13 @@ func (ftc *fileTypeChecker) GetPath() string {
|
||||
return ftc.path
|
||||
}
|
||||
|
||||
func newFileTypeChecker(path string, mounter mount.Interface) hostPathTypeChecker {
|
||||
return &fileTypeChecker{path: path, mounter: mounter}
|
||||
func newFileTypeChecker(path string, hu mount.HostUtils) hostPathTypeChecker {
|
||||
return &fileTypeChecker{path: path, hu: hu}
|
||||
}
|
||||
|
||||
// checkType checks whether the given path is the exact pathType
|
||||
func checkType(path string, pathType *v1.HostPathType, mounter mount.Interface) error {
|
||||
return checkTypeInternal(newFileTypeChecker(path, mounter), pathType)
|
||||
func checkType(path string, pathType *v1.HostPathType, hu mount.HostUtils) error {
|
||||
return checkTypeInternal(newFileTypeChecker(path, hu), pathType)
|
||||
}
|
||||
|
||||
func checkTypeInternal(ftc hostPathTypeChecker, pathType *v1.HostPathType) error {
|
||||
|
@ -386,7 +386,7 @@ func TestOSFileTypeChecker(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
fakeFTC := &utilmount.FakeMounter{
|
||||
fakeFTC := &utilmount.FakeHostUtil{
|
||||
Filesystem: map[string]utilmount.FileType{
|
||||
tc.path: utilmount.FileType(tc.desiredType),
|
||||
},
|
||||
|
@ -124,12 +124,18 @@ func (plugin *localVolumePlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ vo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
|
||||
return &localVolumeMounter{
|
||||
localVolume: &localVolume{
|
||||
pod: pod,
|
||||
podUID: pod.UID,
|
||||
volName: spec.Name(),
|
||||
mounter: plugin.host.GetMounter(plugin.GetPluginName()),
|
||||
hostUtil: kvh.GetHostUtil(),
|
||||
plugin: plugin,
|
||||
globalPath: globalLocalPath,
|
||||
MetricsProvider: volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(pod.UID, utilstrings.EscapeQualifiedName(localVolumePluginName), spec.Name())),
|
||||
@ -230,7 +236,12 @@ func (plugin *localVolumePlugin) getGlobalLocalPath(spec *volume.Spec) (string,
|
||||
return "", fmt.Errorf("local volume source is nil or local path is not set")
|
||||
}
|
||||
|
||||
fileType, err := plugin.host.GetMounter(plugin.GetPluginName()).GetFileType(spec.PersistentVolume.Spec.Local.Path)
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
|
||||
fileType, err := kvh.GetHostUtil().GetFileType(spec.PersistentVolume.Spec.Local.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -247,8 +258,9 @@ func (plugin *localVolumePlugin) getGlobalLocalPath(spec *volume.Spec) (string,
|
||||
var _ volume.DeviceMountableVolumePlugin = &localVolumePlugin{}
|
||||
|
||||
type deviceMounter struct {
|
||||
plugin *localVolumePlugin
|
||||
mounter *mount.SafeFormatAndMount
|
||||
plugin *localVolumePlugin
|
||||
mounter *mount.SafeFormatAndMount
|
||||
hostUtil mount.HostUtils
|
||||
}
|
||||
|
||||
var _ volume.DeviceMounter = &deviceMounter{}
|
||||
@ -258,9 +270,14 @@ func (plugin *localVolumePlugin) CanDeviceMount(spec *volume.Spec) (bool, error)
|
||||
}
|
||||
|
||||
func (plugin *localVolumePlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
return &deviceMounter{
|
||||
plugin: plugin,
|
||||
mounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
|
||||
plugin: plugin,
|
||||
mounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
|
||||
hostUtil: kvh.GetHostUtil(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -307,7 +324,7 @@ func (dm *deviceMounter) MountDevice(spec *volume.Spec, devicePath string, devic
|
||||
if spec.PersistentVolume.Spec.Local == nil || len(spec.PersistentVolume.Spec.Local.Path) == 0 {
|
||||
return fmt.Errorf("local volume source is nil or local path is not set")
|
||||
}
|
||||
fileType, err := dm.mounter.GetFileType(spec.PersistentVolume.Spec.Local.Path)
|
||||
fileType, err := dm.hostUtil.GetFileType(spec.PersistentVolume.Spec.Local.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -390,8 +407,9 @@ type localVolume struct {
|
||||
// Global path to the volume
|
||||
globalPath string
|
||||
// Mounter interface that provides system calls to mount the global path to the pod local path.
|
||||
mounter mount.Interface
|
||||
plugin *localVolumePlugin
|
||||
mounter mount.Interface
|
||||
hostUtil mount.HostUtils
|
||||
plugin *localVolumePlugin
|
||||
volume.MetricsProvider
|
||||
}
|
||||
|
||||
@ -462,7 +480,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs)
|
||||
refs = m.filterPodMounts(refs)
|
||||
if len(refs) > 0 {
|
||||
fsGroupNew := int64(*mounterArgs.FsGroup)
|
||||
fsGroupOld, err := m.mounter.GetFSGroup(m.globalPath)
|
||||
fsGroupOld, err := m.hostUtil.GetFSGroup(m.globalPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check fsGroup for %s (%v)", m.globalPath, err)
|
||||
}
|
||||
|
@ -334,6 +334,8 @@ type KubeletVolumeHost interface {
|
||||
CSIDriversSynced() cache.InformerSynced
|
||||
// WaitForCacheSync is a helper function that waits for cache sync for CSIDriverLister
|
||||
WaitForCacheSync() error
|
||||
// Returns HostUtils Interface
|
||||
GetHostUtil() mount.HostUtils
|
||||
}
|
||||
|
||||
// AttachDetachVolumeHost is a AttachDetach Controller specific interface that plugins can use
|
||||
|
@ -374,8 +374,13 @@ func (plugin *rbdPlugin) newUnmounterInternal(volName string, podUID types.UID,
|
||||
|
||||
func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter(plugin.GetPluginName())
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
pluginMntDir := volutil.GetPluginMountDir(plugin.host, plugin.GetPluginName())
|
||||
sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
|
||||
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -201,7 +201,12 @@ func (v *sioVolume) TearDownAt(dir string) error {
|
||||
klog.V(4).Info(log("dir %s unmounted successfully", dir))
|
||||
|
||||
// detach/unmap
|
||||
deviceBusy, err := mounter.DeviceOpened(dev)
|
||||
kvh, ok := v.plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
deviceBusy, err := hu.DeviceOpened(dev)
|
||||
if err != nil {
|
||||
klog.Error(log("teardown unable to get status for device %s: %v", dev, err))
|
||||
return err
|
||||
|
@ -25,8 +25,10 @@ go_library(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/listers/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
|
@ -33,8 +33,10 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
storagelisters "k8s.io/client-go/listers/storage/v1beta1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
@ -68,11 +70,13 @@ type fakeVolumeHost struct {
|
||||
pluginMgr VolumePluginMgr
|
||||
cloud cloudprovider.Interface
|
||||
mounter mount.Interface
|
||||
hostUtil mount.HostUtils
|
||||
exec mount.Exec
|
||||
nodeLabels map[string]string
|
||||
nodeName string
|
||||
subpather subpath.Interface
|
||||
csiDriverLister storagelisters.CSIDriverLister
|
||||
informerFactory informers.SharedInformerFactory
|
||||
}
|
||||
|
||||
var _ VolumeHost = &fakeVolumeHost{}
|
||||
@ -103,12 +107,14 @@ func NewFakeVolumeHostWithCSINodeName(rootDir string, kubeClient clientset.Inter
|
||||
|
||||
func newFakeVolumeHost(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, cloud cloudprovider.Interface, pathToTypeMap map[string]mount.FileType) *fakeVolumeHost {
|
||||
host := &fakeVolumeHost{rootDir: rootDir, kubeClient: kubeClient, cloud: cloud}
|
||||
host.mounter = &mount.FakeMounter{
|
||||
host.mounter = &mount.FakeMounter{}
|
||||
host.hostUtil = &mount.FakeHostUtil{
|
||||
Filesystem: pathToTypeMap,
|
||||
}
|
||||
host.exec = mount.NewFakeExec(nil)
|
||||
host.pluginMgr.InitPlugins(plugins, nil /* prober */, host)
|
||||
host.subpather = &subpath.FakeSubpath{}
|
||||
host.informerFactory = informers.NewSharedInformerFactory(kubeClient, time.Minute)
|
||||
return host
|
||||
}
|
||||
|
||||
@ -153,6 +159,10 @@ func (f *fakeVolumeHost) GetMounter(pluginName string) mount.Interface {
|
||||
return f.mounter
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) GetHostUtil() mount.HostUtils {
|
||||
return f.hostUtil
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) GetSubpather() subpath.Interface {
|
||||
return f.subpather
|
||||
}
|
||||
@ -1495,11 +1505,28 @@ func (f *fakeVolumeHost) CSIDriverLister() storagelisters.CSIDriverLister {
|
||||
return f.csiDriverLister
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) CSIDriversSynced() cache.InformerSynced {
|
||||
// not needed for testing
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) CSINodeLister() storagelisters.CSINodeLister {
|
||||
// not needed for testing
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) GetInformerFactory() informers.SharedInformerFactory {
|
||||
return f.informerFactory
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) IsAttachDetachController() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) SetKubeletError(err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) WaitForCacheSync() error {
|
||||
return nil
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ package exec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"k8s.io/klog"
|
||||
|
||||
@ -92,70 +91,15 @@ func (m *execMounter) List() ([]mount.MountPoint, error) {
|
||||
return m.wrappedMounter.List()
|
||||
}
|
||||
|
||||
func (m *execMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
|
||||
return m.wrappedMounter.IsMountPointMatch(mp, dir)
|
||||
}
|
||||
|
||||
// IsLikelyNotMountPoint determines whether a path is a mountpoint.
|
||||
func (m *execMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return m.wrappedMounter.IsLikelyNotMountPoint(file)
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// 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 (m *execMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.DeviceOpened(pathname)
|
||||
}
|
||||
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (m *execMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.PathIsDevice(pathname)
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
|
||||
func (m *execMounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return m.wrappedMounter.GetDeviceNameFromMount(mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
func (m *execMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
|
||||
return m.wrappedMounter.IsMountPointMatch(mp, dir)
|
||||
}
|
||||
|
||||
func (m *execMounter) MakeRShared(path string) error {
|
||||
return m.wrappedMounter.MakeRShared(path)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetFileType(pathname string) (mount.FileType, error) {
|
||||
return m.wrappedMounter.GetFileType(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) MakeFile(pathname string) error {
|
||||
return m.wrappedMounter.MakeFile(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) MakeDir(pathname string) error {
|
||||
return m.wrappedMounter.MakeDir(pathname)
|
||||
}
|
||||
|
||||
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) GetMountRefs(pathname string) ([]string, error) {
|
||||
return m.wrappedMounter.GetMountRefs(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return m.wrappedMounter.GetFSGroup(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return m.wrappedMounter.GetSELinuxSupport(pathname)
|
||||
}
|
||||
|
||||
func (m *execMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return m.wrappedMounter.GetMode(pathname)
|
||||
}
|
||||
|
@ -20,13 +20,14 @@ package exec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
type execMounter struct{}
|
||||
|
||||
var _ = mount.Interface(&execMounter{})
|
||||
|
||||
// NewExecMounter returns a mounter that uses provided Exec interface to mount and
|
||||
// unmount a filesystem. For all other calls it uses a wrapped mounter.
|
||||
func NewExecMounter(exec mount.Exec, wrapped mount.Interface) mount.Interface {
|
||||
@ -53,54 +54,6 @@ func (mounter *execMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetFileType(pathname string) (mount.FileType, error) {
|
||||
return mount.FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *execMounter) ExistsPath(pathname string) (bool, error) {
|
||||
return true, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetMountRefs(pathname string) ([]string, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetFSGroup(pathname string) (int64, error) {
|
||||
return -1, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return false, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *execMounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//vendor/k8s.io/utils/nsenter:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
|
@ -165,7 +165,8 @@ func (n *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
}
|
||||
|
||||
// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts
|
||||
resolvedFile, err := n.EvalHostSymlinks(file)
|
||||
hu := NewHostUtil(n.ne, n.rootDir)
|
||||
resolvedFile, err := hu.EvalHostSymlinks(file)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
@ -211,36 +212,67 @@ func parseFindMnt(out string) (string, error) {
|
||||
return out[:i], nil
|
||||
}
|
||||
|
||||
// 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 := n.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mount.SearchMountPoints(hostpath, hostProcMountinfoPath)
|
||||
}
|
||||
|
||||
type hostUtil struct {
|
||||
ne *nsenter.Nsenter
|
||||
rootDir string
|
||||
}
|
||||
|
||||
// hostUtil implements mount.HostUtils
|
||||
var _ = mount.HostUtils(&hostUtil{})
|
||||
|
||||
// NewHostUtil returns a new mount.HostUtils implementation that works
|
||||
// for kubelet running in a container
|
||||
func NewHostUtil(ne *nsenter.Nsenter, rootDir string) mount.HostUtils {
|
||||
return &hostUtil{ne: ne, rootDir: rootDir}
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// 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 *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||
func (hu *hostUtil) 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 *Mounter) PathIsDevice(pathname string) (bool, error) {
|
||||
pathType, err := n.GetFileType(pathname)
|
||||
func (hu *hostUtil) PathIsDevice(pathname string) (bool, error) {
|
||||
pathType, err := hu.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 *Mounter) GetDeviceNameFromMount(mountPath, pluginMountDir string) (string, error) {
|
||||
return mount.GetDeviceNameFromMountLinux(n, mountPath, pluginMountDir)
|
||||
func (hu *hostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) {
|
||||
return mount.GetDeviceNameFromMountLinux(mounter, mountPath, pluginMountDir)
|
||||
}
|
||||
|
||||
// MakeRShared checks if path is shared and bind-mounts it as rshared if needed.
|
||||
func (n *Mounter) MakeRShared(path string) error {
|
||||
func (hu *hostUtil) MakeRShared(path string) error {
|
||||
return mount.DoMakeRShared(path, hostProcMountinfoPath)
|
||||
}
|
||||
|
||||
// GetFileType checks for file/directory/socket/block/character devices.
|
||||
func (n *Mounter) GetFileType(pathname string) (mount.FileType, error) {
|
||||
func (hu *hostUtil) GetFileType(pathname string) (mount.FileType, error) {
|
||||
var pathType mount.FileType
|
||||
outputBytes, err := n.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput()
|
||||
outputBytes, err := hu.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)
|
||||
@ -267,18 +299,18 @@ func (n *Mounter) GetFileType(pathname string) (mount.FileType, error) {
|
||||
}
|
||||
|
||||
// MakeDir creates a new directory.
|
||||
func (n *Mounter) MakeDir(pathname string) error {
|
||||
func (hu *hostUtil) MakeDir(pathname string) error {
|
||||
args := []string{"-p", pathname}
|
||||
if _, err := n.ne.Exec("mkdir", args).CombinedOutput(); err != nil {
|
||||
if _, err := hu.ne.Exec("mkdir", args).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeFile creates an empty file.
|
||||
func (n *Mounter) MakeFile(pathname string) error {
|
||||
func (hu *hostUtil) MakeFile(pathname string) error {
|
||||
args := []string{pathname}
|
||||
if _, err := n.ne.Exec("touch", args).CombinedOutput(); err != nil {
|
||||
if _, err := hu.ne.Exec("touch", args).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -286,60 +318,43 @@ func (n *Mounter) MakeFile(pathname string) 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) {
|
||||
func (hu *hostUtil) 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 := n.ne.EvalSymlinks(pathname, false /* mustExist */)
|
||||
hostPath, err := hu.ne.EvalSymlinks(pathname, false /* mustExist */)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
kubeletpath := n.ne.KubeletPath(hostPath)
|
||||
kubeletpath := hu.ne.KubeletPath(hostPath)
|
||||
return utilpath.Exists(utilpath.CheckFollowSymlink, kubeletpath)
|
||||
}
|
||||
|
||||
// EvalHostSymlinks returns the path name after evaluating symlinks.
|
||||
func (n *Mounter) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return n.ne.EvalSymlinks(pathname, true)
|
||||
}
|
||||
|
||||
// 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 := n.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mount.SearchMountPoints(hostpath, hostProcMountinfoPath)
|
||||
func (hu *hostUtil) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return hu.ne.EvalSymlinks(pathname, true)
|
||||
}
|
||||
|
||||
// GetFSGroup returns FSGroup of pathname.
|
||||
func (n *Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
hostPath, err := n.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
func (hu *hostUtil) GetFSGroup(pathname string) (int64, error) {
|
||||
hostPath, err := hu.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
kubeletpath := n.ne.KubeletPath(hostPath)
|
||||
kubeletpath := hu.ne.KubeletPath(hostPath)
|
||||
return mount.GetFSGroupLinux(kubeletpath)
|
||||
}
|
||||
|
||||
// GetSELinuxSupport tests if pathname is on a mount that supports SELinux.
|
||||
func (n *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
func (hu *hostUtil) GetSELinuxSupport(pathname string) (bool, error) {
|
||||
return mount.GetSELinux(pathname, hostProcMountsPath)
|
||||
}
|
||||
|
||||
// GetMode returns permissions of pathname.
|
||||
func (n *Mounter) GetMode(pathname string) (os.FileMode, error) {
|
||||
hostPath, err := n.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
func (hu *hostUtil) GetMode(pathname string) (os.FileMode, error) {
|
||||
hostPath, err := hu.ne.EvalSymlinks(pathname, true /* mustExist */)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
kubeletpath := n.ne.KubeletPath(hostPath)
|
||||
kubeletpath := hu.ne.KubeletPath(hostPath)
|
||||
return mount.GetModeLinux(kubeletpath)
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/utils/nsenter"
|
||||
)
|
||||
|
||||
@ -74,8 +75,9 @@ func TestParseFindMnt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newFakeNsenterMounter(tmpdir string, t *testing.T) (mounter *Mounter, rootfsPath string, varlibPath string, err error) {
|
||||
rootfsPath = filepath.Join(tmpdir, "rootfs")
|
||||
func newFakeNsenterHostUtil(tmpdir string, t *testing.T) (mount.HostUtils, string, string, error) {
|
||||
rootfsPath := filepath.Join(tmpdir, "rootfs")
|
||||
|
||||
if err := os.Mkdir(rootfsPath, 0755); err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
@ -84,12 +86,14 @@ func newFakeNsenterMounter(tmpdir string, t *testing.T) (mounter *Mounter, rootf
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
varlibPath = filepath.Join(tmpdir, "/var/lib/kubelet")
|
||||
varlibPath := filepath.Join(tmpdir, "var/lib/kubelet")
|
||||
if err := os.MkdirAll(varlibPath, 0755); err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
return NewMounter(varlibPath, ne), rootfsPath, varlibPath, nil
|
||||
hu := NewHostUtil(ne, varlibPath)
|
||||
|
||||
return hu, rootfsPath, varlibPath, nil
|
||||
}
|
||||
|
||||
func TestNsenterExistsFile(t *testing.T) {
|
||||
@ -262,7 +266,7 @@ func TestNsenterExistsFile(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
mounter, rootfs, _, err := newFakeNsenterMounter(tmpdir, t)
|
||||
hu, rootfs, _, err := newFakeNsenterHostUtil(tmpdir, t)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
@ -274,7 +278,7 @@ func TestNsenterExistsFile(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
out, err := mounter.ExistsPath(path)
|
||||
out, err := hu.ExistsPath(path)
|
||||
if err != nil && !test.expectError {
|
||||
t.Errorf("Test %q: unexpected error: %s", test.name, err)
|
||||
}
|
||||
@ -387,7 +391,7 @@ func TestNsenterGetMode(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
mounter, rootfs, _, err := newFakeNsenterMounter(tmpdir, t)
|
||||
hu, rootfs, _, err := newFakeNsenterHostUtil(tmpdir, t)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
@ -399,7 +403,7 @@ func TestNsenterGetMode(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
mode, err := mounter.GetMode(path)
|
||||
mode, err := hu.GetMode(path)
|
||||
if err != nil && !test.expectError {
|
||||
t.Errorf("Test %q: unexpected error: %s", test.name, err)
|
||||
}
|
||||
|
@ -65,75 +65,87 @@ 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, pluginMountDir 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")
|
||||
}
|
||||
|
||||
type hostUtil struct {
|
||||
}
|
||||
|
||||
// hostUtil implements mount.HostUtils
|
||||
var _ = mount.HostUtils(&hostUtil{})
|
||||
|
||||
// NewHostUtil returns a new implementation of mount.HostUtils for unsupported
|
||||
// platforms
|
||||
func NewHostUtil(ne *nsenter.Nsenter, rootDir string) mount.HostUtils {
|
||||
return &hostUtil{}
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use. I tis a noop for unsupported systems
|
||||
func (*hostUtil) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// PathIsDevice checks if pathname refers to a device. It is a noop for unsupported
|
||||
// systems
|
||||
func (*hostUtil) 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 (*hostUtil) GetDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir 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 (*hostUtil) 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 (*hostUtil) GetFileType(_ string) (mount.FileType, error) {
|
||||
return mount.FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
// MakeDir creates a new directory. Noop on unsupported platforms
|
||||
func (*hostUtil) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeFile creats an empty file. Noop on unsupported platforms
|
||||
func (*hostUtil) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistsPath checks if pathname exists. Always returns an error on unsupported
|
||||
// platforms
|
||||
func (*hostUtil) 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 (*hostUtil) EvalHostSymlinks(pathname string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
// GetFSGroup returns FSGroup of pathname. Always returns an error on unsupported platforms
|
||||
func (*Mounter) GetFSGroup(pathname string) (int64, error) {
|
||||
func (*hostUtil) 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) {
|
||||
func (*hostUtil) 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) {
|
||||
func (*hostUtil) GetMode(pathname string) (os.FileMode, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func (f *fakeOGCounter) GenerateVolumesAreAttachedFunc(attachedVolumes []Attache
|
||||
return f.recordFuncCall("GenerateVolumesAreAttachedFunc"), nil
|
||||
}
|
||||
|
||||
func (f *fakeOGCounter) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||
func (f *fakeOGCounter) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hu mount.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
return f.recordFuncCall("GenerateUnmountDeviceFunc"), nil
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ func (f *fakeOGCounter) GenerateUnmapVolumeFunc(volumeToUnmount MountedVolume, a
|
||||
return f.recordFuncCall("GenerateUnmapVolumeFunc"), nil
|
||||
}
|
||||
|
||||
func (f *fakeOGCounter) GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||
func (f *fakeOGCounter) GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hu mount.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
return f.recordFuncCall("GenerateUnmapDeviceFunc"), nil
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ type OperationExecutor interface {
|
||||
// global map path. If number of reference is zero, remove global map path
|
||||
// directory and free a volume for detach.
|
||||
// It then updates the actual state of the world to reflect that.
|
||||
UnmountDevice(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) error
|
||||
UnmountDevice(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hostutil mount.HostUtils) error
|
||||
|
||||
// VerifyControllerAttachedVolume checks if the specified volume is present
|
||||
// in the specified nodes AttachedVolumes Status field. It uses kubeClient
|
||||
@ -792,7 +792,7 @@ func (oe *operationExecutor) UnmountVolume(
|
||||
func (oe *operationExecutor) UnmountDevice(
|
||||
deviceToDetach AttachedVolume,
|
||||
actualStateOfWorld ActualStateOfWorldMounterUpdater,
|
||||
mounter mount.Interface) error {
|
||||
hostutil mount.HostUtils) error {
|
||||
fsVolume, err := util.CheckVolumeModeFilesystem(deviceToDetach.VolumeSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -802,12 +802,12 @@ func (oe *operationExecutor) UnmountDevice(
|
||||
// Filesystem volume case
|
||||
// Unmount and detach a device if a volume isn't referenced
|
||||
generatedOperations, err = oe.operationGenerator.GenerateUnmountDeviceFunc(
|
||||
deviceToDetach, actualStateOfWorld, mounter)
|
||||
deviceToDetach, actualStateOfWorld, hostutil)
|
||||
} else {
|
||||
// Block volume case
|
||||
// Detach a device and remove loopback if a volume isn't referenced
|
||||
generatedOperations, err = oe.operationGenerator.GenerateUnmapDeviceFunc(
|
||||
deviceToDetach, actualStateOfWorld, mounter)
|
||||
deviceToDetach, actualStateOfWorld, hostutil)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -433,7 +433,7 @@ func (fopg *fakeOperationGenerator) GenerateVolumesAreAttachedFunc(attachedVolum
|
||||
OperationFunc: opFunc,
|
||||
}, nil
|
||||
}
|
||||
func (fopg *fakeOperationGenerator) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||
func (fopg *fakeOperationGenerator) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hostutil mount.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
opFunc := func() (error, error) {
|
||||
startOperationAndBlock(fopg.ch, fopg.quit)
|
||||
return nil, nil
|
||||
@ -506,7 +506,7 @@ func (fopg *fakeOperationGenerator) GenerateUnmapVolumeFunc(volumeToUnmount Moun
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (fopg *fakeOperationGenerator) GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||
func (fopg *fakeOperationGenerator) GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hostutil mount.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
opFunc := func() (error, error) {
|
||||
startOperationAndBlock(fopg.ch, fopg.quit)
|
||||
return nil, nil
|
||||
|
@ -106,7 +106,7 @@ type OperationGenerator interface {
|
||||
GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
|
||||
|
||||
// Generates the UnMountDevice function needed to perform the unmount of a device
|
||||
GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (volumetypes.GeneratedOperations, error)
|
||||
GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.HostUtils) (volumetypes.GeneratedOperations, error)
|
||||
|
||||
// Generates the function needed to check if the attach_detach controller has attached the volume plugin
|
||||
GenerateVerifyControllerAttachedVolumeFunc(volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
|
||||
@ -118,7 +118,7 @@ type OperationGenerator interface {
|
||||
GenerateUnmapVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error)
|
||||
|
||||
// Generates the UnmapDevice function needed to perform the unmap of a device
|
||||
GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (volumetypes.GeneratedOperations, error)
|
||||
GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.HostUtils) (volumetypes.GeneratedOperations, error)
|
||||
|
||||
// GetVolumePluginMgr returns volume plugin manager
|
||||
GetVolumePluginMgr() *volume.VolumePluginMgr
|
||||
@ -888,7 +888,7 @@ func (og *operationGenerator) GenerateUnmountVolumeFunc(
|
||||
func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
||||
deviceToDetach AttachedVolume,
|
||||
actualStateOfWorld ActualStateOfWorldMounterUpdater,
|
||||
mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||
hostutil mount.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
|
||||
var pluginName string
|
||||
if useCSIPlugin(og.volumePluginMgr, deviceToDetach.VolumeSpec) {
|
||||
@ -942,10 +942,10 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
||||
return deviceToDetach.GenerateError("UnmountDevice failed", unmountDeviceErr)
|
||||
}
|
||||
// Before logging that UnmountDevice succeeded and moving on,
|
||||
// use mounter.PathIsDevice to check if the path is a device,
|
||||
// if so use mounter.DeviceOpened to check if the device is in use anywhere
|
||||
// use hostutil.PathIsDevice to check if the path is a device,
|
||||
// if so use hostutil.DeviceOpened to check if the device is in use anywhere
|
||||
// else on the system. Retry if it returns true.
|
||||
deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, mounter)
|
||||
deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, hostutil)
|
||||
if deviceOpenedErr != nil {
|
||||
return nil, deviceOpenedErr
|
||||
}
|
||||
@ -1080,8 +1080,12 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
|
||||
// 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)
|
||||
kvh, ok := og.GetVolumePluginMgr().Host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return volumeToMount.GenerateError("MapVolume type assertion error", fmt.Errorf("volume host does not implement KubeletVolumeHost interface"))
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
devicePath, err = hu.EvalHostSymlinks(devicePath)
|
||||
if err != nil {
|
||||
return volumeToMount.GenerateError("MapVolume.EvalHostSymlinks failed", err)
|
||||
}
|
||||
@ -1258,7 +1262,7 @@ func (og *operationGenerator) GenerateUnmapVolumeFunc(
|
||||
func (og *operationGenerator) GenerateUnmapDeviceFunc(
|
||||
deviceToDetach AttachedVolume,
|
||||
actualStateOfWorld ActualStateOfWorldMounterUpdater,
|
||||
mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||
hostutil mount.HostUtils) (volumetypes.GeneratedOperations, error) {
|
||||
|
||||
var blockVolumePlugin volume.BlockVolumePlugin
|
||||
var err error
|
||||
@ -1344,10 +1348,10 @@ func (og *operationGenerator) GenerateUnmapDeviceFunc(
|
||||
}
|
||||
|
||||
// Before logging that UnmapDevice succeeded and moving on,
|
||||
// use mounter.PathIsDevice to check if the path is a device,
|
||||
// if so use mounter.DeviceOpened to check if the device is in use anywhere
|
||||
// use hostutil.PathIsDevice to check if the path is a device,
|
||||
// if so use hostutil.DeviceOpened to check if the device is in use anywhere
|
||||
// else on the system. Retry if it returns true.
|
||||
deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, mounter)
|
||||
deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, hostutil)
|
||||
if deviceOpenedErr != nil {
|
||||
return nil, deviceOpenedErr
|
||||
}
|
||||
@ -1726,8 +1730,8 @@ func checkNodeAffinity(og *operationGenerator, volumeToMount VolumeToMount) erro
|
||||
}
|
||||
|
||||
// isDeviceOpened checks the device status if the device is in use anywhere else on the system
|
||||
func isDeviceOpened(deviceToDetach AttachedVolume, mounter mount.Interface) (bool, error) {
|
||||
isDevicePath, devicePathErr := mounter.PathIsDevice(deviceToDetach.DevicePath)
|
||||
func isDeviceOpened(deviceToDetach AttachedVolume, hostUtil mount.HostUtils) (bool, error) {
|
||||
isDevicePath, devicePathErr := hostUtil.PathIsDevice(deviceToDetach.DevicePath)
|
||||
var deviceOpened bool
|
||||
var deviceOpenedErr error
|
||||
if !isDevicePath && devicePathErr == nil ||
|
||||
@ -1739,7 +1743,7 @@ func isDeviceOpened(deviceToDetach AttachedVolume, mounter mount.Interface) (boo
|
||||
} else if devicePathErr != nil {
|
||||
return false, deviceToDetach.GenerateErrorDetailed("PathIsDevice failed", devicePathErr)
|
||||
} else {
|
||||
deviceOpened, deviceOpenedErr = mounter.DeviceOpened(deviceToDetach.DevicePath)
|
||||
deviceOpened, deviceOpenedErr = hostUtil.DeviceOpened(deviceToDetach.DevicePath)
|
||||
if deviceOpenedErr != nil {
|
||||
return false, deviceToDetach.GenerateErrorDetailed("DeviceOpened failed", deviceOpenedErr)
|
||||
}
|
||||
|
@ -145,8 +145,13 @@ func (plugin *vsphereVolumePlugin) newUnmounterInternal(volName string, podUID t
|
||||
|
||||
func (plugin *vsphereVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter(plugin.GetPluginName())
|
||||
kvh, ok := plugin.host.(volume.KubeletVolumeHost)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
|
||||
}
|
||||
hu := kvh.GetHostUtil()
|
||||
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
|
||||
volumePath, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
|
||||
volumePath, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user