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