1
16
17 package rbd
18
19 import (
20 "fmt"
21 "os"
22 "path/filepath"
23 "reflect"
24 "runtime"
25 "strings"
26 "sync"
27 "testing"
28 "time"
29
30 "k8s.io/mount-utils"
31
32 v1 "k8s.io/api/core/v1"
33 "k8s.io/apimachinery/pkg/api/resource"
34 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35 "k8s.io/apimachinery/pkg/types"
36 "k8s.io/apimachinery/pkg/util/uuid"
37 "k8s.io/client-go/kubernetes/fake"
38 utiltesting "k8s.io/client-go/util/testing"
39 "k8s.io/kubernetes/pkg/volume"
40 volumetest "k8s.io/kubernetes/pkg/volume/testing"
41 )
42
43 const (
44 testVolName = "vol-1234"
45 testRBDImage = "volume-a4b47414-a675-47dc-a9cc-c223f13439b0"
46 testRBDPool = "volumes"
47 testGlobalPath = "plugins/kubernetes.io/rbd/volumeDevices/volumes-image-volume-a4b47414-a675-47dc-a9cc-c223f13439b0"
48 )
49
50 func TestGetVolumeSpecFromGlobalMapPath(t *testing.T) {
51
52
53
54 tmpVDir, err := utiltesting.MkTmpdir("rbdBlockTest")
55 if err != nil {
56 t.Fatalf("can't make a temp dir: %v", err)
57 }
58
59 defer os.RemoveAll(tmpVDir)
60
61 expectedGlobalPath := filepath.Join(tmpVDir, testGlobalPath)
62
63
64 badspec, err := getVolumeSpecFromGlobalMapPath("", testVolName)
65 if badspec != nil || err == nil {
66 t.Fatalf("Expected not to get spec from GlobalMapPath but did")
67 }
68
69
70 spec, err := getVolumeSpecFromGlobalMapPath(expectedGlobalPath, testVolName)
71 if spec == nil || err != nil {
72 t.Fatalf("Failed to get spec from GlobalMapPath: %v", err)
73 }
74
75 if spec.PersistentVolume.Name != testVolName {
76 t.Errorf("Invalid spec name for GlobalMapPath spec: %s", spec.PersistentVolume.Name)
77 }
78
79 if spec.PersistentVolume.Spec.RBD.RBDPool != testRBDPool {
80 t.Errorf("Invalid RBDPool from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.RBD.RBDPool)
81 }
82
83 if spec.PersistentVolume.Spec.RBD.RBDImage != testRBDImage {
84 t.Errorf("Invalid RBDImage from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.RBD.RBDImage)
85 }
86
87 block := v1.PersistentVolumeBlock
88 specMode := spec.PersistentVolume.Spec.VolumeMode
89 if specMode == nil {
90 t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v - %v", specMode, block)
91 }
92 if *specMode != block {
93 t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v - %v", *specMode, block)
94 }
95 }
96
97 func TestCanSupport(t *testing.T) {
98 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
99 if err != nil {
100 t.Fatalf("error creating temp dir: %v", err)
101 }
102 defer os.RemoveAll(tmpDir)
103
104 plugMgr := volume.VolumePluginMgr{}
105 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
106
107 plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
108 if err != nil {
109 t.Fatal("Can't find the plugin by name")
110 }
111 if plug.GetPluginName() != "kubernetes.io/rbd" {
112 t.Errorf("Wrong name: %s", plug.GetPluginName())
113 }
114 if plug.CanSupport(&volume.Spec{}) {
115 t.Errorf("Expected false")
116 }
117 if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
118 t.Errorf("Expected false")
119 }
120 if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{RBD: &v1.RBDVolumeSource{}}}}) {
121 t.Errorf("Expected true")
122 }
123 if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{}}}) {
124 t.Errorf("Expected false")
125 }
126 if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{}}}}) {
127 t.Errorf("Expected false")
128 }
129 if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{RBD: &v1.RBDPersistentVolumeSource{}}}}}) {
130 t.Errorf("Expected true")
131 }
132 }
133
134 type fakeDiskManager struct {
135
136 mutex sync.RWMutex
137
138 rbdImageLocks map[string]bool
139 rbdMapIndex int
140 rbdDevices map[string]bool
141 }
142
143 func newFakeDiskManager() *fakeDiskManager {
144 return &fakeDiskManager{
145 rbdImageLocks: make(map[string]bool),
146 rbdMapIndex: 0,
147 rbdDevices: make(map[string]bool),
148 }
149 }
150
151 func (fake *fakeDiskManager) MakeGlobalPDName(rbd rbd) string {
152 return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
153 }
154
155 func (fake *fakeDiskManager) MakeGlobalVDPDName(rbd rbd) string {
156 return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
157 }
158
159 func (fake *fakeDiskManager) DetachDisk(r *rbdPlugin, deviceMountPath string, device string) error {
160 fake.mutex.Lock()
161 defer fake.mutex.Unlock()
162 ok := fake.rbdDevices[device]
163 if !ok {
164 return fmt.Errorf("rbd: failed to detach device %s, it does not exist", device)
165 }
166 delete(fake.rbdDevices, device)
167 return nil
168 }
169
170 func (fake *fakeDiskManager) DetachBlockDisk(r rbdDiskUnmapper, device string) error {
171 fake.mutex.Lock()
172 defer fake.mutex.Unlock()
173 ok := fake.rbdDevices[device]
174 if !ok {
175 return fmt.Errorf("rbd: failed to detach device %s, it does not exist", device)
176 }
177 delete(fake.rbdDevices, device)
178 return nil
179 }
180
181 func (fake *fakeDiskManager) CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, volumeSizeGB int, err error) {
182 return nil, 0, fmt.Errorf("not implemented")
183 }
184
185 func (fake *fakeDiskManager) DeleteImage(deleter *rbdVolumeDeleter) error {
186 return fmt.Errorf("not implemented")
187 }
188
189 func (fake *fakeDiskManager) Fencing(r rbdMounter, nodeName string) error {
190 fake.mutex.Lock()
191 defer fake.mutex.Unlock()
192 key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
193 isLocked, ok := fake.rbdImageLocks[key]
194 if ok && isLocked {
195
196 return fmt.Errorf("%s is already locked", key)
197 }
198 fake.rbdImageLocks[key] = true
199 return nil
200 }
201
202 func (fake *fakeDiskManager) Defencing(r rbdMounter, nodeName string) error {
203 fake.mutex.Lock()
204 defer fake.mutex.Unlock()
205 key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
206 isLocked, ok := fake.rbdImageLocks[key]
207 if !ok || !isLocked {
208
209 return fmt.Errorf("%s is not locked", key)
210 }
211 delete(fake.rbdImageLocks, key)
212 return nil
213 }
214
215 func (fake *fakeDiskManager) IsLocked(r rbdMounter, nodeName string) (bool, error) {
216 fake.mutex.RLock()
217 defer fake.mutex.RUnlock()
218 key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
219 isLocked, ok := fake.rbdImageLocks[key]
220 return ok && isLocked, nil
221 }
222
223 func (fake *fakeDiskManager) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
224 return resource.Quantity{}, fmt.Errorf("not implemented")
225 }
226
227
228 func checkMounterLog(t *testing.T, fakeMounter *mount.FakeMounter, expected int, expectedAction mount.FakeAction) {
229 log := fakeMounter.GetLog()
230 if len(log) != expected {
231 t.Fatalf("fakeMounter should have %d logs, actual: %d", expected, len(log))
232 }
233 lastIndex := len(log) - 1
234 lastAction := log[lastIndex]
235 if !reflect.DeepEqual(expectedAction, lastAction) {
236 t.Fatalf("fakeMounter.Log[%d] should be %#v, not: %#v", lastIndex, expectedAction, lastAction)
237 }
238 }
239
240 func doTestPlugin(t *testing.T, c *testcase) {
241 fakeVolumeHost := volumetest.NewFakeKubeletVolumeHost(t, c.root, nil, nil)
242 plugMgr := volume.VolumePluginMgr{}
243 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , fakeVolumeHost)
244 plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
245 if err != nil {
246 t.Fatal("Can't find the plugin by name")
247 }
248 fakeMounter := fakeVolumeHost.GetMounter(plug.GetPluginName()).(*mount.FakeMounter)
249 fakeNodeName := types.NodeName("localhost")
250 fdm := newFakeDiskManager()
251
252
253 attacher, err := plug.(*rbdPlugin).newAttacherInternal(fdm)
254 if err != nil {
255 t.Errorf("Failed to make a new Attacher: %v", err)
256 }
257 deviceAttachPath, err := attacher.Attach(c.spec, fakeNodeName)
258 if err != nil {
259 t.Fatal(err)
260 }
261 devicePath, err := attacher.WaitForAttach(c.spec, deviceAttachPath, c.pod, time.Second*10)
262 if err != nil {
263 t.Fatal(err)
264 }
265 if devicePath != c.expectedDevicePath {
266 t.Errorf("Unexpected path, expected %q, not: %q", c.expectedDevicePath, devicePath)
267 }
268 deviceMountPath, err := attacher.GetDeviceMountPath(c.spec)
269 if err != nil {
270 t.Fatal(err)
271 }
272 if deviceMountPath != c.expectedDeviceMountPath {
273 t.Errorf("Unexpected mount path, expected %q, not: %q", c.expectedDeviceMountPath, deviceMountPath)
274 }
275 err = attacher.MountDevice(c.spec, devicePath, deviceMountPath, volume.DeviceMounterArgs{})
276 if err != nil {
277 t.Fatal(err)
278 }
279 if _, err := os.Stat(deviceMountPath); err != nil {
280 if os.IsNotExist(err) {
281 t.Errorf("Attacher.MountDevice() failed, device mount path not created: %s", deviceMountPath)
282 } else {
283 t.Errorf("Attacher.MountDevice() failed: %v", err)
284 }
285 }
286 loggedSource, err := getLoggedSource(devicePath)
287 if err != nil {
288 t.Fatal(err)
289 }
290 checkMounterLog(t, fakeMounter, 1, mount.FakeAction{Action: "mount", Target: c.expectedDeviceMountPath, Source: loggedSource, FSType: "ext4"})
291
292
293 mounter, err := plug.(*rbdPlugin).newMounterInternal(c.spec, c.pod.UID, fdm, "secrets")
294 if err != nil {
295 t.Errorf("Failed to make a new Mounter: %v", err)
296 }
297 if mounter == nil {
298 t.Error("Got a nil Mounter")
299 }
300 path := mounter.GetPath()
301 if path != c.expectedPodMountPath {
302 t.Errorf("Unexpected path, expected %q, got: %q", c.expectedPodMountPath, path)
303 }
304
305 if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
306 t.Errorf("Expected success, got: %v", err)
307 }
308 if _, err := os.Stat(path); err != nil {
309 if os.IsNotExist(err) {
310 t.Errorf("SetUp() failed, volume path not created: %s", path)
311 } else {
312 t.Errorf("SetUp() failed: %v", err)
313 }
314 }
315 checkMounterLog(t, fakeMounter, 2, mount.FakeAction{Action: "mount", Target: c.expectedPodMountPath, Source: loggedSource, FSType: ""})
316
317
318 unmounter, err := plug.(*rbdPlugin).newUnmounterInternal(c.spec.Name(), c.pod.UID, fdm)
319 if err != nil {
320 t.Errorf("Failed to make a new Unmounter: %v", err)
321 }
322 if unmounter == nil {
323 t.Error("Got a nil Unmounter")
324 }
325
326 if err := unmounter.TearDown(); err != nil {
327 t.Errorf("Expected success, got: %v", err)
328 }
329 if _, err := os.Stat(path); err == nil {
330 t.Errorf("TearDown() failed, volume path still exists: %s", path)
331 } else if !os.IsNotExist(err) {
332 t.Errorf("TearDown() failed: %v", err)
333 }
334 checkMounterLog(t, fakeMounter, 3, mount.FakeAction{Action: "unmount", Target: c.expectedPodMountPath, Source: "", FSType: ""})
335
336
337 detacher, err := plug.(*rbdPlugin).newDetacherInternal(fdm)
338 if err != nil {
339 t.Errorf("Failed to make a new Attacher: %v", err)
340 }
341 err = detacher.UnmountDevice(deviceMountPath)
342 if err != nil {
343 t.Fatalf("Detacher.UnmountDevice failed to unmount %s", deviceMountPath)
344 }
345 checkMounterLog(t, fakeMounter, 4, mount.FakeAction{Action: "unmount", Target: c.expectedDeviceMountPath, Source: "", FSType: ""})
346 err = detacher.Detach(deviceMountPath, fakeNodeName)
347 if err != nil {
348 t.Fatalf("Detacher.Detach failed to detach %s from %s", deviceMountPath, fakeNodeName)
349 }
350 }
351
352 type testcase struct {
353 spec *volume.Spec
354 root string
355 pod *v1.Pod
356 expectedDevicePath string
357 expectedDeviceMountPath string
358 expectedPodMountPath string
359 }
360
361 func TestPlugin(t *testing.T) {
362 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
363 if err != nil {
364 t.Fatalf("error creating temp dir: %v", err)
365 }
366 defer os.RemoveAll(tmpDir)
367 tmpDir, err = filepath.EvalSymlinks(tmpDir)
368 if err != nil {
369 t.Fatal(err)
370 }
371
372 expectedDevicePath := "/dev/rbd0"
373 if runtime.GOOS == "windows" {
374
375 expectedDevicePath = "0"
376 }
377
378 podUID := uuid.NewUUID()
379 var cases []*testcase
380 cases = append(cases, &testcase{
381 spec: volume.NewSpecFromVolume(&v1.Volume{
382 Name: "vol1",
383 VolumeSource: v1.VolumeSource{
384 RBD: &v1.RBDVolumeSource{
385 CephMonitors: []string{"a", "b"},
386 RBDPool: "pool1",
387 RBDImage: "image1",
388 FSType: "ext4",
389 },
390 },
391 }),
392 root: tmpDir,
393 pod: &v1.Pod{
394 ObjectMeta: metav1.ObjectMeta{
395 Name: "testpod",
396 Namespace: "testns",
397 UID: podUID,
398 },
399 },
400 expectedDevicePath: expectedDevicePath,
401 expectedDeviceMountPath: filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts/pool1-image-image1"),
402 expectedPodMountPath: filepath.Join(tmpDir, "pods", string(podUID), "volumes/kubernetes.io~rbd/vol1"),
403 })
404 cases = append(cases, &testcase{
405 spec: volume.NewSpecFromPersistentVolume(&v1.PersistentVolume{
406 ObjectMeta: metav1.ObjectMeta{
407 Name: "vol2",
408 },
409 Spec: v1.PersistentVolumeSpec{
410 PersistentVolumeSource: v1.PersistentVolumeSource{
411 RBD: &v1.RBDPersistentVolumeSource{
412 CephMonitors: []string{"a", "b"},
413 RBDPool: "pool2",
414 RBDImage: "image2",
415 FSType: "ext4",
416 },
417 },
418 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany},
419 },
420 }, false),
421 root: tmpDir,
422 pod: &v1.Pod{
423 ObjectMeta: metav1.ObjectMeta{
424 Name: "testpod",
425 Namespace: "testns",
426 UID: podUID,
427 },
428 },
429 expectedDevicePath: expectedDevicePath,
430 expectedDeviceMountPath: filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts/pool2-image-image2"),
431 expectedPodMountPath: filepath.Join(tmpDir, "pods", string(podUID), "volumes/kubernetes.io~rbd/vol2"),
432 })
433
434 for i := 0; i < len(cases); i++ {
435 doTestPlugin(t, cases[i])
436 }
437 }
438
439 func TestPersistentClaimReadOnlyFlag(t *testing.T) {
440 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
441 if err != nil {
442 t.Fatalf("error creating temp dir: %v", err)
443 }
444 defer os.RemoveAll(tmpDir)
445
446 pv := &v1.PersistentVolume{
447 ObjectMeta: metav1.ObjectMeta{
448 Name: "pvA",
449 },
450 Spec: v1.PersistentVolumeSpec{
451 PersistentVolumeSource: v1.PersistentVolumeSource{
452 RBD: &v1.RBDPersistentVolumeSource{
453 CephMonitors: []string{"a", "b"},
454 RBDImage: "bar",
455 FSType: "ext4",
456 },
457 },
458 ClaimRef: &v1.ObjectReference{
459 Name: "claimA",
460 },
461 },
462 }
463
464 claim := &v1.PersistentVolumeClaim{
465 ObjectMeta: metav1.ObjectMeta{
466 Name: "claimA",
467 Namespace: "nsA",
468 },
469 Spec: v1.PersistentVolumeClaimSpec{
470 VolumeName: "pvA",
471 },
472 Status: v1.PersistentVolumeClaimStatus{
473 Phase: v1.ClaimBound,
474 },
475 }
476
477 client := fake.NewSimpleClientset(pv, claim)
478
479 plugMgr := volume.VolumePluginMgr{}
480 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, client, nil))
481 plug, _ := plugMgr.FindPluginByName(rbdPluginName)
482
483
484 spec := volume.NewSpecFromPersistentVolume(pv, true)
485 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
486 mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
487 if mounter == nil {
488 t.Fatalf("Got a nil Mounter")
489 }
490
491 if !mounter.GetAttributes().ReadOnly {
492 t.Errorf("Expected true for mounter.IsReadOnly")
493 }
494 }
495
496 func TestGetSecretNameAndNamespace(t *testing.T) {
497 secretName := "test-secret-name"
498 secretNamespace := "test-secret-namespace"
499
500 volSpec := &volume.Spec{
501 PersistentVolume: &v1.PersistentVolume{
502 Spec: v1.PersistentVolumeSpec{
503 PersistentVolumeSource: v1.PersistentVolumeSource{
504 RBD: &v1.RBDPersistentVolumeSource{
505 CephMonitors: []string{"a", "b"},
506 RBDImage: "bar",
507 FSType: "ext4",
508 },
509 },
510 },
511 },
512 }
513
514 secretRef := new(v1.SecretReference)
515 secretRef.Name = secretName
516 secretRef.Namespace = secretNamespace
517 volSpec.PersistentVolume.Spec.PersistentVolumeSource.RBD.SecretRef = secretRef
518
519 foundSecretName, foundSecretNamespace, err := getSecretNameAndNamespace(volSpec, "default")
520 if err != nil {
521 t.Errorf("getSecretNameAndNamespace failed to get Secret's name and namespace: %v", err)
522 }
523 if strings.Compare(secretName, foundSecretName) != 0 || strings.Compare(secretNamespace, foundSecretNamespace) != 0 {
524 t.Errorf("getSecretNameAndNamespace returned incorrect values, expected %s and %s but got %s and %s", secretName, secretNamespace, foundSecretName, foundSecretNamespace)
525 }
526 }
527
528
529 func TestGetDeviceMountPath(t *testing.T) {
530 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
531 if err != nil {
532 t.Fatalf("error creating temp dir: %v", err)
533 }
534 defer os.RemoveAll(tmpDir)
535
536 fakeVolumeHost := volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)
537 plugMgr := volume.VolumePluginMgr{}
538 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , fakeVolumeHost)
539 plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
540 if err != nil {
541 t.Errorf("Can't find the plugin by name")
542 }
543 fdm := newFakeDiskManager()
544
545
546 attacher, err := plug.(*rbdPlugin).newAttacherInternal(fdm)
547 if err != nil {
548 t.Errorf("Failed to make a new Attacher: %v", err)
549 }
550
551 pool, image := "pool", "image"
552 spec := volume.NewSpecFromVolume(&v1.Volume{
553 Name: "vol",
554 VolumeSource: v1.VolumeSource{
555 RBD: &v1.RBDVolumeSource{
556 CephMonitors: []string{"a", "b"},
557 RBDPool: pool,
558 RBDImage: image,
559 FSType: "ext4",
560 },
561 },
562 })
563
564 deprecatedDir := filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/rbd/rbd/%s-image-%s", pool, image))
565 canonicalDir := filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/rbd/mounts/%s-image-%s", pool, image))
566
567 type testCase struct {
568 deprecated bool
569 targetPath string
570 }
571 for _, c := range []testCase{
572 {false, canonicalDir},
573 {true, deprecatedDir},
574 } {
575 if c.deprecated {
576
577
578 if err := os.MkdirAll(c.targetPath, 0700); err != nil {
579 t.Fatalf("Create deprecated mount path failed: %v", err)
580 }
581 }
582 mountPath, err := attacher.GetDeviceMountPath(spec)
583 if err != nil {
584 t.Fatalf("GetDeviceMountPath failed: %v", err)
585 }
586 if mountPath != c.targetPath {
587 t.Errorf("Mismatch device mount path: wanted %s, got %s", c.targetPath, mountPath)
588 }
589 }
590 }
591
592
593 func TestConstructVolumeSpec(t *testing.T) {
594 if runtime.GOOS == "darwin" {
595 t.Skipf("TestConstructVolumeSpec is not supported on GOOS=%s", runtime.GOOS)
596 }
597 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
598 if err != nil {
599 t.Fatalf("error creating temp dir: %v", err)
600 }
601 defer os.RemoveAll(tmpDir)
602
603 fakeVolumeHost := volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)
604 plugMgr := volume.VolumePluginMgr{}
605 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , fakeVolumeHost)
606 plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
607 if err != nil {
608 t.Fatal("Can't find the plugin by name")
609 }
610 fakeMounter := fakeVolumeHost.GetMounter(plug.GetPluginName()).(*mount.FakeMounter)
611
612 pool, image, volumeName := "pool", "image", "vol"
613 podMountPath := filepath.Join(tmpDir, "pods/pod123/volumes/kubernetes.io~rbd", volumeName)
614 deprecatedDir := filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/rbd", fmt.Sprintf("%s-image-%s", pool, image))
615 canonicalDir := filepath.Join(tmpDir, "plugins/kubernetes.io/rbd/mounts", fmt.Sprintf("%s-image-%s", pool, image))
616
617 type testCase struct {
618 volumeName string
619 targetPath string
620 }
621
622 for _, c := range []testCase{
623 {"vol", canonicalDir},
624 {"vol", deprecatedDir},
625 } {
626 if err := os.MkdirAll(c.targetPath, 0700); err != nil {
627 t.Fatalf("Create mount path %s failed: %v", c.targetPath, err)
628 }
629 if err = fakeMounter.Mount("/dev/rbd0", c.targetPath, "fake", nil); err != nil {
630 t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
631 }
632 if err = fakeMounter.Mount(c.targetPath, podMountPath, "fake", []string{"bind"}); err != nil {
633 t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
634 }
635 rec, err := plug.ConstructVolumeSpec(c.volumeName, podMountPath)
636 if err != nil {
637 t.Errorf("ConstructVolumeSpec failed: %v", err)
638 } else {
639 if rec.Spec.Volume.RBD.RBDPool != pool {
640 t.Errorf("Mismatch rbd pool: wanted %s, got %s", pool, rec.Spec.Volume.RBD.RBDPool)
641 }
642 if rec.Spec.Volume.RBD.RBDImage != image {
643 t.Fatalf("Mismatch rbd image: wanted %s, got %s", image, rec.Spec.Volume.RBD.RBDImage)
644 }
645 }
646 if err = fakeMounter.Unmount(podMountPath); err != nil {
647 t.Fatalf("Unmount pod path %s failed: %v", podMountPath, err)
648 }
649 if err = fakeMounter.Unmount(c.targetPath); err != nil {
650 t.Fatalf("Unmount device path %s failed: %v", c.targetPath, err)
651 }
652 }
653 }
654
655 func TestGetAccessModes(t *testing.T) {
656 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
657 if err != nil {
658 t.Fatalf("error creating temp dir: %v", err)
659 }
660 defer os.RemoveAll(tmpDir)
661
662 plugMgr := volume.VolumePluginMgr{}
663 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
664
665 plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/rbd")
666 if err != nil {
667 t.Errorf("Can't find the plugin by name")
668 }
669 modes := plug.GetAccessModes()
670 for _, v := range modes {
671 if !volumetest.ContainsAccessMode(modes, v) {
672 t.Errorf("Expected AccessModeTypes: %s", v)
673 }
674 }
675 }
676
677 func TestRequiresRemount(t *testing.T) {
678 tmpDir, _ := utiltesting.MkTmpdir("rbd_test")
679 defer os.RemoveAll(tmpDir)
680 plugMgr := volume.VolumePluginMgr{}
681 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil))
682 plug, _ := plugMgr.FindPluginByName("kubernetes.io/rbd")
683 has := plug.RequiresRemount(nil)
684 if has {
685 t.Errorf("Expected RequiresRemount to be false, got %t", has)
686 }
687 }
688
689 func TestGetRbdImageSize(t *testing.T) {
690 for i, c := range []struct {
691 Output string
692 TargetSize int
693 }{
694 {
695 Output: `{"name":"kubernetes-dynamic-pvc-18e7a4d9-050d-11e9-b905-548998f3478f","size":10737418240,"objects":2560,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.9f4ff7238e1f29","format":2}`,
696 TargetSize: 10240,
697 },
698 {
699 Output: `{"name":"kubernetes-dynamic-pvc-070635bf-e33f-11e8-aab7-548998f3478f","size":1073741824,"objects":256,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.670ac4238e1f29","format":2}`,
700 TargetSize: 1024,
701 },
702 } {
703 size, err := getRbdImageSize([]byte(c.Output))
704 if err != nil {
705 t.Errorf("Case %d: getRbdImageSize failed: %v", i, err)
706 continue
707 }
708 if size != c.TargetSize {
709 t.Errorf("Case %d: unexpected size, wanted %d, got %d", i, c.TargetSize, size)
710 }
711 }
712 }
713
714 func TestGetRbdImageInfo(t *testing.T) {
715 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
716 if err != nil {
717 t.Fatalf("error creating temp dir: %v", err)
718 }
719 defer os.RemoveAll(tmpDir)
720
721 for i, c := range []struct {
722 DeviceMountPath string
723 TargetRbdImageInfo *rbdImageInfo
724 }{
725 {
726 DeviceMountPath: fmt.Sprintf("%s/plugins/kubernetes.io/rbd/rbd/pool1-image-image1", tmpDir),
727 TargetRbdImageInfo: &rbdImageInfo{pool: "pool1", name: "image1"},
728 },
729 {
730 DeviceMountPath: fmt.Sprintf("%s/plugins/kubernetes.io/rbd/mounts/pool2-image-image2", tmpDir),
731 TargetRbdImageInfo: &rbdImageInfo{pool: "pool2", name: "image2"},
732 },
733 } {
734 rbdImageInfo, err := getRbdImageInfo(c.DeviceMountPath)
735 if err != nil {
736 t.Errorf("Case %d: getRbdImageInfo failed: %v", i, err)
737 continue
738 }
739 if !reflect.DeepEqual(rbdImageInfo, c.TargetRbdImageInfo) {
740 t.Errorf("Case %d: unexpected RbdImageInfo, wanted %v, got %v", i, c.TargetRbdImageInfo, rbdImageInfo)
741 }
742 }
743 }
744
745 func TestUnsupportedVolumeHost(t *testing.T) {
746 tmpDir, err := utiltesting.MkTmpdir("rbd_test")
747 if err != nil {
748 t.Fatalf("error creating temp dir: %v", err)
749 }
750 defer os.RemoveAll(tmpDir)
751
752 plugMgr := volume.VolumePluginMgr{}
753 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
754
755 plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
756 if err != nil {
757 t.Fatal("Can't find the plugin by name")
758 }
759
760 _, err = plug.ConstructVolumeSpec("", "")
761 if err == nil {
762 t.Errorf("Expected failure constructing volume spec with unsupported VolumeHost")
763 }
764 }
765
View as plain text