csi_attacher_test.go 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package csi
  14. import (
  15. "context"
  16. "fmt"
  17. "io/ioutil"
  18. "os"
  19. "path/filepath"
  20. "reflect"
  21. "sync"
  22. "testing"
  23. "time"
  24. v1 "k8s.io/api/core/v1"
  25. storage "k8s.io/api/storage/v1"
  26. apierrors "k8s.io/apimachinery/pkg/api/errors"
  27. meta "k8s.io/apimachinery/pkg/apis/meta/v1"
  28. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  29. "k8s.io/apimachinery/pkg/runtime"
  30. "k8s.io/apimachinery/pkg/types"
  31. "k8s.io/apimachinery/pkg/util/wait"
  32. "k8s.io/apimachinery/pkg/watch"
  33. utilfeature "k8s.io/apiserver/pkg/util/feature"
  34. "k8s.io/client-go/informers"
  35. clientset "k8s.io/client-go/kubernetes"
  36. fakeclient "k8s.io/client-go/kubernetes/fake"
  37. core "k8s.io/client-go/testing"
  38. utiltesting "k8s.io/client-go/util/testing"
  39. featuregatetesting "k8s.io/component-base/featuregate/testing"
  40. "k8s.io/kubernetes/pkg/features"
  41. "k8s.io/kubernetes/pkg/volume"
  42. fakecsi "k8s.io/kubernetes/pkg/volume/csi/fake"
  43. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  44. volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
  45. )
  46. var (
  47. bFalse = false
  48. bTrue = true
  49. )
  50. func makeTestAttachment(attachID, nodeName, pvName string) *storage.VolumeAttachment {
  51. return &storage.VolumeAttachment{
  52. ObjectMeta: meta.ObjectMeta{
  53. Name: attachID,
  54. },
  55. Spec: storage.VolumeAttachmentSpec{
  56. NodeName: nodeName,
  57. Attacher: "mock",
  58. Source: storage.VolumeAttachmentSource{
  59. PersistentVolumeName: &pvName,
  60. },
  61. },
  62. Status: storage.VolumeAttachmentStatus{
  63. Attached: false,
  64. AttachError: nil,
  65. DetachError: nil,
  66. },
  67. }
  68. }
  69. func markVolumeAttached(t *testing.T, client clientset.Interface, watch *watch.RaceFreeFakeWatcher, attachID string, status storage.VolumeAttachmentStatus) {
  70. ticker := time.NewTicker(10 * time.Millisecond)
  71. var attach *storage.VolumeAttachment
  72. var err error
  73. defer ticker.Stop()
  74. // wait for attachment to be saved
  75. for i := 0; i < 100; i++ {
  76. attach, err = client.StorageV1().VolumeAttachments().Get(context.TODO(), attachID, meta.GetOptions{})
  77. if err != nil {
  78. if apierrors.IsNotFound(err) {
  79. <-ticker.C
  80. continue
  81. }
  82. t.Error(err)
  83. }
  84. if attach != nil {
  85. t.Logf("attachment found on try %d, stopping wait...", i)
  86. break
  87. }
  88. }
  89. t.Logf("stopped waiting for attachment")
  90. if attach == nil {
  91. t.Logf("attachment not found for id:%v", attachID)
  92. } else {
  93. attach.Status = status
  94. t.Logf("updating attachment %s with attach status %v", attachID, status)
  95. _, err := client.StorageV1().VolumeAttachments().Update(context.TODO(), attach, metav1.UpdateOptions{})
  96. if err != nil {
  97. t.Error(err)
  98. }
  99. watch.Modify(attach)
  100. }
  101. }
  102. func TestAttacherAttach(t *testing.T) {
  103. testCases := []struct {
  104. name string
  105. nodeName string
  106. driverName string
  107. volumeName string
  108. attachID string
  109. spec *volume.Spec
  110. injectAttacherError bool
  111. shouldFail bool
  112. }{
  113. {
  114. name: "test ok 1",
  115. nodeName: "testnode-01",
  116. driverName: "testdriver-01",
  117. volumeName: "testvol-01",
  118. attachID: getAttachmentName("testvol-01", "testdriver-01", "testnode-01"),
  119. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "testdriver-01", "testvol-01"), false),
  120. },
  121. {
  122. name: "test ok 2",
  123. nodeName: "node02",
  124. driverName: "driver02",
  125. volumeName: "vol02",
  126. attachID: getAttachmentName("vol02", "driver02", "node02"),
  127. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol02"), false),
  128. },
  129. {
  130. name: "mismatch vol",
  131. nodeName: "node02",
  132. driverName: "driver02",
  133. volumeName: "vol01",
  134. attachID: getAttachmentName("vol02", "driver02", "node02"),
  135. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol01"), false),
  136. shouldFail: true,
  137. },
  138. {
  139. name: "mismatch driver",
  140. nodeName: "node02",
  141. driverName: "driver000",
  142. volumeName: "vol02",
  143. attachID: getAttachmentName("vol02", "driver02", "node02"),
  144. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver01", "vol02"), false),
  145. shouldFail: true,
  146. },
  147. {
  148. name: "mismatch node",
  149. nodeName: "node000",
  150. driverName: "driver000",
  151. volumeName: "vol02",
  152. attachID: getAttachmentName("vol02", "driver02", "node02"),
  153. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol02"), false),
  154. shouldFail: true,
  155. },
  156. {
  157. name: "attacher error",
  158. nodeName: "node02",
  159. driverName: "driver02",
  160. volumeName: "vol02",
  161. attachID: getAttachmentName("vol02", "driver02", "node02"),
  162. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver02", "vol02"), false),
  163. injectAttacherError: true,
  164. shouldFail: true,
  165. },
  166. {
  167. name: "test with volume source",
  168. nodeName: "node000",
  169. driverName: "driver000",
  170. volumeName: "vol02",
  171. attachID: getAttachmentName("vol02", "driver02", "node02"),
  172. spec: volume.NewSpecFromVolume(makeTestVol("pv01", "driver02")),
  173. shouldFail: true, // csi not enabled
  174. },
  175. {
  176. name: "missing spec",
  177. nodeName: "node000",
  178. driverName: "driver000",
  179. volumeName: "vol02",
  180. attachID: getAttachmentName("vol02", "driver02", "node02"),
  181. shouldFail: true, // csi not enabled
  182. },
  183. }
  184. // attacher loop
  185. for _, tc := range testCases {
  186. t.Run(tc.name, func(t *testing.T) {
  187. t.Logf("test case: %s", tc.name)
  188. plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
  189. defer os.RemoveAll(tmpDir)
  190. attacher, err := plug.NewAttacher()
  191. if err != nil {
  192. t.Fatalf("failed to create new attacher: %v", err)
  193. }
  194. csiAttacher := attacher.(*csiAttacher)
  195. go func(spec *volume.Spec, nodename string, fail bool) {
  196. attachID, err := csiAttacher.Attach(spec, types.NodeName(nodename))
  197. if !fail && err != nil {
  198. t.Errorf("expecting no failure, but got err: %v", err)
  199. }
  200. if fail && err == nil {
  201. t.Errorf("expecting failure, but got no err")
  202. }
  203. if attachID != "" {
  204. t.Errorf("expecting empty attachID, got %v", attachID)
  205. }
  206. }(tc.spec, tc.nodeName, tc.shouldFail)
  207. var status storage.VolumeAttachmentStatus
  208. if tc.injectAttacherError {
  209. status.Attached = false
  210. status.AttachError = &storage.VolumeError{
  211. Message: "attacher error",
  212. }
  213. errStatus := apierrors.NewInternalError(fmt.Errorf("we got an error")).Status()
  214. fakeWatcher.Error(&errStatus)
  215. } else {
  216. status.Attached = true
  217. }
  218. markVolumeAttached(t, csiAttacher.k8s, fakeWatcher, tc.attachID, status)
  219. })
  220. }
  221. }
  222. func TestAttacherAttachWithInline(t *testing.T) {
  223. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  224. testCases := []struct {
  225. name string
  226. nodeName string
  227. driverName string
  228. volumeName string
  229. attachID string
  230. spec *volume.Spec
  231. injectAttacherError bool
  232. shouldFail bool
  233. }{
  234. {
  235. name: "test ok 1 with PV",
  236. nodeName: "node01",
  237. attachID: getAttachmentName("vol01", "driver01", "node01"),
  238. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv01", 10, "driver01", "vol01"), false),
  239. },
  240. {
  241. name: "test failure, attach with volSrc",
  242. nodeName: "node01",
  243. attachID: getAttachmentName("vol01", "driver01", "node01"),
  244. spec: volume.NewSpecFromVolume(makeTestVol("vol01", "driver01")),
  245. shouldFail: true,
  246. },
  247. {
  248. name: "attacher error",
  249. nodeName: "node02",
  250. attachID: getAttachmentName("vol02", "driver02", "node02"),
  251. spec: volume.NewSpecFromPersistentVolume(makeTestPV("pv02", 10, "driver02", "vol02"), false),
  252. injectAttacherError: true,
  253. shouldFail: true,
  254. },
  255. {
  256. name: "missing spec",
  257. nodeName: "node02",
  258. attachID: getAttachmentName("vol02", "driver02", "node02"),
  259. shouldFail: true,
  260. },
  261. }
  262. // attacher loop
  263. for _, tc := range testCases {
  264. t.Run(tc.name, func(t *testing.T) {
  265. t.Logf("test case: %s", tc.name)
  266. plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
  267. defer os.RemoveAll(tmpDir)
  268. attacher, err := plug.NewAttacher()
  269. if err != nil {
  270. t.Fatalf("failed to create new attacher: %v", err)
  271. }
  272. csiAttacher := attacher.(*csiAttacher)
  273. go func(spec *volume.Spec, nodename string, fail bool) {
  274. attachID, err := csiAttacher.Attach(spec, types.NodeName(nodename))
  275. if fail != (err != nil) {
  276. t.Errorf("expecting no failure, but got err: %v", err)
  277. }
  278. if attachID != "" {
  279. t.Errorf("expecting empty attachID, got %v", attachID)
  280. }
  281. }(tc.spec, tc.nodeName, tc.shouldFail)
  282. var status storage.VolumeAttachmentStatus
  283. if tc.injectAttacherError {
  284. status.Attached = false
  285. status.AttachError = &storage.VolumeError{
  286. Message: "attacher error",
  287. }
  288. } else {
  289. status.Attached = true
  290. }
  291. markVolumeAttached(t, csiAttacher.k8s, fakeWatcher, tc.attachID, status)
  292. })
  293. }
  294. }
  295. func TestAttacherWithCSIDriver(t *testing.T) {
  296. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIDriverRegistry, true)()
  297. tests := []struct {
  298. name string
  299. driver string
  300. expectVolumeAttachment bool
  301. }{
  302. {
  303. name: "CSIDriver not attachable",
  304. driver: "not-attachable",
  305. expectVolumeAttachment: false,
  306. },
  307. {
  308. name: "CSIDriver is attachable",
  309. driver: "attachable",
  310. expectVolumeAttachment: true,
  311. },
  312. {
  313. name: "CSIDriver.AttachRequired not set -> failure",
  314. driver: "nil",
  315. expectVolumeAttachment: true,
  316. },
  317. {
  318. name: "CSIDriver does not exist not set -> failure",
  319. driver: "unknown",
  320. expectVolumeAttachment: true,
  321. },
  322. }
  323. for _, test := range tests {
  324. t.Run(test.name, func(t *testing.T) {
  325. fakeClient := fakeclient.NewSimpleClientset(
  326. getTestCSIDriver("not-attachable", nil, &bFalse, nil),
  327. getTestCSIDriver("attachable", nil, &bTrue, nil),
  328. getTestCSIDriver("nil", nil, nil, nil),
  329. )
  330. plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, fakeClient)
  331. defer os.RemoveAll(tmpDir)
  332. attacher, err := plug.NewAttacher()
  333. if err != nil {
  334. t.Fatalf("failed to create new attacher: %v", err)
  335. }
  336. csiAttacher := attacher.(*csiAttacher)
  337. spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, test.driver, "test-vol"), false)
  338. pluginCanAttach, err := plug.CanAttach(spec)
  339. if err != nil {
  340. t.Fatalf("attacher.CanAttach failed: %s", err)
  341. }
  342. if pluginCanAttach != test.expectVolumeAttachment {
  343. t.Errorf("attacher.CanAttach does not match expected attachment status %t", test.expectVolumeAttachment)
  344. }
  345. if !pluginCanAttach {
  346. t.Log("plugin is not attachable")
  347. return
  348. }
  349. var wg sync.WaitGroup
  350. wg.Add(1)
  351. go func(volSpec *volume.Spec, expectAttach bool) {
  352. attachID, err := csiAttacher.Attach(volSpec, types.NodeName("fakeNode"))
  353. defer wg.Done()
  354. if err != nil {
  355. t.Errorf("Attach() failed: %s", err)
  356. }
  357. if attachID != "" {
  358. t.Errorf("Expected empty attachID, got %q", attachID)
  359. }
  360. }(spec, test.expectVolumeAttachment)
  361. if test.expectVolumeAttachment {
  362. expectedAttachID := getAttachmentName("test-vol", test.driver, "fakeNode")
  363. status := storage.VolumeAttachmentStatus{
  364. Attached: true,
  365. }
  366. markVolumeAttached(t, csiAttacher.k8s, fakeWatcher, expectedAttachID, status)
  367. }
  368. wg.Wait()
  369. })
  370. }
  371. }
  372. func TestAttacherWaitForVolumeAttachmentWithCSIDriver(t *testing.T) {
  373. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIDriverRegistry, true)()
  374. // In order to detect if the volume plugin would skip WaitForAttach for non-attachable drivers,
  375. // we do not instantiate any VolumeAttachment. So if the plugin does not skip attach, WaitForVolumeAttachment
  376. // will return an error that volume attachment was not found.
  377. tests := []struct {
  378. name string
  379. driver string
  380. expectError bool
  381. }{
  382. {
  383. name: "CSIDriver not attachable -> success",
  384. driver: "not-attachable",
  385. expectError: false,
  386. },
  387. {
  388. name: "CSIDriver is attachable -> failure",
  389. driver: "attachable",
  390. expectError: true,
  391. },
  392. {
  393. name: "CSIDriver.AttachRequired not set -> failure",
  394. driver: "nil",
  395. expectError: true,
  396. },
  397. {
  398. name: "CSIDriver does not exist not set -> failure",
  399. driver: "unknown",
  400. expectError: true,
  401. },
  402. }
  403. for _, test := range tests {
  404. t.Run(test.name, func(t *testing.T) {
  405. fakeClient := fakeclient.NewSimpleClientset(
  406. getTestCSIDriver("not-attachable", nil, &bFalse, nil),
  407. getTestCSIDriver("attachable", nil, &bTrue, nil),
  408. getTestCSIDriver("nil", nil, nil, nil),
  409. &v1.Node{
  410. ObjectMeta: metav1.ObjectMeta{
  411. Name: "fakeNode",
  412. },
  413. Spec: v1.NodeSpec{},
  414. },
  415. )
  416. plug, tmpDir := newTestPlugin(t, fakeClient)
  417. defer os.RemoveAll(tmpDir)
  418. attacher, err := plug.NewAttacher()
  419. if err != nil {
  420. t.Fatalf("failed to create new attacher: %v", err)
  421. }
  422. csiAttacher := attacher.(*csiAttacher)
  423. spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, test.driver, "test-vol"), false)
  424. pluginCanAttach, err := plug.CanAttach(spec)
  425. if err != nil {
  426. t.Fatalf("plugin.CanAttach test failed: %s", err)
  427. }
  428. if !pluginCanAttach {
  429. t.Log("plugin is not attachable")
  430. return
  431. }
  432. _, err = csiAttacher.WaitForAttach(spec, "", nil, time.Second)
  433. if err != nil && !test.expectError {
  434. t.Errorf("Unexpected error: %s", err)
  435. }
  436. if err == nil && test.expectError {
  437. t.Errorf("Expected error, got none")
  438. }
  439. })
  440. }
  441. }
  442. func TestAttacherWaitForAttach(t *testing.T) {
  443. tests := []struct {
  444. name string
  445. driver string
  446. makeAttachment func() *storage.VolumeAttachment
  447. spec *volume.Spec
  448. expectedAttachID string
  449. expectError bool
  450. }{
  451. {
  452. name: "successful attach",
  453. driver: "attachable",
  454. makeAttachment: func() *storage.VolumeAttachment {
  455. testAttachID := getAttachmentName("test-vol", "attachable", "fakeNode")
  456. successfulAttachment := makeTestAttachment(testAttachID, "fakeNode", "test-pv")
  457. successfulAttachment.Status.Attached = true
  458. return successfulAttachment
  459. },
  460. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "attachable", "test-vol"), false),
  461. expectedAttachID: getAttachmentName("test-vol", "attachable", "fakeNode"),
  462. expectError: false,
  463. },
  464. {
  465. name: "failed attach with vol source",
  466. makeAttachment: func() *storage.VolumeAttachment {
  467. testAttachID := getAttachmentName("test-vol", "attachable", "fakeNode")
  468. successfulAttachment := makeTestAttachment(testAttachID, "fakeNode", "volSrc01")
  469. successfulAttachment.Status.Attached = true
  470. return successfulAttachment
  471. },
  472. spec: volume.NewSpecFromVolume(makeTestVol("volSrc01", "attachable")),
  473. expectError: true,
  474. },
  475. {
  476. name: "failed attach",
  477. driver: "attachable",
  478. expectError: true,
  479. },
  480. }
  481. for _, test := range tests {
  482. t.Run(test.name, func(t *testing.T) {
  483. plug, _, tmpDir, _ := newTestWatchPlugin(t, nil)
  484. defer os.RemoveAll(tmpDir)
  485. attacher, err := plug.NewAttacher()
  486. if err != nil {
  487. t.Fatalf("failed to create new attacher: %v", err)
  488. }
  489. csiAttacher := attacher.(*csiAttacher)
  490. if test.makeAttachment != nil {
  491. attachment := test.makeAttachment()
  492. _, err = csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  493. if err != nil {
  494. t.Fatalf("failed to create VolumeAttachment: %v", err)
  495. }
  496. gotAttachment, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Get(context.TODO(), attachment.Name, meta.GetOptions{})
  497. if err != nil {
  498. t.Fatalf("failed to get created VolumeAttachment: %v", err)
  499. }
  500. t.Logf("created test VolumeAttachment %+v", gotAttachment)
  501. }
  502. attachID, err := csiAttacher.WaitForAttach(test.spec, "", nil, time.Second)
  503. if err != nil && !test.expectError {
  504. t.Errorf("Unexpected error: %s", err)
  505. }
  506. if err == nil && test.expectError {
  507. t.Errorf("Expected error, got none")
  508. }
  509. if attachID != test.expectedAttachID {
  510. t.Errorf("Expected attachID %q, got %q", test.expectedAttachID, attachID)
  511. }
  512. })
  513. }
  514. }
  515. func TestAttacherWaitForAttachWithInline(t *testing.T) {
  516. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  517. tests := []struct {
  518. name string
  519. driver string
  520. makeAttachment func() *storage.VolumeAttachment
  521. spec *volume.Spec
  522. expectedAttachID string
  523. expectError bool
  524. }{
  525. {
  526. name: "successful attach with PV",
  527. makeAttachment: func() *storage.VolumeAttachment {
  528. testAttachID := getAttachmentName("test-vol", "attachable", "fakeNode")
  529. successfulAttachment := makeTestAttachment(testAttachID, "fakeNode", "test-pv")
  530. successfulAttachment.Status.Attached = true
  531. return successfulAttachment
  532. },
  533. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "attachable", "test-vol"), false),
  534. expectedAttachID: getAttachmentName("test-vol", "attachable", "fakeNode"),
  535. expectError: false,
  536. },
  537. {
  538. name: "failed attach with volSrc",
  539. makeAttachment: func() *storage.VolumeAttachment {
  540. testAttachID := getAttachmentName("test-vol", "attachable", "fakeNode")
  541. successfulAttachment := makeTestAttachment(testAttachID, "fakeNode", "volSrc01")
  542. successfulAttachment.Status.Attached = true
  543. return successfulAttachment
  544. },
  545. spec: volume.NewSpecFromVolume(makeTestVol("volSrc01", "attachable")),
  546. expectError: true,
  547. },
  548. {
  549. name: "failed attach",
  550. driver: "non-attachable",
  551. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "non-attachable", "test-vol"), false),
  552. expectError: true,
  553. },
  554. }
  555. for _, test := range tests {
  556. t.Run(test.name, func(t *testing.T) {
  557. plug, _, tmpDir, _ := newTestWatchPlugin(t, nil)
  558. defer os.RemoveAll(tmpDir)
  559. attacher, err := plug.NewAttacher()
  560. if err != nil {
  561. t.Fatalf("failed to create new attacher: %v", err)
  562. }
  563. csiAttacher := attacher.(*csiAttacher)
  564. if test.makeAttachment != nil {
  565. attachment := test.makeAttachment()
  566. _, err = csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  567. if err != nil {
  568. t.Fatalf("failed to create VolumeAttachment: %v", err)
  569. }
  570. gotAttachment, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Get(context.TODO(), attachment.Name, meta.GetOptions{})
  571. if err != nil {
  572. t.Fatalf("failed to get created VolumeAttachment: %v", err)
  573. }
  574. t.Logf("created test VolumeAttachment %+v", gotAttachment)
  575. }
  576. attachID, err := csiAttacher.WaitForAttach(test.spec, "", nil, time.Second)
  577. if test.expectError != (err != nil) {
  578. t.Errorf("Unexpected error: %s", err)
  579. return
  580. }
  581. if attachID != test.expectedAttachID {
  582. t.Errorf("Expected attachID %q, got %q", test.expectedAttachID, attachID)
  583. }
  584. })
  585. }
  586. }
  587. func TestAttacherWaitForVolumeAttachment(t *testing.T) {
  588. nodeName := "fakeNode"
  589. testCases := []struct {
  590. name string
  591. initAttached bool
  592. finalAttached bool
  593. trigerWatchEventTime time.Duration
  594. initAttachErr *storage.VolumeError
  595. finalAttachErr *storage.VolumeError
  596. timeout time.Duration
  597. shouldFail bool
  598. }{
  599. {
  600. name: "attach success at get",
  601. initAttached: true,
  602. timeout: 50 * time.Millisecond,
  603. shouldFail: false,
  604. },
  605. {
  606. name: "attachment error ant get",
  607. initAttachErr: &storage.VolumeError{Message: "missing volume"},
  608. timeout: 30 * time.Millisecond,
  609. shouldFail: true,
  610. },
  611. {
  612. name: "attach success at watch",
  613. initAttached: false,
  614. finalAttached: true,
  615. trigerWatchEventTime: 5 * time.Millisecond,
  616. timeout: 50 * time.Millisecond,
  617. shouldFail: false,
  618. },
  619. {
  620. name: "attachment error ant watch",
  621. initAttached: false,
  622. finalAttached: false,
  623. finalAttachErr: &storage.VolumeError{Message: "missing volume"},
  624. trigerWatchEventTime: 5 * time.Millisecond,
  625. timeout: 30 * time.Millisecond,
  626. shouldFail: true,
  627. },
  628. {
  629. name: "time ran out",
  630. initAttached: false,
  631. finalAttached: true,
  632. trigerWatchEventTime: 100 * time.Millisecond,
  633. timeout: 50 * time.Millisecond,
  634. shouldFail: true,
  635. },
  636. }
  637. for i, tc := range testCases {
  638. t.Run(tc.name, func(t *testing.T) {
  639. plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
  640. defer os.RemoveAll(tmpDir)
  641. attacher, err := plug.NewAttacher()
  642. if err != nil {
  643. t.Fatalf("failed to create new attacher: %v", err)
  644. }
  645. csiAttacher := attacher.(*csiAttacher)
  646. t.Logf("running test: %v", tc.name)
  647. pvName := fmt.Sprintf("test-pv-%d", i)
  648. volID := fmt.Sprintf("test-vol-%d", i)
  649. attachID := getAttachmentName(volID, testDriver, nodeName)
  650. attachment := makeTestAttachment(attachID, nodeName, pvName)
  651. attachment.Status.Attached = tc.initAttached
  652. attachment.Status.AttachError = tc.initAttachErr
  653. _, err = csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  654. if err != nil {
  655. t.Fatalf("failed to attach: %v", err)
  656. }
  657. trigerWatchEventTime := tc.trigerWatchEventTime
  658. finalAttached := tc.finalAttached
  659. finalAttachErr := tc.finalAttachErr
  660. // after timeout, fakeWatcher will be closed by csiAttacher.waitForVolumeAttachment
  661. if tc.trigerWatchEventTime > 0 && tc.trigerWatchEventTime < tc.timeout {
  662. go func() {
  663. time.Sleep(trigerWatchEventTime)
  664. attachment := makeTestAttachment(attachID, nodeName, pvName)
  665. attachment.Status.Attached = finalAttached
  666. attachment.Status.AttachError = finalAttachErr
  667. fakeWatcher.Modify(attachment)
  668. }()
  669. }
  670. retID, err := csiAttacher.waitForVolumeAttachment(volID, attachID, tc.timeout)
  671. if tc.shouldFail && err == nil {
  672. t.Error("expecting failure, but err is nil")
  673. }
  674. if tc.initAttachErr != nil {
  675. if tc.initAttachErr.Message != err.Error() {
  676. t.Errorf("expecting error [%v], got [%v]", tc.initAttachErr.Message, err.Error())
  677. }
  678. }
  679. if err == nil && retID != attachID {
  680. t.Errorf("attacher.WaitForAttach not returning attachment ID")
  681. }
  682. })
  683. }
  684. }
  685. func TestAttacherVolumesAreAttached(t *testing.T) {
  686. type attachedSpec struct {
  687. volName string
  688. spec *volume.Spec
  689. attached bool
  690. }
  691. testCases := []struct {
  692. name string
  693. attachedSpecs []attachedSpec
  694. }{
  695. {
  696. "attach and detach",
  697. []attachedSpec{
  698. {"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
  699. {"vol1", volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol1"), false), true},
  700. {"vol2", volume.NewSpecFromPersistentVolume(makeTestPV("pv2", 10, testDriver, "vol2"), false), false},
  701. {"vol3", volume.NewSpecFromPersistentVolume(makeTestPV("pv3", 10, testDriver, "vol3"), false), false},
  702. {"vol4", volume.NewSpecFromPersistentVolume(makeTestPV("pv4", 20, testDriver, "vol4"), false), true},
  703. },
  704. },
  705. {
  706. "all detached",
  707. []attachedSpec{
  708. {"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), false},
  709. {"vol1", volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol1"), false), false},
  710. {"vol2", volume.NewSpecFromPersistentVolume(makeTestPV("pv2", 10, testDriver, "vol2"), false), false},
  711. },
  712. },
  713. {
  714. "all attached",
  715. []attachedSpec{
  716. {"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
  717. {"vol1", volume.NewSpecFromPersistentVolume(makeTestPV("pv1", 20, testDriver, "vol1"), false), true},
  718. },
  719. },
  720. {
  721. "include non-attable",
  722. []attachedSpec{
  723. {"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
  724. {"vol1", volume.NewSpecFromVolume(makeTestVol("pv1", testDriver)), false},
  725. },
  726. },
  727. }
  728. for _, tc := range testCases {
  729. t.Run(tc.name, func(t *testing.T) {
  730. plug, tmpDir := newTestPlugin(t, nil)
  731. defer os.RemoveAll(tmpDir)
  732. attacher, err := plug.NewAttacher()
  733. if err != nil {
  734. t.Fatalf("failed to create new attacher: %v", err)
  735. }
  736. csiAttacher := attacher.(*csiAttacher)
  737. nodeName := "fakeNode"
  738. var specs []*volume.Spec
  739. // create and save volume attchments
  740. for _, attachedSpec := range tc.attachedSpecs {
  741. specs = append(specs, attachedSpec.spec)
  742. attachID := getAttachmentName(attachedSpec.volName, testDriver, nodeName)
  743. attachment := makeTestAttachment(attachID, nodeName, attachedSpec.spec.Name())
  744. attachment.Status.Attached = attachedSpec.attached
  745. _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  746. if err != nil {
  747. t.Fatalf("failed to attach: %v", err)
  748. }
  749. }
  750. // retrieve attached status
  751. stats, err := csiAttacher.VolumesAreAttached(specs, types.NodeName(nodeName))
  752. if err != nil {
  753. t.Fatal(err)
  754. }
  755. if len(tc.attachedSpecs) != len(stats) {
  756. t.Errorf("expecting %d attachment status, got %d", len(tc.attachedSpecs), len(stats))
  757. }
  758. // compare attachment status for each spec
  759. for _, attached := range tc.attachedSpecs {
  760. stat, ok := stats[attached.spec]
  761. if attached.attached && !ok {
  762. t.Error("failed to retrieve attached status for:", attached.spec)
  763. }
  764. if attached.attached != stat {
  765. t.Errorf("expecting volume attachment %t, got %t", attached.attached, stat)
  766. }
  767. }
  768. })
  769. }
  770. }
  771. func TestAttacherVolumesAreAttachedWithInline(t *testing.T) {
  772. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  773. type attachedSpec struct {
  774. volName string
  775. spec *volume.Spec
  776. attached bool
  777. }
  778. testCases := []struct {
  779. name string
  780. attachedSpecs []attachedSpec
  781. }{
  782. {
  783. "attach and detach with volume sources",
  784. []attachedSpec{
  785. {"vol0", volume.NewSpecFromPersistentVolume(makeTestPV("pv0", 10, testDriver, "vol0"), false), true},
  786. {"vol1", volume.NewSpecFromVolume(makeTestVol("pv1", testDriver)), false},
  787. {"vol2", volume.NewSpecFromPersistentVolume(makeTestPV("pv2", 10, testDriver, "vol2"), false), true},
  788. {"vol3", volume.NewSpecFromVolume(makeTestVol("pv3", testDriver)), false},
  789. {"vol4", volume.NewSpecFromPersistentVolume(makeTestPV("pv4", 20, testDriver, "vol4"), false), true},
  790. },
  791. },
  792. }
  793. for _, tc := range testCases {
  794. t.Run(tc.name, func(t *testing.T) {
  795. plug, tmpDir := newTestPlugin(t, nil)
  796. defer os.RemoveAll(tmpDir)
  797. attacher, err := plug.NewAttacher()
  798. if err != nil {
  799. t.Fatalf("failed to create new attacher: %v", err)
  800. }
  801. csiAttacher := attacher.(*csiAttacher)
  802. nodeName := "fakeNode"
  803. var specs []*volume.Spec
  804. // create and save volume attchments
  805. for _, attachedSpec := range tc.attachedSpecs {
  806. specs = append(specs, attachedSpec.spec)
  807. attachID := getAttachmentName(attachedSpec.volName, testDriver, nodeName)
  808. attachment := makeTestAttachment(attachID, nodeName, attachedSpec.spec.Name())
  809. attachment.Status.Attached = attachedSpec.attached
  810. _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  811. if err != nil {
  812. t.Fatalf("failed to attach: %v", err)
  813. }
  814. }
  815. // retrieve attached status
  816. stats, err := csiAttacher.VolumesAreAttached(specs, types.NodeName(nodeName))
  817. if err != nil {
  818. t.Fatal(err)
  819. }
  820. if len(tc.attachedSpecs) != len(stats) {
  821. t.Errorf("expecting %d attachment status, got %d", len(tc.attachedSpecs), len(stats))
  822. }
  823. // compare attachment status for each spec
  824. for _, attached := range tc.attachedSpecs {
  825. stat, ok := stats[attached.spec]
  826. if attached.attached && !ok {
  827. t.Error("failed to retrieve attached status for:", attached.spec)
  828. }
  829. if attached.attached != stat {
  830. t.Errorf("expecting volume attachment %t, got %t", attached.attached, stat)
  831. }
  832. }
  833. })
  834. }
  835. }
  836. func TestAttacherDetach(t *testing.T) {
  837. nodeName := "fakeNode"
  838. testCases := []struct {
  839. name string
  840. volID string
  841. attachID string
  842. shouldFail bool
  843. watcherError bool
  844. reactor func(action core.Action) (handled bool, ret runtime.Object, err error)
  845. }{
  846. {name: "normal test", volID: "vol-001", attachID: getAttachmentName("vol-001", testDriver, nodeName)},
  847. {name: "normal test 2", volID: "vol-002", attachID: getAttachmentName("vol-002", testDriver, nodeName)},
  848. {name: "object not found", volID: "vol-non-existing", attachID: getAttachmentName("vol-003", testDriver, nodeName)},
  849. {
  850. name: "API error",
  851. volID: "vol-004",
  852. attachID: getAttachmentName("vol-004", testDriver, nodeName),
  853. shouldFail: true, // All other API errors should be propagated to caller
  854. reactor: func(action core.Action) (handled bool, ret runtime.Object, err error) {
  855. // return Forbidden to all DELETE requests
  856. if action.Matches("delete", "volumeattachments") {
  857. return true, nil, apierrors.NewForbidden(action.GetResource().GroupResource(), action.GetNamespace(), fmt.Errorf("mock error"))
  858. }
  859. return false, nil, nil
  860. },
  861. },
  862. {
  863. name: "API watch error happen",
  864. volID: "vol-005",
  865. attachID: getAttachmentName("vol-005", testDriver, nodeName),
  866. shouldFail: true,
  867. watcherError: true,
  868. reactor: func(action core.Action) (handled bool, ret runtime.Object, err error) {
  869. if action.Matches("get", "volumeattachments") {
  870. return true, makeTestAttachment(getAttachmentName("vol-005", testDriver, nodeName), nodeName, "vol-005"), nil
  871. }
  872. return false, nil, nil
  873. },
  874. },
  875. }
  876. for _, tc := range testCases {
  877. t.Run(tc.name, func(t *testing.T) {
  878. t.Logf("running test: %v", tc.name)
  879. plug, fakeWatcher, tmpDir, client := newTestWatchPlugin(t, nil)
  880. defer os.RemoveAll(tmpDir)
  881. if tc.reactor != nil {
  882. client.PrependReactor("*", "*", tc.reactor)
  883. }
  884. attacher, err0 := plug.NewAttacher()
  885. if err0 != nil {
  886. t.Fatalf("failed to create new attacher: %v", err0)
  887. }
  888. csiAttacher := attacher.(*csiAttacher)
  889. pv := makeTestPV("test-pv", 10, testDriver, tc.volID)
  890. spec := volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly)
  891. attachment := makeTestAttachment(tc.attachID, nodeName, "test-pv")
  892. _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  893. if err != nil {
  894. t.Fatalf("failed to attach: %v", err)
  895. }
  896. volumeName, err := plug.GetVolumeName(spec)
  897. if err != nil {
  898. t.Errorf("test case %s failed: %v", tc.name, err)
  899. }
  900. watchError := tc.watcherError
  901. csiAttacher.waitSleepTime = 100 * time.Millisecond
  902. go func() {
  903. if watchError {
  904. errStatus := apierrors.NewInternalError(fmt.Errorf("we got an error")).Status()
  905. fakeWatcher.Error(&errStatus)
  906. return
  907. }
  908. fakeWatcher.Delete(attachment)
  909. }()
  910. err = csiAttacher.Detach(volumeName, types.NodeName(nodeName))
  911. if tc.shouldFail && err == nil {
  912. t.Fatal("expecting failure, but err = nil")
  913. }
  914. if !tc.shouldFail && err != nil {
  915. t.Fatalf("unexpected err: %v", err)
  916. }
  917. attach, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Get(context.TODO(), tc.attachID, meta.GetOptions{})
  918. if err != nil {
  919. if !apierrors.IsNotFound(err) {
  920. t.Fatalf("unexpected err: %v", err)
  921. }
  922. } else {
  923. if attach == nil {
  924. t.Errorf("expecting attachment not to be nil, but it is")
  925. }
  926. }
  927. })
  928. }
  929. }
  930. func TestAttacherGetDeviceMountPath(t *testing.T) {
  931. // Setup
  932. // Create a new attacher
  933. plug, _, tmpDir, _ := newTestWatchPlugin(t, nil)
  934. defer os.RemoveAll(tmpDir)
  935. attacher, err0 := plug.NewAttacher()
  936. if err0 != nil {
  937. t.Fatalf("failed to create new attacher: %v", err0)
  938. }
  939. csiAttacher := attacher.(*csiAttacher)
  940. pluginDir := csiAttacher.plugin.host.GetPluginDir(plug.GetPluginName())
  941. testCases := []struct {
  942. testName string
  943. pvName string
  944. expectedMountPath string
  945. shouldFail bool
  946. }{
  947. {
  948. testName: "normal test",
  949. pvName: "test-pv1",
  950. expectedMountPath: pluginDir + "/pv/test-pv1/globalmount",
  951. },
  952. {
  953. testName: "no pv name",
  954. pvName: "",
  955. expectedMountPath: pluginDir + "/pv/test-pv1/globalmount",
  956. shouldFail: true,
  957. },
  958. }
  959. for _, tc := range testCases {
  960. t.Logf("Running test case: %s", tc.testName)
  961. var spec *volume.Spec
  962. // Create spec
  963. pv := makeTestPV(tc.pvName, 10, testDriver, "testvol")
  964. spec = volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly)
  965. // Run
  966. mountPath, err := csiAttacher.GetDeviceMountPath(spec)
  967. // Verify
  968. if err != nil && !tc.shouldFail {
  969. t.Errorf("test should not fail, but error occurred: %v", err)
  970. } else if err == nil {
  971. if tc.shouldFail {
  972. t.Errorf("test should fail, but no error occurred")
  973. } else if mountPath != tc.expectedMountPath {
  974. t.Errorf("mountPath does not equal expectedMountPath. Got: %s. Expected: %s", mountPath, tc.expectedMountPath)
  975. }
  976. }
  977. }
  978. }
  979. func TestAttacherMountDevice(t *testing.T) {
  980. pvName := "test-pv"
  981. nonFinalError := volumetypes.NewUncertainProgressError("")
  982. transientError := volumetypes.NewTransientOperationFailure("")
  983. testCases := []struct {
  984. testName string
  985. volName string
  986. devicePath string
  987. deviceMountPath string
  988. stageUnstageSet bool
  989. shouldFail bool
  990. createAttachment bool
  991. exitError error
  992. spec *volume.Spec
  993. }{
  994. {
  995. testName: "normal PV",
  996. volName: "test-vol1",
  997. devicePath: "path1",
  998. deviceMountPath: "path2",
  999. stageUnstageSet: true,
  1000. createAttachment: true,
  1001. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1002. },
  1003. {
  1004. testName: "normal PV with mount options",
  1005. volName: "test-vol1",
  1006. devicePath: "path1",
  1007. deviceMountPath: "path2",
  1008. stageUnstageSet: true,
  1009. createAttachment: true,
  1010. spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false),
  1011. },
  1012. {
  1013. testName: "normal PV but with missing attachment should result in no-change",
  1014. volName: "test-vol1",
  1015. devicePath: "path1",
  1016. deviceMountPath: "path2",
  1017. stageUnstageSet: true,
  1018. createAttachment: false,
  1019. shouldFail: true,
  1020. exitError: transientError,
  1021. spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false),
  1022. },
  1023. {
  1024. testName: "no vol name",
  1025. volName: "",
  1026. devicePath: "path1",
  1027. deviceMountPath: "path2",
  1028. stageUnstageSet: true,
  1029. shouldFail: true,
  1030. createAttachment: true,
  1031. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false),
  1032. },
  1033. {
  1034. testName: "no device path",
  1035. volName: "test-vol1",
  1036. devicePath: "",
  1037. deviceMountPath: "path2",
  1038. stageUnstageSet: true,
  1039. shouldFail: false,
  1040. createAttachment: true,
  1041. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1042. },
  1043. {
  1044. testName: "no device mount path",
  1045. volName: "test-vol1",
  1046. devicePath: "path1",
  1047. deviceMountPath: "",
  1048. stageUnstageSet: true,
  1049. shouldFail: true,
  1050. createAttachment: true,
  1051. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1052. },
  1053. {
  1054. testName: "stage_unstage cap not set",
  1055. volName: "test-vol1",
  1056. devicePath: "path1",
  1057. deviceMountPath: "path2",
  1058. stageUnstageSet: false,
  1059. createAttachment: true,
  1060. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1061. },
  1062. {
  1063. testName: "failure with volume source",
  1064. volName: "test-vol1",
  1065. devicePath: "path1",
  1066. deviceMountPath: "path2",
  1067. shouldFail: true,
  1068. createAttachment: true,
  1069. spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)),
  1070. },
  1071. {
  1072. testName: "pv with nodestage timeout should result in in-progress device",
  1073. volName: fakecsi.NodeStageTimeOut_VolumeID,
  1074. devicePath: "path1",
  1075. deviceMountPath: "path2",
  1076. stageUnstageSet: true,
  1077. createAttachment: true,
  1078. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, fakecsi.NodeStageTimeOut_VolumeID), false),
  1079. exitError: nonFinalError,
  1080. shouldFail: true,
  1081. },
  1082. }
  1083. for _, tc := range testCases {
  1084. t.Run(tc.testName, func(t *testing.T) {
  1085. t.Logf("Running test case: %s", tc.testName)
  1086. // Setup
  1087. // Create a new attacher
  1088. plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
  1089. defer os.RemoveAll(tmpDir)
  1090. attacher, err0 := plug.NewAttacher()
  1091. if err0 != nil {
  1092. t.Fatalf("failed to create new attacher: %v", err0)
  1093. }
  1094. csiAttacher := attacher.(*csiAttacher)
  1095. csiAttacher.csiClient = setupClient(t, tc.stageUnstageSet)
  1096. if tc.deviceMountPath != "" {
  1097. tc.deviceMountPath = filepath.Join(tmpDir, tc.deviceMountPath)
  1098. }
  1099. nodeName := string(csiAttacher.plugin.host.GetNodeName())
  1100. attachID := getAttachmentName(tc.volName, testDriver, nodeName)
  1101. if tc.createAttachment {
  1102. // Set up volume attachment
  1103. attachment := makeTestAttachment(attachID, nodeName, pvName)
  1104. _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  1105. if err != nil {
  1106. t.Fatalf("failed to attach: %v", err)
  1107. }
  1108. go func() {
  1109. fakeWatcher.Delete(attachment)
  1110. }()
  1111. }
  1112. // Run
  1113. err := csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath)
  1114. // Verify
  1115. if err != nil {
  1116. if !tc.shouldFail {
  1117. t.Errorf("test should not fail, but error occurred: %v", err)
  1118. }
  1119. return
  1120. }
  1121. if err == nil && tc.shouldFail {
  1122. t.Errorf("test should fail, but no error occurred")
  1123. }
  1124. if tc.exitError != nil && reflect.TypeOf(tc.exitError) != reflect.TypeOf(err) {
  1125. t.Fatalf("expected exitError: %v got: %v", tc.exitError, err)
  1126. }
  1127. // Verify call goes through all the way
  1128. numStaged := 1
  1129. if !tc.stageUnstageSet {
  1130. numStaged = 0
  1131. }
  1132. cdc := csiAttacher.csiClient.(*fakeCsiDriverClient)
  1133. staged := cdc.nodeClient.GetNodeStagedVolumes()
  1134. if len(staged) != numStaged {
  1135. t.Errorf("got wrong number of staged volumes, expecting %v got: %v", numStaged, len(staged))
  1136. }
  1137. if tc.stageUnstageSet {
  1138. vol, ok := staged[tc.volName]
  1139. if !ok {
  1140. t.Errorf("could not find staged volume: %s", tc.volName)
  1141. }
  1142. if vol.Path != tc.deviceMountPath {
  1143. t.Errorf("expected mount path: %s. got: %s", tc.deviceMountPath, vol.Path)
  1144. }
  1145. if !reflect.DeepEqual(vol.MountFlags, tc.spec.PersistentVolume.Spec.MountOptions) {
  1146. t.Errorf("expected mount options: %v, got: %v", tc.spec.PersistentVolume.Spec.MountOptions, vol.MountFlags)
  1147. }
  1148. }
  1149. })
  1150. }
  1151. }
  1152. func TestAttacherMountDeviceWithInline(t *testing.T) {
  1153. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  1154. pvName := "test-pv"
  1155. testCases := []struct {
  1156. testName string
  1157. volName string
  1158. devicePath string
  1159. deviceMountPath string
  1160. stageUnstageSet bool
  1161. shouldFail bool
  1162. spec *volume.Spec
  1163. }{
  1164. {
  1165. testName: "normal PV",
  1166. volName: "test-vol1",
  1167. devicePath: "path1",
  1168. deviceMountPath: "path2",
  1169. stageUnstageSet: true,
  1170. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1171. },
  1172. {
  1173. testName: "failure with volSrc",
  1174. volName: "test-vol1",
  1175. devicePath: "path1",
  1176. deviceMountPath: "path2",
  1177. shouldFail: true,
  1178. spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)),
  1179. },
  1180. {
  1181. testName: "no vol name",
  1182. volName: "",
  1183. devicePath: "path1",
  1184. deviceMountPath: "path2",
  1185. stageUnstageSet: true,
  1186. shouldFail: true,
  1187. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false),
  1188. },
  1189. {
  1190. testName: "no device path",
  1191. volName: "test-vol1",
  1192. devicePath: "",
  1193. deviceMountPath: "path2",
  1194. stageUnstageSet: true,
  1195. shouldFail: false,
  1196. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1197. },
  1198. {
  1199. testName: "no device mount path",
  1200. volName: "test-vol1",
  1201. devicePath: "path1",
  1202. deviceMountPath: "",
  1203. stageUnstageSet: true,
  1204. shouldFail: true,
  1205. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1206. },
  1207. {
  1208. testName: "stage_unstage cap not set",
  1209. volName: "test-vol1",
  1210. devicePath: "path1",
  1211. deviceMountPath: "path2",
  1212. stageUnstageSet: false,
  1213. spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false),
  1214. },
  1215. {
  1216. testName: "missing spec",
  1217. volName: "test-vol1",
  1218. devicePath: "path1",
  1219. deviceMountPath: "path2",
  1220. shouldFail: true,
  1221. },
  1222. }
  1223. for _, tc := range testCases {
  1224. t.Run(tc.testName, func(t *testing.T) {
  1225. t.Logf("Running test case: %s", tc.testName)
  1226. // Setup
  1227. // Create a new attacher
  1228. plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, nil)
  1229. defer os.RemoveAll(tmpDir)
  1230. attacher, err0 := plug.NewAttacher()
  1231. if err0 != nil {
  1232. t.Fatalf("failed to create new attacher: %v", err0)
  1233. }
  1234. csiAttacher := attacher.(*csiAttacher)
  1235. csiAttacher.csiClient = setupClient(t, tc.stageUnstageSet)
  1236. if tc.deviceMountPath != "" {
  1237. tc.deviceMountPath = filepath.Join(tmpDir, tc.deviceMountPath)
  1238. }
  1239. nodeName := string(csiAttacher.plugin.host.GetNodeName())
  1240. attachID := getAttachmentName(tc.volName, testDriver, nodeName)
  1241. // Set up volume attachment
  1242. attachment := makeTestAttachment(attachID, nodeName, pvName)
  1243. _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
  1244. if err != nil {
  1245. t.Fatalf("failed to attach: %v", err)
  1246. }
  1247. go func() {
  1248. fakeWatcher.Delete(attachment)
  1249. }()
  1250. // Run
  1251. err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath)
  1252. // Verify
  1253. if err != nil {
  1254. if !tc.shouldFail {
  1255. t.Errorf("test should not fail, but error occurred: %v", err)
  1256. }
  1257. return
  1258. }
  1259. if err == nil && tc.shouldFail {
  1260. t.Errorf("test should fail, but no error occurred")
  1261. }
  1262. // Verify call goes through all the way
  1263. numStaged := 1
  1264. if !tc.stageUnstageSet {
  1265. numStaged = 0
  1266. }
  1267. cdc := csiAttacher.csiClient.(*fakeCsiDriverClient)
  1268. staged := cdc.nodeClient.GetNodeStagedVolumes()
  1269. if len(staged) != numStaged {
  1270. t.Errorf("got wrong number of staged volumes, expecting %v got: %v", numStaged, len(staged))
  1271. }
  1272. if tc.stageUnstageSet {
  1273. vol, ok := staged[tc.volName]
  1274. if !ok {
  1275. t.Errorf("could not find staged volume: %s", tc.volName)
  1276. }
  1277. if vol.Path != tc.deviceMountPath {
  1278. t.Errorf("expected mount path: %s. got: %s", tc.deviceMountPath, vol.Path)
  1279. }
  1280. }
  1281. })
  1282. }
  1283. }
  1284. func TestAttacherUnmountDevice(t *testing.T) {
  1285. testCases := []struct {
  1286. testName string
  1287. volID string
  1288. deviceMountPath string
  1289. jsonFile string
  1290. createPV bool
  1291. stageUnstageSet bool
  1292. shouldFail bool
  1293. }{
  1294. {
  1295. testName: "normal, json file exists",
  1296. volID: "project/zone/test-vol1",
  1297. deviceMountPath: "plugins/csi/pv/test-pv-name/globalmount",
  1298. jsonFile: `{"driverName": "csi", "volumeHandle":"project/zone/test-vol1"}`,
  1299. createPV: false,
  1300. stageUnstageSet: true,
  1301. },
  1302. {
  1303. testName: "normal, json file doesn't exist -> use PV",
  1304. volID: "project/zone/test-vol1",
  1305. deviceMountPath: "plugins/csi/pv/test-pv-name/globalmount",
  1306. jsonFile: "",
  1307. createPV: true,
  1308. stageUnstageSet: true,
  1309. },
  1310. {
  1311. testName: "invalid json -> use PV",
  1312. volID: "project/zone/test-vol1",
  1313. deviceMountPath: "plugins/csi/pv/test-pv-name/globalmount",
  1314. jsonFile: `{"driverName"}}`,
  1315. createPV: true,
  1316. stageUnstageSet: true,
  1317. },
  1318. {
  1319. testName: "no json, no PV.volID",
  1320. volID: "",
  1321. deviceMountPath: "plugins/csi/pv/test-pv-name/globalmount",
  1322. jsonFile: "",
  1323. createPV: true,
  1324. shouldFail: true,
  1325. },
  1326. {
  1327. testName: "no json, no PV",
  1328. volID: "project/zone/test-vol1",
  1329. deviceMountPath: "plugins/csi/pv/test-pv-name/globalmount",
  1330. jsonFile: "",
  1331. createPV: false,
  1332. stageUnstageSet: true,
  1333. shouldFail: true,
  1334. },
  1335. {
  1336. testName: "stage_unstage not set no vars should not fail",
  1337. deviceMountPath: "plugins/csi/pv/test-pv-name/globalmount",
  1338. jsonFile: `{"driverName":"test-driver","volumeHandle":"test-vol1"}`,
  1339. stageUnstageSet: false,
  1340. },
  1341. }
  1342. for _, tc := range testCases {
  1343. t.Run(tc.testName, func(t *testing.T) {
  1344. t.Logf("Running test case: %s", tc.testName)
  1345. // Setup
  1346. // Create a new attacher
  1347. plug, _, tmpDir, _ := newTestWatchPlugin(t, nil)
  1348. defer os.RemoveAll(tmpDir)
  1349. attacher, err0 := plug.NewAttacher()
  1350. if err0 != nil {
  1351. t.Fatalf("failed to create new attacher: %v", err0)
  1352. }
  1353. csiAttacher := attacher.(*csiAttacher)
  1354. csiAttacher.csiClient = setupClient(t, tc.stageUnstageSet)
  1355. if tc.deviceMountPath != "" {
  1356. tc.deviceMountPath = filepath.Join(tmpDir, tc.deviceMountPath)
  1357. }
  1358. // Add the volume to NodeStagedVolumes
  1359. cdc := csiAttacher.csiClient.(*fakeCsiDriverClient)
  1360. cdc.nodeClient.AddNodeStagedVolume(tc.volID, tc.deviceMountPath, nil)
  1361. // Make JSON for this object
  1362. if tc.deviceMountPath != "" {
  1363. if err := os.MkdirAll(tc.deviceMountPath, 0755); err != nil {
  1364. t.Fatalf("error creating directory %s: %s", tc.deviceMountPath, err)
  1365. }
  1366. }
  1367. dir := filepath.Dir(tc.deviceMountPath)
  1368. if tc.jsonFile != "" {
  1369. dataPath := filepath.Join(dir, volDataFileName)
  1370. if err := ioutil.WriteFile(dataPath, []byte(tc.jsonFile), 0644); err != nil {
  1371. t.Fatalf("error creating %s: %s", dataPath, err)
  1372. }
  1373. }
  1374. if tc.createPV {
  1375. // Make the PV for this object
  1376. pvName := filepath.Base(dir)
  1377. pv := makeTestPV(pvName, 5, "csi", tc.volID)
  1378. _, err := csiAttacher.k8s.CoreV1().PersistentVolumes().Create(context.TODO(), pv, metav1.CreateOptions{})
  1379. if err != nil && !tc.shouldFail {
  1380. t.Fatalf("Failed to create PV: %v", err)
  1381. }
  1382. }
  1383. // Run
  1384. err := csiAttacher.UnmountDevice(tc.deviceMountPath)
  1385. // Verify
  1386. if err != nil {
  1387. if !tc.shouldFail {
  1388. t.Errorf("test should not fail, but error occurred: %v", err)
  1389. }
  1390. return
  1391. }
  1392. if err == nil && tc.shouldFail {
  1393. t.Errorf("test should fail, but no error occurred")
  1394. }
  1395. // Verify call goes through all the way
  1396. expectedSet := 0
  1397. if !tc.stageUnstageSet {
  1398. expectedSet = 1
  1399. }
  1400. staged := cdc.nodeClient.GetNodeStagedVolumes()
  1401. if len(staged) != expectedSet {
  1402. t.Errorf("got wrong number of staged volumes, expecting %v got: %v", expectedSet, len(staged))
  1403. }
  1404. _, ok := staged[tc.volID]
  1405. if ok && tc.stageUnstageSet {
  1406. t.Errorf("found unexpected staged volume: %s", tc.volID)
  1407. } else if !ok && !tc.stageUnstageSet {
  1408. t.Errorf("could not find expected staged volume: %s", tc.volID)
  1409. }
  1410. if tc.jsonFile != "" && !tc.shouldFail {
  1411. dataPath := filepath.Join(dir, volDataFileName)
  1412. if _, err := os.Stat(dataPath); !os.IsNotExist(err) {
  1413. if err != nil {
  1414. t.Errorf("error checking file %s: %s", dataPath, err)
  1415. } else {
  1416. t.Errorf("json file %s should not exists, but it does", dataPath)
  1417. }
  1418. } else {
  1419. t.Logf("json file %s was correctly removed", dataPath)
  1420. }
  1421. }
  1422. })
  1423. }
  1424. }
  1425. // create a plugin mgr to load plugins and setup a fake client
  1426. func newTestWatchPlugin(t *testing.T, fakeClient *fakeclient.Clientset) (*csiPlugin, *watch.RaceFreeFakeWatcher, string, *fakeclient.Clientset) {
  1427. tmpDir, err := utiltesting.MkTmpdir("csi-test")
  1428. if err != nil {
  1429. t.Fatalf("can't create temp dir: %v", err)
  1430. }
  1431. if fakeClient == nil {
  1432. fakeClient = fakeclient.NewSimpleClientset()
  1433. }
  1434. fakeClient.Tracker().Add(&v1.Node{
  1435. ObjectMeta: metav1.ObjectMeta{
  1436. Name: "fakeNode",
  1437. },
  1438. Spec: v1.NodeSpec{},
  1439. })
  1440. fakeWatcher := watch.NewRaceFreeFake()
  1441. fakeClient.Fake.PrependWatchReactor("volumeattachments", core.DefaultWatchReactor(fakeWatcher, nil))
  1442. // Start informer for CSIDrivers.
  1443. factory := informers.NewSharedInformerFactory(fakeClient, CsiResyncPeriod)
  1444. csiDriverInformer := factory.Storage().V1beta1().CSIDrivers()
  1445. csiDriverLister := csiDriverInformer.Lister()
  1446. factory.Start(wait.NeverStop)
  1447. host := volumetest.NewFakeVolumeHostWithCSINodeName(t,
  1448. tmpDir,
  1449. fakeClient,
  1450. ProbeVolumePlugins(),
  1451. "fakeNode",
  1452. csiDriverLister,
  1453. )
  1454. plugMgr := host.GetPluginMgr()
  1455. plug, err := plugMgr.FindPluginByName(CSIPluginName)
  1456. if err != nil {
  1457. t.Fatalf("can't find plugin %v", CSIPluginName)
  1458. }
  1459. csiPlug, ok := plug.(*csiPlugin)
  1460. if !ok {
  1461. t.Fatalf("cannot assert plugin to be type csiPlugin")
  1462. }
  1463. if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
  1464. // Wait until the informer in CSI volume plugin has all CSIDrivers.
  1465. wait.PollImmediate(TestInformerSyncPeriod, TestInformerSyncTimeout, func() (bool, error) {
  1466. return csiDriverInformer.Informer().HasSynced(), nil
  1467. })
  1468. }
  1469. return csiPlug, fakeWatcher, tmpDir, fakeClient
  1470. }