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