diff --git a/pkg/util/mount/fake.go b/pkg/util/mount/fake.go index a354ca99fd..e834e297b3 100644 --- a/pkg/util/mount/fake.go +++ b/pkg/util/mount/fake.go @@ -194,7 +194,7 @@ func (f *FakeMounter) GetFileType(pathname string) (FileType, error) { if t, ok := f.Filesystem[pathname]; ok { return t, nil } - return FileType("fake"), nil + return FileType("Directory"), nil } func (f *FakeMounter) MakeDir(pathname string) error { diff --git a/pkg/volume/local/BUILD b/pkg/volume/local/BUILD index b3d622ed36..8fe054c70b 100644 --- a/pkg/volume/local/BUILD +++ b/pkg/volume/local/BUILD @@ -33,6 +33,7 @@ go_test( embed = [":go_default_library"], deps = select({ "@io_bazel_rules_go//go/platform:darwin": [ + "//pkg/util/mount:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", @@ -41,6 +42,7 @@ go_test( "//staging/src/k8s.io/client-go/util/testing:go_default_library", ], "@io_bazel_rules_go//go/platform:linux": [ + "//pkg/util/mount:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", @@ -49,6 +51,7 @@ go_test( "//staging/src/k8s.io/client-go/util/testing:go_default_library", ], "@io_bazel_rules_go//go/platform:windows": [ + "//pkg/util/mount:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/pkg/volume/local/local_test.go b/pkg/volume/local/local_test.go index 0d9cdd6007..37fd16a080 100644 --- a/pkg/volume/local/local_test.go +++ b/pkg/volume/local/local_test.go @@ -31,16 +31,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" utiltesting "k8s.io/client-go/util/testing" + "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" ) const ( - testPVName = "pvA" - testMountPath = "pods/poduid/volumes/kubernetes.io~local-volume/pvA" - testGlobalPath = "plugins/kubernetes.io~local-volume/volumeDevices/pvA" - testPodPath = "pods/poduid/volumeDevices/kubernetes.io~local-volume" - testNodeName = "fakeNodeName" + testPVName = "pvA" + testMountPath = "pods/poduid/volumes/kubernetes.io~local-volume/pvA" + testGlobalPath = "plugins/kubernetes.io~local-volume/volumeDevices/pvA" + testPodPath = "pods/poduid/volumeDevices/kubernetes.io~local-volume" + testNodeName = "fakeNodeName" + testBlockFormattingToFSGlobalPath = "plugins/kubernetes.io/local-volume/mounts/pvA" ) func getPlugin(t *testing.T) (string, volume.VolumePlugin) { @@ -102,6 +104,33 @@ func getPersistentPlugin(t *testing.T) (string, volume.PersistentVolumePlugin) { return tmpDir, plug } +func getDeviceMountablePluginWithBlockPath(t *testing.T, isBlockDevice bool) (string, volume.DeviceMountableVolumePlugin) { + tmpDir, err := utiltesting.MkTmpdir("localVolumeTest") + if err != nil { + t.Fatalf("can't make a temp dir: %v", err) + } + + plugMgr := volume.VolumePluginMgr{} + var pathToFSType map[string]mount.FileType + if isBlockDevice { + pathToFSType = map[string]mount.FileType{ + tmpDir: mount.FileTypeBlockDev, + } + } + + plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHostWithMounterFSType(tmpDir, nil, nil, pathToFSType)) + + plug, err := plugMgr.FindDeviceMountablePluginByName(localVolumePluginName) + if err != nil { + os.RemoveAll(tmpDir) + t.Fatalf("Can't find the plugin by name") + } + if plug.GetPluginName() != localVolumePluginName { + t.Errorf("Wrong name: %s", plug.GetPluginName()) + } + return tmpDir, plug +} + func getTestVolume(readOnly bool, path string, isBlock bool) *volume.Spec { pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ @@ -179,6 +208,87 @@ func TestInvalidLocalPath(t *testing.T) { } } +func TestBlockDeviceGlobalPathAndMountDevice(t *testing.T) { + // Block device global mount path testing + tmpBlockDir, plug := getDeviceMountablePluginWithBlockPath(t, true) + defer os.RemoveAll(tmpBlockDir) + + dm, err := plug.NewDeviceMounter() + if err != nil { + t.Errorf("Failed to make a new device mounter: %v", err) + } + + pvSpec := getTestVolume(false, tmpBlockDir, false) + + expectedGlobalPath := filepath.Join(tmpBlockDir, testBlockFormattingToFSGlobalPath) + actualPath, err := dm.GetDeviceMountPath(pvSpec) + if err != nil { + t.Errorf("Failed to get device mount path: %v", err) + } + if expectedGlobalPath != actualPath { + t.Fatalf("Expected device mount global path:%s, got: %s", expectedGlobalPath, actualPath) + } + + fmt.Println("expected global path is:", expectedGlobalPath) + + err = dm.MountDevice(pvSpec, tmpBlockDir, expectedGlobalPath) + if err != nil { + t.Fatal(err) + } + if _, err := os.Stat(actualPath); err != nil { + if os.IsNotExist(err) { + t.Errorf("DeviceMounter.MountDevice() failed, device mount path not created: %s", actualPath) + } else { + t.Errorf("DeviceMounter.MountDevice() failed: %v", err) + } + } + + du, err := plug.NewDeviceUnmounter() + if err != nil { + t.Fatalf("Create device unmounter error: %v", err) + } + + err = du.UnmountDevice(actualPath) + if err != nil { + t.Fatalf("Unmount device error: %v", err) + } +} + +func TestFSGlobalPathAndMountDevice(t *testing.T) { + // FS global path testing + tmpFSDir, plug := getDeviceMountablePluginWithBlockPath(t, false) + defer os.RemoveAll(tmpFSDir) + + dm, err := plug.NewDeviceMounter() + if err != nil { + t.Errorf("Failed to make a new device mounter: %v", err) + } + + pvSpec := getTestVolume(false, tmpFSDir, false) + + expectedGlobalPath := tmpFSDir + actualPath, err := dm.GetDeviceMountPath(pvSpec) + if err != nil { + t.Errorf("Failed to get device mount path: %v", err) + } + if expectedGlobalPath != actualPath { + t.Fatalf("Expected device mount global path:%s, got: %s", expectedGlobalPath, actualPath) + } + + // Actually, we will do nothing if the local path is FS type + err = dm.MountDevice(pvSpec, tmpFSDir, expectedGlobalPath) + if err != nil { + t.Fatal(err) + } + if _, err := os.Stat(expectedGlobalPath); err != nil { + if os.IsNotExist(err) { + t.Errorf("DeviceMounter.MountDevice() failed, device mount path not created: %s", expectedGlobalPath) + } else { + t.Errorf("DeviceMounter.MountDevice() failed: %v", err) + } + } +} + func TestMountUnmount(t *testing.T) { tmpDir, plug := getPlugin(t) defer os.RemoveAll(tmpDir) diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 94565eaaf7..8cfa765784 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -60,33 +60,40 @@ type fakeVolumeHost struct { } func NewFakeVolumeHost(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin) *fakeVolumeHost { - return newFakeVolumeHost(rootDir, kubeClient, plugins, nil) + return newFakeVolumeHost(rootDir, kubeClient, plugins, nil, nil) } func NewFakeVolumeHostWithCloudProvider(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, cloud cloudprovider.Interface) *fakeVolumeHost { - return newFakeVolumeHost(rootDir, kubeClient, plugins, cloud) + return newFakeVolumeHost(rootDir, kubeClient, plugins, cloud, nil) } func NewFakeVolumeHostWithNodeLabels(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, labels map[string]string) *fakeVolumeHost { - volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil) + volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil, nil) volHost.nodeLabels = labels return volHost } func NewFakeVolumeHostWithNodeName(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, nodeName string) *fakeVolumeHost { - volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil) + volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil, nil) volHost.nodeName = nodeName return volHost } -func newFakeVolumeHost(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, cloud cloudprovider.Interface) *fakeVolumeHost { +func newFakeVolumeHost(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, cloud cloudprovider.Interface, pathToTypeMap map[string]mount.FileType) *fakeVolumeHost { host := &fakeVolumeHost{rootDir: rootDir, kubeClient: kubeClient, cloud: cloud} - host.mounter = &mount.FakeMounter{} + host.mounter = &mount.FakeMounter{ + Filesystem: pathToTypeMap, + } host.exec = mount.NewFakeExec(nil) host.pluginMgr.InitPlugins(plugins, nil /* prober */, host) return host } +func NewFakeVolumeHostWithMounterFSType(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, pathToTypeMap map[string]mount.FileType) *fakeVolumeHost { + volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil, pathToTypeMap) + return volHost +} + func (f *fakeVolumeHost) GetPluginDir(podUID string) string { return path.Join(f.rootDir, "plugins", podUID) }