1
16
17 package fc
18
19 import (
20 "os"
21 "path/filepath"
22 "runtime"
23 "strconv"
24 "strings"
25 "testing"
26
27 "k8s.io/mount-utils"
28 testingexec "k8s.io/utils/exec/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 "k8s.io/client-go/kubernetes/fake"
34 utiltesting "k8s.io/client-go/util/testing"
35 "k8s.io/kubernetes/pkg/volume"
36 volumetest "k8s.io/kubernetes/pkg/volume/testing"
37 )
38
39 func TestCanSupport(t *testing.T) {
40 tmpDir, err := utiltesting.MkTmpdir("fc_test")
41 if err != nil {
42 t.Fatalf("error creating temp dir: %v", err)
43 }
44 defer os.RemoveAll(tmpDir)
45
46 plugMgr := volume.VolumePluginMgr{}
47 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
48
49 plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
50 if err != nil {
51 t.Fatal("Can't find the plugin by name")
52 }
53 if plug.GetPluginName() != "kubernetes.io/fc" {
54 t.Errorf("Wrong name: %s", plug.GetPluginName())
55 }
56 if plug.CanSupport(&volume.Spec{}) {
57 t.Errorf("Expected false")
58 }
59 if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
60 t.Errorf("Expected false")
61 }
62 if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{FC: &v1.FCVolumeSource{}}}}) {
63 t.Errorf("Expected true")
64 }
65 if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{}}}) {
66 t.Errorf("Expected false")
67 }
68 if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{}}}}) {
69 t.Errorf("Expected false")
70 }
71 if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{FC: &v1.FCVolumeSource{}}}}}) {
72 t.Errorf("Expected true")
73 }
74 }
75
76 func TestGetAccessModes(t *testing.T) {
77 tmpDir, err := utiltesting.MkTmpdir("fc_test")
78 if err != nil {
79 t.Fatalf("error creating temp dir: %v", err)
80 }
81 defer os.RemoveAll(tmpDir)
82
83 plugMgr := volume.VolumePluginMgr{}
84 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
85
86 plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/fc")
87 if err != nil {
88 t.Errorf("Can't find the plugin by name")
89 }
90 if !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadWriteOnce) || !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadOnlyMany) {
91 t.Errorf("Expected two AccessModeTypes: %s and %s", v1.ReadWriteOnce, v1.ReadOnlyMany)
92 }
93 }
94
95 type fakeDiskManager struct {
96 tmpDir string
97 attachCalled bool
98 detachCalled bool
99 }
100
101 func newFakeDiskManager() *fakeDiskManager {
102 return &fakeDiskManager{
103 tmpDir: utiltesting.MkTmpdirOrDie("fc_test"),
104 }
105 }
106
107 func (fake *fakeDiskManager) Cleanup() {
108 os.RemoveAll(fake.tmpDir)
109 }
110
111 func (fake *fakeDiskManager) MakeGlobalPDName(disk fcDisk) string {
112 return fake.tmpDir
113 }
114
115 func (fake *fakeDiskManager) MakeGlobalVDPDName(disk fcDisk) string {
116 return fake.tmpDir
117 }
118
119 func (fake *fakeDiskManager) AttachDisk(b fcDiskMounter) (string, error) {
120 globalPath := b.manager.MakeGlobalPDName(*b.fcDisk)
121 err := os.MkdirAll(globalPath, 0750)
122 if err != nil {
123 return "", err
124 }
125 fake.attachCalled = true
126 return "", nil
127 }
128
129 func (fake *fakeDiskManager) DetachDisk(c fcDiskUnmounter, mntPath string) error {
130 globalPath := c.manager.MakeGlobalPDName(*c.fcDisk)
131 err := os.RemoveAll(globalPath)
132 if err != nil {
133 return err
134 }
135 fake.detachCalled = true
136 return nil
137 }
138
139 func (fake *fakeDiskManager) DetachBlockFCDisk(c fcDiskUnmapper, mapPath, devicePath string) error {
140 err := os.RemoveAll(mapPath)
141 if err != nil {
142 return err
143 }
144 fake.detachCalled = true
145 return nil
146 }
147
148 func doTestPlugin(t *testing.T, spec *volume.Spec) {
149 tmpDir, err := utiltesting.MkTmpdir("fc_test")
150 if err != nil {
151 t.Fatalf("error creating temp dir: %v", err)
152 }
153 defer os.RemoveAll(tmpDir)
154
155 plugMgr := volume.VolumePluginMgr{}
156 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
157
158 plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
159 if err != nil {
160 t.Errorf("Can't find the plugin by name")
161 }
162 fakeManager := newFakeDiskManager()
163 defer fakeManager.Cleanup()
164 fakeMounter := mount.NewFakeMounter(nil)
165 fakeExec := &testingexec.FakeExec{}
166 mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
167 if err != nil {
168 t.Errorf("Failed to make a new Mounter: %v", err)
169 }
170 if mounter == nil {
171 t.Errorf("Got a nil Mounter: %v", err)
172 }
173
174 path := mounter.GetPath()
175 expectedPath := filepath.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~fc/vol1")
176 if path != expectedPath {
177 t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, path)
178 }
179
180 if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
181 t.Errorf("Expected success, got: %v", err)
182 }
183 if _, err := os.Stat(path); err != nil {
184 if os.IsNotExist(err) {
185 t.Errorf("SetUp() failed, volume path not created: %s", path)
186 } else {
187 t.Errorf("SetUp() failed: %v", err)
188 }
189 }
190
191 fakeManager2 := newFakeDiskManager()
192 defer fakeManager2.Cleanup()
193 unmounter, err := plug.(*fcPlugin).newUnmounterInternal("vol1", types.UID("poduid"), fakeManager2, fakeMounter, fakeExec)
194 if err != nil {
195 t.Errorf("Failed to make a new Unmounter: %v", err)
196 }
197 if unmounter == nil {
198 t.Errorf("Got a nil Unmounter: %v", err)
199 }
200
201 if err := unmounter.TearDown(); err != nil {
202 t.Errorf("Expected success, got: %v", err)
203 }
204 if _, err := os.Stat(path); err == nil {
205 t.Errorf("TearDown() failed, volume path still exists: %s", path)
206 } else if !os.IsNotExist(err) {
207 t.Errorf("TearDown() failed: %v", err)
208 }
209 }
210
211 func doTestPluginNilMounter(t *testing.T, spec *volume.Spec) {
212 tmpDir, err := utiltesting.MkTmpdir("fc_test")
213 if err != nil {
214 t.Fatalf("error creating temp dir: %v", err)
215 }
216 defer os.RemoveAll(tmpDir)
217
218 plugMgr := volume.VolumePluginMgr{}
219 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
220
221 plug, err := plugMgr.FindPluginByName("kubernetes.io/fc")
222 if err != nil {
223 t.Errorf("Can't find the plugin by name")
224 }
225 fakeManager := newFakeDiskManager()
226 defer fakeManager.Cleanup()
227 fakeMounter := mount.NewFakeMounter(nil)
228 fakeExec := &testingexec.FakeExec{}
229 mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
230 if err == nil {
231 t.Errorf("Error failed to make a new Mounter is expected: %v", err)
232 }
233 if mounter != nil {
234 t.Errorf("A nil Mounter is expected: %v", err)
235 }
236 }
237
238 func TestPluginVolume(t *testing.T) {
239 lun := int32(0)
240 vol := &v1.Volume{
241 Name: "vol1",
242 VolumeSource: v1.VolumeSource{
243 FC: &v1.FCVolumeSource{
244 TargetWWNs: []string{"500a0981891b8dc5"},
245 FSType: "ext4",
246 Lun: &lun,
247 },
248 },
249 }
250 doTestPlugin(t, volume.NewSpecFromVolume(vol))
251 }
252
253 func TestPluginPersistentVolume(t *testing.T) {
254 lun := int32(0)
255 fs := v1.PersistentVolumeFilesystem
256 vol := &v1.PersistentVolume{
257 ObjectMeta: metav1.ObjectMeta{
258 Name: "vol1",
259 },
260 Spec: v1.PersistentVolumeSpec{
261 PersistentVolumeSource: v1.PersistentVolumeSource{
262 FC: &v1.FCVolumeSource{
263 TargetWWNs: []string{"500a0981891b8dc5"},
264 FSType: "ext4",
265 Lun: &lun,
266 },
267 },
268 VolumeMode: &fs,
269 },
270 }
271 doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
272 }
273
274 func TestPluginVolumeWWIDs(t *testing.T) {
275 vol := &v1.Volume{
276 Name: "vol1",
277 VolumeSource: v1.VolumeSource{
278 FC: &v1.FCVolumeSource{
279 WWIDs: []string{"3600508b400105e210000900000490000"},
280 FSType: "ext4",
281 },
282 },
283 }
284 doTestPlugin(t, volume.NewSpecFromVolume(vol))
285 }
286
287 func TestPluginPersistentVolumeWWIDs(t *testing.T) {
288 fs := v1.PersistentVolumeFilesystem
289 vol := &v1.PersistentVolume{
290 ObjectMeta: metav1.ObjectMeta{
291 Name: "vol1",
292 },
293 Spec: v1.PersistentVolumeSpec{
294 PersistentVolumeSource: v1.PersistentVolumeSource{
295 FC: &v1.FCVolumeSource{
296 WWIDs: []string{"3600508b400105e21 000900000490000"},
297 FSType: "ext4",
298 },
299 },
300 VolumeMode: &fs,
301 },
302 }
303 doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
304 }
305
306 func TestPluginVolumeNoDiskInfo(t *testing.T) {
307 vol := &v1.Volume{
308 Name: "vol1",
309 VolumeSource: v1.VolumeSource{
310 FC: &v1.FCVolumeSource{
311 FSType: "ext4",
312 },
313 },
314 }
315 doTestPluginNilMounter(t, volume.NewSpecFromVolume(vol))
316 }
317
318 func TestPluginPersistentVolumeNoDiskInfo(t *testing.T) {
319 fs := v1.PersistentVolumeFilesystem
320 vol := &v1.PersistentVolume{
321 ObjectMeta: metav1.ObjectMeta{
322 Name: "vol1",
323 },
324 Spec: v1.PersistentVolumeSpec{
325 PersistentVolumeSource: v1.PersistentVolumeSource{
326 FC: &v1.FCVolumeSource{
327 FSType: "ext4",
328 },
329 },
330 VolumeMode: &fs,
331 },
332 }
333 doTestPluginNilMounter(t, volume.NewSpecFromPersistentVolume(vol, false))
334 }
335
336 func TestPersistentClaimReadOnlyFlag(t *testing.T) {
337 tmpDir, err := utiltesting.MkTmpdir("fc_test")
338 if err != nil {
339 t.Fatalf("error creating temp dir: %v", err)
340 }
341 defer os.RemoveAll(tmpDir)
342
343 lun := int32(0)
344 fs := v1.PersistentVolumeFilesystem
345 pv := &v1.PersistentVolume{
346 ObjectMeta: metav1.ObjectMeta{
347 Name: "pvA",
348 },
349 Spec: v1.PersistentVolumeSpec{
350 PersistentVolumeSource: v1.PersistentVolumeSource{
351 FC: &v1.FCVolumeSource{
352 TargetWWNs: []string{"some_wwn"},
353 FSType: "ext4",
354 Lun: &lun,
355 },
356 },
357 ClaimRef: &v1.ObjectReference{
358 Name: "claimA",
359 },
360 VolumeMode: &fs,
361 },
362 }
363
364 claim := &v1.PersistentVolumeClaim{
365 ObjectMeta: metav1.ObjectMeta{
366 Name: "claimA",
367 Namespace: "nsA",
368 },
369 Spec: v1.PersistentVolumeClaimSpec{
370 VolumeName: "pvA",
371 VolumeMode: &fs,
372 },
373 Status: v1.PersistentVolumeClaimStatus{
374 Phase: v1.ClaimBound,
375 },
376 }
377
378 client := fake.NewSimpleClientset(pv, claim)
379
380 plugMgr := volume.VolumePluginMgr{}
381 plugMgr.InitPlugins(ProbeVolumePlugins(), nil , volumetest.NewFakeVolumeHost(t, tmpDir, client, nil))
382 plug, _ := plugMgr.FindPluginByName(fcPluginName)
383
384
385 spec := volume.NewSpecFromPersistentVolume(pv, true)
386 pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
387 mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
388 if mounter == nil {
389 t.Fatalf("Got a nil Mounter")
390 }
391
392 if !mounter.GetAttributes().ReadOnly {
393 t.Errorf("Expected true for mounter.IsReadOnly")
394 }
395 }
396
397 func Test_getWwnsLun(t *testing.T) {
398 num := int32(0)
399 fc := &v1.FCVolumeSource{
400 TargetWWNs: []string{"500a0981891b8dc5"},
401 FSType: "ext4",
402 Lun: &num,
403 }
404 wwn, lun, _, err := getWwnsLunWwids(fc)
405
406 if (len(wwn) == 0 && lun != "0") || err != nil {
407 t.Errorf("no fc disk found")
408 }
409 }
410
411 func Test_getWwids(t *testing.T) {
412 fc := &v1.FCVolumeSource{
413 FSType: "ext4",
414 WWIDs: []string{"3600508b400105e210000900000490000"},
415 }
416 _, _, wwid, err := getWwnsLunWwids(fc)
417
418 if len(wwid) == 0 || err != nil {
419 t.Errorf("no fc disk found")
420 }
421 }
422
423 func Test_getWwnsLunWwidsError(t *testing.T) {
424 fc := &v1.FCVolumeSource{
425 FSType: "ext4",
426 }
427 wwn, lun, wwid, err := getWwnsLunWwids(fc)
428
429 if (len(wwn) != 0 && lun != "" && len(wwid) != 0) || err == nil {
430 t.Errorf("unexpected fc disk found")
431 }
432 }
433
434 func Test_ConstructVolumeSpec(t *testing.T) {
435 if runtime.GOOS == "darwin" {
436 t.Skipf("Test_ConstructVolumeSpec is not supported on GOOS=%s", runtime.GOOS)
437 }
438 fm := mount.NewFakeMounter(
439 []mount.MountPoint{
440 {Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1"},
441 {Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/fc/50060e801049cfd1-lun-0"},
442 {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod2"},
443 {Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/fc/volumeDevices/3600508b400105e210000900000490000"},
444 })
445 mountPaths := []string{
446 "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1",
447 "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod2",
448 }
449 for _, path := range mountPaths {
450 refs, err := fm.GetMountRefs(path)
451 if err != nil {
452 t.Errorf("couldn't get mountrefs. err: %v", err)
453 }
454 var globalPDPath string
455 for _, ref := range refs {
456 if strings.Contains(ref, "kubernetes.io/fc") {
457 globalPDPath = ref
458 break
459 }
460 }
461 if len(globalPDPath) == 0 {
462 t.Errorf("couldn't fetch mountrefs")
463 }
464 arr := strings.Split(globalPDPath, "/")
465 if len(arr) < 1 {
466 t.Errorf("failed to retrieve volume plugin information from globalPDPath: %v", globalPDPath)
467 }
468 volumeInfo := arr[len(arr)-1]
469 if strings.Contains(volumeInfo, "-lun-") {
470 wwnLun := strings.Split(volumeInfo, "-lun-")
471 if len(wwnLun) < 2 {
472 t.Errorf("failed to retrieve TargetWWN and Lun. volumeInfo is invalid: %v", volumeInfo)
473 }
474 lun, _ := strconv.Atoi(wwnLun[1])
475 lun32 := int32(lun)
476 if wwnLun[0] != "50060e801049cfd1" || lun32 != 0 {
477 t.Errorf("failed to retrieve TargetWWN and Lun")
478 }
479 } else {
480 if volumeInfo != "3600508b400105e210000900000490000" {
481 t.Errorf("failed to retrieve WWIDs")
482 }
483 }
484 }
485 }
486
487 func Test_ConstructVolumeSpecNoRefs(t *testing.T) {
488 fm := mount.NewFakeMounter(
489 []mount.MountPoint{
490 {Device: "/dev/sdd", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1"},
491 })
492 mountPaths := []string{
493 "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~fc/fc-in-pod1",
494 }
495 for _, path := range mountPaths {
496 refs, _ := fm.GetMountRefs(path)
497 var globalPDPath string
498 for _, ref := range refs {
499 if strings.Contains(ref, "kubernetes.io/fc") {
500 globalPDPath = ref
501 break
502 }
503 }
504 if len(globalPDPath) != 0 {
505 t.Errorf("invalid globalPDPath")
506 }
507 }
508 }
509
View as plain text