1
2
3
4
19
20 package local
21
22 import (
23 "fmt"
24 "os"
25 "path/filepath"
26 "reflect"
27 "runtime"
28 "testing"
29
30 v1 "k8s.io/api/core/v1"
31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 "k8s.io/apimachinery/pkg/types"
33 utiltesting "k8s.io/client-go/util/testing"
34 "k8s.io/kubernetes/pkg/volume"
35 volumetest "k8s.io/kubernetes/pkg/volume/testing"
36 "k8s.io/kubernetes/pkg/volume/util/hostutil"
37 "k8s.io/mount-utils"
38 )
39
40 const (
41 testPVName = "pvA"
42 testMountPath = "pods/poduid/volumes/kubernetes.io~local-volume/pvA"
43 testGlobalPath = "plugins/kubernetes.io~local-volume/volumeDevices/pvA"
44 testPodPath = "pods/poduid/volumeDevices/kubernetes.io~local-volume"
45 testBlockFormattingToFSGlobalPath = "plugins/kubernetes.io/local-volume/mounts/pvA"
46 )
47
48 func getPlugin(t *testing.T) (string, volume.VolumePlugin) {
49 tmpDir, err := utiltesting.MkTmpdir("localVolumeTest")
50 if err != nil {
51 t.Fatalf("can't make a temp dir: %v", err)
52 }
53
54 plugMgr := volume.VolumePluginMgr{}
55 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
56
57 plug, err := plugMgr.FindPluginByName(localVolumePluginName)
58 if err != nil {
59 os.RemoveAll(tmpDir)
60 t.Fatalf("Can't find the plugin by name")
61 }
62 if plug.GetPluginName() != localVolumePluginName {
63 t.Errorf("Wrong name: %s", plug.GetPluginName())
64 }
65 return tmpDir, plug
66 }
67
68 func getBlockPlugin(t *testing.T) (string, volume.BlockVolumePlugin) {
69 tmpDir, err := utiltesting.MkTmpdir("localVolumeTest")
70 if err != nil {
71 t.Fatalf("can't make a temp dir: %v", err)
72 }
73
74 plugMgr := volume.VolumePluginMgr{}
75 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
76 plug, err := plugMgr.FindMapperPluginByName(localVolumePluginName)
77 if err != nil {
78 os.RemoveAll(tmpDir)
79 t.Fatalf("Can't find the plugin by name: %q", localVolumePluginName)
80 }
81 if plug.GetPluginName() != localVolumePluginName {
82 t.Errorf("Wrong name: %s", plug.GetPluginName())
83 }
84 return tmpDir, plug
85 }
86
87 func getNodeExpandablePlugin(t *testing.T, isBlockDevice bool) (string, volume.NodeExpandableVolumePlugin) {
88 tmpDir, err := utiltesting.MkTmpdir("localVolumeTest")
89 if err != nil {
90 t.Fatalf("can't make a temp dir: %v", err)
91 }
92
93 plugMgr := volume.VolumePluginMgr{}
94 var pathToFSType map[string]hostutil.FileType
95 if isBlockDevice {
96 pathToFSType = map[string]hostutil.FileType{
97 tmpDir: hostutil.FileTypeBlockDev,
98 }
99 } else {
100 pathToFSType = map[string]hostutil.FileType{
101 tmpDir: hostutil.FileTypeDirectory,
102 }
103 }
104
105 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHostWithMounterFSType(t, tmpDir, nil, nil, pathToFSType))
106
107 plug, err := plugMgr.FindNodeExpandablePluginByName(localVolumePluginName)
108 if err != nil {
109 os.RemoveAll(tmpDir)
110 t.Fatalf("Can't find the plugin by name")
111 }
112 if plug.GetPluginName() != localVolumePluginName {
113 t.Errorf("Wrong name: %s", plug.GetPluginName())
114 }
115 return tmpDir, plug
116 }
117
118 func getPersistentPlugin(t *testing.T) (string, volume.PersistentVolumePlugin) {
119 tmpDir, err := utiltesting.MkTmpdir("localVolumeTest")
120 if err != nil {
121 t.Fatalf("can't make a temp dir: %v", err)
122 }
123
124 plugMgr := volume.VolumePluginMgr{}
125 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
126
127 plug, err := plugMgr.FindPersistentPluginByName(localVolumePluginName)
128 if err != nil {
129 os.RemoveAll(tmpDir)
130 t.Fatalf("Can't find the plugin by name")
131 }
132 if plug.GetPluginName() != localVolumePluginName {
133 t.Errorf("Wrong name: %s", plug.GetPluginName())
134 }
135 return tmpDir, plug
136 }
137
138 func getDeviceMountablePluginWithBlockPath(t *testing.T, isBlockDevice bool) (string, volume.DeviceMountableVolumePlugin) {
139 var (
140 source string
141 err error
142 )
143
144 if isBlockDevice && runtime.GOOS == "windows" {
145
146 source = "0"
147 } else {
148 source, err = utiltesting.MkTmpdir("localVolumeTest")
149 if err != nil {
150 t.Fatalf("can't make a temp dir: %v", err)
151 }
152 }
153
154 plugMgr := volume.VolumePluginMgr{}
155 var pathToFSType map[string]hostutil.FileType
156 if isBlockDevice {
157 pathToFSType = map[string]hostutil.FileType{
158 source: hostutil.FileTypeBlockDev,
159 }
160 }
161
162 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHostWithMounterFSType(t, source, nil, nil, pathToFSType))
163
164 plug, err := plugMgr.FindDeviceMountablePluginByName(localVolumePluginName)
165 if err != nil {
166 os.RemoveAll(source)
167 t.Fatalf("Can't find the plugin by name")
168 }
169 if plug.GetPluginName() != localVolumePluginName {
170 t.Errorf("Wrong name: %s", plug.GetPluginName())
171 }
172 return source, plug
173 }
174
175 func getTestVolume(readOnly bool, path string, isBlock bool, mountOptions []string) *volume.Spec {
176 pv := &v1.PersistentVolume{
177 ObjectMeta: metav1.ObjectMeta{
178 Name: testPVName,
179 },
180 Spec: v1.PersistentVolumeSpec{
181 PersistentVolumeSource: v1.PersistentVolumeSource{
182 Local: &v1.LocalVolumeSource{
183 Path: path,
184 },
185 },
186 MountOptions: mountOptions,
187 },
188 }
189
190 if isBlock {
191 blockMode := v1.PersistentVolumeBlock
192 pv.Spec.VolumeMode = &blockMode
193 } else {
194 fsMode := v1.PersistentVolumeFilesystem
195 pv.Spec.VolumeMode = &fsMode
196 }
197 return volume.NewSpecFromPersistentVolume(pv, readOnly)
198 }
199
200 func TestCanSupport(t *testing.T) {
201 tmpDir, plug := getPlugin(t)
202 defer os.RemoveAll(tmpDir)
203
204 if !plug.CanSupport(getTestVolume(false, tmpDir, false, nil)) {
205 t.Errorf("Expected true")
206 }
207 }
208
209 func TestGetAccessModes(t *testing.T) {
210 tmpDir, plug := getPersistentPlugin(t)
211 defer os.RemoveAll(tmpDir)
212
213 modes := plug.GetAccessModes()
214 if !volumetest.ContainsAccessMode(modes, v1.ReadWriteOnce) {
215 t.Errorf("Expected AccessModeType %q", v1.ReadWriteOnce)
216 }
217
218 if volumetest.ContainsAccessMode(modes, v1.ReadWriteMany) {
219 t.Errorf("Found AccessModeType %q, expected not", v1.ReadWriteMany)
220 }
221 if volumetest.ContainsAccessMode(modes, v1.ReadOnlyMany) {
222 t.Errorf("Found AccessModeType %q, expected not", v1.ReadOnlyMany)
223 }
224 }
225
226 func TestGetVolumeName(t *testing.T) {
227 tmpDir, plug := getPersistentPlugin(t)
228 defer os.RemoveAll(tmpDir)
229
230 volName, err := plug.GetVolumeName(getTestVolume(false, tmpDir, false, nil))
231 if err != nil {
232 t.Errorf("Failed to get volume name: %v", err)
233 }
234 if volName != testPVName {
235 t.Errorf("Expected volume name %q, got %q", testPVName, volName)
236 }
237 }
238
239 func TestInvalidLocalPath(t *testing.T) {
240 tmpDir, plug := getPlugin(t)
241 defer os.RemoveAll(tmpDir)
242
243 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
244 mounter, err := plug.NewMounter(getTestVolume(false, "/no/backsteps/allowed/..", false, nil), pod, volume.VolumeOptions{})
245 if err != nil {
246 t.Fatal(err)
247 }
248
249 err = mounter.SetUp(volume.MounterArgs{})
250 expectedMsg := "invalid path: /no/backsteps/allowed/.. must not contain '..'"
251 if err.Error() != expectedMsg {
252 t.Fatalf("expected error `%s` but got `%s`", expectedMsg, err)
253 }
254 }
255
256 func TestBlockDeviceGlobalPathAndMountDevice(t *testing.T) {
257
258 tmpBlockDir, plug := getDeviceMountablePluginWithBlockPath(t, true)
259 defer os.RemoveAll(tmpBlockDir)
260
261 dm, err := plug.NewDeviceMounter()
262 if err != nil {
263 t.Errorf("Failed to make a new device mounter: %v", err)
264 }
265
266 pvSpec := getTestVolume(false, tmpBlockDir, false, nil)
267
268 expectedGlobalPath := filepath.Join(tmpBlockDir, testBlockFormattingToFSGlobalPath)
269 actualPath, err := dm.GetDeviceMountPath(pvSpec)
270 if err != nil {
271 t.Errorf("Failed to get device mount path: %v", err)
272 }
273 if expectedGlobalPath != actualPath {
274 t.Fatalf("Expected device mount global path:%s, got: %s", expectedGlobalPath, actualPath)
275 }
276
277 fmt.Println("expected global path is:", expectedGlobalPath)
278
279 err = dm.MountDevice(pvSpec, tmpBlockDir, expectedGlobalPath, volume.DeviceMounterArgs{})
280 if err != nil {
281 t.Fatal(err)
282 }
283 if _, err := os.Stat(actualPath); err != nil {
284 if os.IsNotExist(err) {
285 t.Errorf("DeviceMounter.MountDevice() failed, device mount path not created: %s", actualPath)
286 } else {
287 t.Errorf("DeviceMounter.MountDevice() failed: %v", err)
288 }
289 }
290
291 du, err := plug.NewDeviceUnmounter()
292 if err != nil {
293 t.Fatalf("Create device unmounter error: %v", err)
294 }
295
296 err = du.UnmountDevice(actualPath)
297 if err != nil {
298 t.Fatalf("Unmount device error: %v", err)
299 }
300 }
301
302 func TestFSGlobalPathAndMountDevice(t *testing.T) {
303
304 tmpFSDir, plug := getDeviceMountablePluginWithBlockPath(t, false)
305 defer os.RemoveAll(tmpFSDir)
306
307 dm, err := plug.NewDeviceMounter()
308 if err != nil {
309 t.Errorf("Failed to make a new device mounter: %v", err)
310 }
311
312 pvSpec := getTestVolume(false, tmpFSDir, false, nil)
313
314 expectedGlobalPath := tmpFSDir
315 actualPath, err := dm.GetDeviceMountPath(pvSpec)
316 if err != nil {
317 t.Errorf("Failed to get device mount path: %v", err)
318 }
319 if expectedGlobalPath != actualPath {
320 t.Fatalf("Expected device mount global path:%s, got: %s", expectedGlobalPath, actualPath)
321 }
322
323
324 err = dm.MountDevice(pvSpec, tmpFSDir, expectedGlobalPath, volume.DeviceMounterArgs{})
325 if err != nil {
326 t.Fatal(err)
327 }
328 if _, err := os.Stat(expectedGlobalPath); err != nil {
329 if os.IsNotExist(err) {
330 t.Errorf("DeviceMounter.MountDevice() failed, device mount path not created: %s", expectedGlobalPath)
331 } else {
332 t.Errorf("DeviceMounter.MountDevice() failed: %v", err)
333 }
334 }
335 }
336
337 func TestNodeExpand(t *testing.T) {
338
339 tmpFSDir, plug := getNodeExpandablePlugin(t, false)
340 defer os.RemoveAll(tmpFSDir)
341
342 pvSpec := getTestVolume(false, tmpFSDir, false, nil)
343
344 resizeOptions := volume.NodeResizeOptions{
345 VolumeSpec: pvSpec,
346 DevicePath: tmpFSDir,
347 }
348
349
350 resizeDone, err := plug.NodeExpand(resizeOptions)
351 if err != nil {
352 t.Fatal(err)
353 }
354 if !resizeDone {
355 t.Errorf("expected resize to be done")
356 }
357 }
358
359 func TestMountUnmount(t *testing.T) {
360 tmpDir, plug := getPlugin(t)
361 defer os.RemoveAll(tmpDir)
362
363 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
364 mounter, err := plug.NewMounter(getTestVolume(false, tmpDir, false, nil), pod, volume.VolumeOptions{})
365 if err != nil {
366 t.Errorf("Failed to make a new Mounter: %v", err)
367 }
368 if mounter == nil {
369 t.Fatalf("Got a nil Mounter")
370 }
371
372 volPath := filepath.Join(tmpDir, testMountPath)
373 path := mounter.GetPath()
374 if path != volPath {
375 t.Errorf("Got unexpected path: %s", path)
376 }
377
378 if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
379 t.Errorf("Expected success, got: %v", err)
380 }
381
382 if runtime.GOOS != "windows" {
383
384 if _, err := os.Stat(path); err != nil {
385 if os.IsNotExist(err) {
386 t.Errorf("SetUp() failed, volume path not created: %s", path)
387 } else {
388 t.Errorf("SetUp() failed: %v", err)
389 }
390 }
391 }
392
393 unmounter, err := plug.NewUnmounter(testPVName, pod.UID)
394 if err != nil {
395 t.Errorf("Failed to make a new Unmounter: %v", err)
396 }
397 if unmounter == nil {
398 t.Fatalf("Got a nil Unmounter")
399 }
400
401 if err := unmounter.TearDown(); err != nil {
402 t.Errorf("Expected success, got: %v", err)
403 }
404 if _, err := os.Stat(path); err == nil {
405 t.Errorf("TearDown() failed, volume path still exists: %s", path)
406 } else if !os.IsNotExist(err) {
407 t.Errorf("TearDown() failed: %v", err)
408 }
409 }
410
411
412 func TestMapUnmap(t *testing.T) {
413 tmpDir, plug := getBlockPlugin(t)
414 defer os.RemoveAll(tmpDir)
415
416 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
417 volSpec := getTestVolume(false, tmpDir, true , nil)
418 mapper, err := plug.NewBlockVolumeMapper(volSpec, pod, volume.VolumeOptions{})
419 if err != nil {
420 t.Errorf("Failed to make a new Mounter: %v", err)
421 }
422 if mapper == nil {
423 t.Fatalf("Got a nil Mounter")
424 }
425
426 expectedGlobalPath := filepath.Join(tmpDir, testGlobalPath)
427 globalPath, err := mapper.GetGlobalMapPath(volSpec)
428 if err != nil {
429 t.Errorf("Failed to get global path: %v", err)
430 }
431 if globalPath != expectedGlobalPath {
432 t.Errorf("Got unexpected path: %s, expected %s", globalPath, expectedGlobalPath)
433 }
434 expectedPodPath := filepath.Join(tmpDir, testPodPath)
435 podPath, volName := mapper.GetPodDeviceMapPath()
436 if podPath != expectedPodPath {
437 t.Errorf("Got unexpected pod path: %s, expected %s", podPath, expectedPodPath)
438 }
439 if volName != testPVName {
440 t.Errorf("Got unexpected volNamne: %s, expected %s", volName, testPVName)
441 }
442 var devPath string
443
444 if customMapper, ok := mapper.(volume.CustomBlockVolumeMapper); ok {
445 _, err = customMapper.SetUpDevice()
446 if err != nil {
447 t.Errorf("Failed to SetUpDevice, err: %v", err)
448 }
449 devPath, err = customMapper.MapPodDevice()
450 if err != nil {
451 t.Errorf("Failed to MapPodDevice, err: %v", err)
452 }
453 }
454
455 if _, err := os.Stat(devPath); err != nil {
456 if os.IsNotExist(err) {
457 t.Errorf("SetUpDevice() failed, volume path not created: %s", devPath)
458 } else {
459 t.Errorf("SetUpDevice() failed: %v", err)
460 }
461 }
462
463 unmapper, err := plug.NewBlockVolumeUnmapper(testPVName, pod.UID)
464 if err != nil {
465 t.Fatalf("Failed to make a new Unmapper: %v", err)
466 }
467 if unmapper == nil {
468 t.Fatalf("Got a nil Unmapper")
469 }
470
471 if customUnmapper, ok := unmapper.(volume.CustomBlockVolumeUnmapper); ok {
472 if err := customUnmapper.UnmapPodDevice(); err != nil {
473 t.Errorf("UnmapPodDevice failed, err: %v", err)
474 }
475
476 if err := customUnmapper.TearDownDevice(globalPath, devPath); err != nil {
477 t.Errorf("TearDownDevice failed, err: %v", err)
478 }
479 }
480 }
481
482 func testFSGroupMount(plug volume.VolumePlugin, pod *v1.Pod, tmpDir string, fsGroup int64) error {
483 mounter, err := plug.NewMounter(getTestVolume(false, tmpDir, false, nil), pod, volume.VolumeOptions{})
484 if err != nil {
485 return err
486 }
487 if mounter == nil {
488 return fmt.Errorf("got a nil Mounter")
489 }
490
491 volPath := filepath.Join(tmpDir, testMountPath)
492 path := mounter.GetPath()
493 if path != volPath {
494 return fmt.Errorf("got unexpected path: %s", path)
495 }
496
497 var mounterArgs volume.MounterArgs
498 mounterArgs.FsGroup = &fsGroup
499 if err := mounter.SetUp(mounterArgs); err != nil {
500 return err
501 }
502 return nil
503 }
504
505 func TestConstructVolumeSpec(t *testing.T) {
506 tests := []struct {
507 name string
508 mountPoints []mount.MountPoint
509 expectedPath string
510 }{
511 {
512 name: "filesystem volume with directory source",
513 mountPoints: []mount.MountPoint{
514 {
515 Device: "/mnt/disk/ssd0",
516 Path: "pods/poduid/volumes/kubernetes.io~local-volume/pvA",
517 },
518 },
519 expectedPath: "",
520 },
521 {
522 name: "filesystem volume with block source",
523 mountPoints: []mount.MountPoint{
524 {
525 Device: "/dev/loop0",
526 Path: testMountPath,
527 },
528 {
529 Device: "/dev/loop0",
530 Path: testBlockFormattingToFSGlobalPath,
531 },
532 },
533 expectedPath: "/dev/loop0",
534 },
535 }
536
537 for _, tt := range tests {
538 t.Run(tt.name, func(t *testing.T) {
539 tmpDir, err := utiltesting.MkTmpdir("localVolumeTest")
540 if err != nil {
541 t.Fatalf("can't make a temp dir: %v", err)
542 }
543 defer os.RemoveAll(tmpDir)
544 plug := &localVolumePlugin{
545 host: volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil),
546 }
547 mounter := plug.host.GetMounter(plug.GetPluginName())
548 fakeMountPoints := []mount.MountPoint{}
549 for _, mp := range tt.mountPoints {
550 fakeMountPoint := mp
551 fakeMountPoint.Path = filepath.Join(tmpDir, mp.Path)
552 fakeMountPoints = append(fakeMountPoints, fakeMountPoint)
553 }
554 mounter.(*mount.FakeMounter).MountPoints = fakeMountPoints
555 volPath := filepath.Join(tmpDir, testMountPath)
556 rec, err := plug.ConstructVolumeSpec(testPVName, volPath)
557 if err != nil {
558 t.Errorf("ConstructVolumeSpec() failed: %v", err)
559 }
560 if rec.Spec == nil {
561 t.Fatalf("ConstructVolumeSpec() returned nil")
562 }
563
564 volName := rec.Spec.Name()
565 if volName != testPVName {
566 t.Errorf("Expected volume name %q, got %q", testPVName, volName)
567 }
568
569 if rec.Spec.Volume != nil {
570 t.Errorf("Volume object returned, expected nil")
571 }
572
573 pv := rec.Spec.PersistentVolume
574 if pv == nil {
575 t.Fatalf("PersistentVolume object nil")
576 }
577
578 if rec.Spec.PersistentVolume.Spec.VolumeMode == nil {
579 t.Fatalf("Volume mode has not been set.")
580 }
581
582 if *rec.Spec.PersistentVolume.Spec.VolumeMode != v1.PersistentVolumeFilesystem {
583 t.Errorf("Unexpected volume mode %q", *rec.Spec.PersistentVolume.Spec.VolumeMode)
584 }
585
586 ls := pv.Spec.PersistentVolumeSource.Local
587 if ls == nil {
588 t.Fatalf("LocalVolumeSource object nil")
589 }
590
591 if pv.Spec.PersistentVolumeSource.Local.Path != tt.expectedPath {
592 t.Fatalf("Unexpected path got %q, expected %q", pv.Spec.PersistentVolumeSource.Local.Path, tt.expectedPath)
593 }
594 })
595 }
596
597 }
598
599 func TestConstructBlockVolumeSpec(t *testing.T) {
600 tmpDir, plug := getBlockPlugin(t)
601 defer os.RemoveAll(tmpDir)
602
603 podPath := filepath.Join(tmpDir, testPodPath)
604 spec, err := plug.ConstructBlockVolumeSpec(types.UID("poduid"), testPVName, podPath)
605 if err != nil {
606 t.Errorf("ConstructBlockVolumeSpec() failed: %v", err)
607 }
608 if spec == nil {
609 t.Fatalf("ConstructBlockVolumeSpec() returned nil")
610 }
611
612 volName := spec.Name()
613 if volName != testPVName {
614 t.Errorf("Expected volume name %q, got %q", testPVName, volName)
615 }
616
617 if spec.Volume != nil {
618 t.Errorf("Volume object returned, expected nil")
619 }
620
621 pv := spec.PersistentVolume
622 if pv == nil {
623 t.Fatalf("PersistentVolume object nil")
624 }
625
626 if spec.PersistentVolume.Spec.VolumeMode == nil {
627 t.Fatalf("Volume mode has not been set.")
628 }
629
630 if *spec.PersistentVolume.Spec.VolumeMode != v1.PersistentVolumeBlock {
631 t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
632 }
633
634 ls := pv.Spec.PersistentVolumeSource.Local
635 if ls == nil {
636 t.Fatalf("LocalVolumeSource object nil")
637 }
638 }
639
640 func TestMountOptions(t *testing.T) {
641 tmpDir, plug := getPlugin(t)
642 defer os.RemoveAll(tmpDir)
643
644 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
645 mounter, err := plug.NewMounter(getTestVolume(false, tmpDir, false, []string{"test-option"}), pod, volume.VolumeOptions{})
646 if err != nil {
647 t.Errorf("Failed to make a new Mounter: %v", err)
648 }
649 if mounter == nil {
650 t.Fatalf("Got a nil Mounter")
651 }
652
653
654 fakeMounter := mount.NewFakeMounter(nil)
655 mounter.(*localVolumeMounter).mounter = fakeMounter
656
657 if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
658 t.Errorf("Expected success, got: %v", err)
659 }
660 mountOptions := fakeMounter.MountPoints[0].Opts
661 expectedMountOptions := []string{"bind", "test-option"}
662 if !reflect.DeepEqual(mountOptions, expectedMountOptions) {
663 t.Errorf("Expected mount options to be %v got %v", expectedMountOptions, mountOptions)
664 }
665 }
666
667 func TestPersistentClaimReadOnlyFlag(t *testing.T) {
668 tmpDir, plug := getPlugin(t)
669 defer os.RemoveAll(tmpDir)
670
671
672 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
673 mounter, err := plug.NewMounter(getTestVolume(true, tmpDir, false, nil), pod, volume.VolumeOptions{})
674 if err != nil {
675 t.Errorf("Failed to make a new Mounter: %v", err)
676 }
677 if mounter == nil {
678 t.Fatalf("Got a nil Mounter")
679 }
680 if !mounter.GetAttributes().ReadOnly {
681 t.Errorf("Expected true for mounter.IsReadOnly")
682 }
683
684
685 mounter, err = plug.NewMounter(getTestVolume(false, tmpDir, false, nil), pod, volume.VolumeOptions{})
686 if err != nil {
687 t.Errorf("Failed to make a new Mounter: %v", err)
688 }
689 if mounter == nil {
690 t.Fatalf("Got a nil Mounter")
691 }
692 if mounter.GetAttributes().ReadOnly {
693 t.Errorf("Expected false for mounter.IsReadOnly")
694 }
695 }
696
697 func TestUnsupportedPlugins(t *testing.T) {
698 tmpDir, err := utiltesting.MkTmpdir("localVolumeTest")
699 if err != nil {
700 t.Fatalf("can't make a temp dir: %v", err)
701 }
702 defer os.RemoveAll(tmpDir)
703
704 plugMgr := volume.VolumePluginMgr{}
705 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
706 spec := getTestVolume(false, tmpDir, false, nil)
707
708 recyclePlug, err := plugMgr.FindRecyclablePluginBySpec(spec)
709 if err == nil && recyclePlug != nil {
710 t.Errorf("Recyclable plugin found, expected none")
711 }
712
713 deletePlug, err := plugMgr.FindDeletablePluginByName(localVolumePluginName)
714 if err == nil && deletePlug != nil {
715 t.Errorf("Deletable plugin found, expected none")
716 }
717
718 attachPlug, err := plugMgr.FindAttachablePluginByName(localVolumePluginName)
719 if err == nil && attachPlug != nil {
720 t.Errorf("Attachable plugin found, expected none")
721 }
722
723 createPlug, err := plugMgr.FindCreatablePluginBySpec(spec)
724 if err == nil && createPlug != nil {
725 t.Errorf("Creatable plugin found, expected none")
726 }
727
728 provisionPlug, err := plugMgr.FindProvisionablePluginByName(localVolumePluginName)
729 if err == nil && provisionPlug != nil {
730 t.Errorf("Provisionable plugin found, expected none")
731 }
732 }
733
734 func TestFilterPodMounts(t *testing.T) {
735 tmpDir, plug := getPlugin(t)
736 defer os.RemoveAll(tmpDir)
737
738 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
739 mounter, err := plug.NewMounter(getTestVolume(false, tmpDir, false, nil), pod, volume.VolumeOptions{})
740 if err != nil {
741 t.Fatal(err)
742 }
743 lvMounter, ok := mounter.(*localVolumeMounter)
744 if !ok {
745 t.Fatal("mounter is not localVolumeMounter")
746 }
747
748 host := volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)
749 podsDir := host.GetPodsDir()
750
751 cases := map[string]struct {
752 input []string
753 expected []string
754 }{
755 "empty": {
756 []string{},
757 []string{},
758 },
759 "not-pod-mount": {
760 []string{"/mnt/outside"},
761 []string{},
762 },
763 "pod-mount": {
764 []string{filepath.Join(podsDir, "pod-mount")},
765 []string{filepath.Join(podsDir, "pod-mount")},
766 },
767 "not-directory-prefix": {
768 []string{podsDir + "pod-mount"},
769 []string{},
770 },
771 "mix": {
772 []string{"/mnt/outside",
773 filepath.Join(podsDir, "pod-mount"),
774 "/another/outside",
775 filepath.Join(podsDir, "pod-mount2")},
776 []string{filepath.Join(podsDir, "pod-mount"),
777 filepath.Join(podsDir, "pod-mount2")},
778 },
779 }
780 for name, test := range cases {
781 output := lvMounter.filterPodMounts(test.input)
782 if !reflect.DeepEqual(output, test.expected) {
783 t.Errorf("%v failed: output %+v doesn't equal expected %+v", name, output, test.expected)
784 }
785 }
786 }
787
View as plain text