csi_plugin_test.go 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598
  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. "fmt"
  16. "math/rand"
  17. "os"
  18. "path/filepath"
  19. "testing"
  20. api "k8s.io/api/core/v1"
  21. v1 "k8s.io/api/core/v1"
  22. storagev1beta1 "k8s.io/api/storage/v1beta1"
  23. meta "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. "k8s.io/apimachinery/pkg/types"
  26. "k8s.io/apimachinery/pkg/util/wait"
  27. utilfeature "k8s.io/apiserver/pkg/util/feature"
  28. "k8s.io/client-go/informers"
  29. fakeclient "k8s.io/client-go/kubernetes/fake"
  30. utiltesting "k8s.io/client-go/util/testing"
  31. featuregatetesting "k8s.io/component-base/featuregate/testing"
  32. "k8s.io/kubernetes/pkg/features"
  33. "k8s.io/kubernetes/pkg/volume"
  34. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  35. )
  36. // create a plugin mgr to load plugins and setup a fake client
  37. func newTestPlugin(t *testing.T, client *fakeclient.Clientset) (*csiPlugin, string) {
  38. tmpDir, err := utiltesting.MkTmpdir("csi-test")
  39. if err != nil {
  40. t.Fatalf("can't create temp dir: %v", err)
  41. }
  42. if client == nil {
  43. client = fakeclient.NewSimpleClientset()
  44. }
  45. client.Tracker().Add(&v1.Node{
  46. ObjectMeta: metav1.ObjectMeta{
  47. Name: "fakeNode",
  48. },
  49. Spec: v1.NodeSpec{},
  50. })
  51. // Start informer for CSIDrivers.
  52. factory := informers.NewSharedInformerFactory(client, CsiResyncPeriod)
  53. csiDriverInformer := factory.Storage().V1beta1().CSIDrivers()
  54. csiDriverLister := csiDriverInformer.Lister()
  55. go factory.Start(wait.NeverStop)
  56. host := volumetest.NewFakeVolumeHostWithCSINodeName(t,
  57. tmpDir,
  58. client,
  59. ProbeVolumePlugins(),
  60. "fakeNode",
  61. csiDriverLister,
  62. )
  63. pluginMgr := host.GetPluginMgr()
  64. plug, err := pluginMgr.FindPluginByName(CSIPluginName)
  65. if err != nil {
  66. t.Fatalf("can't find plugin %v", CSIPluginName)
  67. }
  68. csiPlug, ok := plug.(*csiPlugin)
  69. if !ok {
  70. t.Fatalf("cannot assert plugin to be type csiPlugin")
  71. }
  72. if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
  73. // Wait until the informer in CSI volume plugin has all CSIDrivers.
  74. wait.PollImmediate(TestInformerSyncPeriod, TestInformerSyncTimeout, func() (bool, error) {
  75. return csiDriverInformer.Informer().HasSynced(), nil
  76. })
  77. }
  78. return csiPlug, tmpDir
  79. }
  80. func registerFakePlugin(pluginName, endpoint string, versions []string, t *testing.T) {
  81. highestSupportedVersions, err := highestSupportedVersion(versions)
  82. if err != nil {
  83. t.Fatalf("unexpected error parsing versions (%v) for pluginName %q endpoint %q: %#v", versions, pluginName, endpoint, err)
  84. }
  85. csiDrivers.Clear()
  86. csiDrivers.Set(pluginName, Driver{
  87. endpoint: endpoint,
  88. highestSupportedVersion: highestSupportedVersions,
  89. })
  90. }
  91. func TestPluginGetPluginName(t *testing.T) {
  92. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  93. plug, tmpDir := newTestPlugin(t, nil)
  94. defer os.RemoveAll(tmpDir)
  95. if plug.GetPluginName() != "kubernetes.io/csi" {
  96. t.Errorf("unexpected plugin name %v", plug.GetPluginName())
  97. }
  98. }
  99. func TestPluginGetVolumeName(t *testing.T) {
  100. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  101. plug, tmpDir := newTestPlugin(t, nil)
  102. defer os.RemoveAll(tmpDir)
  103. testCases := []struct {
  104. name string
  105. driverName string
  106. volName string
  107. spec *volume.Spec
  108. shouldFail bool
  109. }{
  110. {
  111. name: "alphanum names",
  112. driverName: "testdr",
  113. volName: "testvol",
  114. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "testdr", "testvol"), false),
  115. },
  116. {
  117. name: "mixchar driver",
  118. driverName: "test.dr.cc",
  119. volName: "testvol",
  120. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "test.dr.cc", "testvol"), false),
  121. },
  122. {
  123. name: "mixchar volume",
  124. driverName: "testdr",
  125. volName: "test-vol-name",
  126. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "testdr", "test-vol-name"), false),
  127. },
  128. {
  129. name: "mixchars all",
  130. driverName: "test-driver",
  131. volName: "test.vol.name",
  132. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "test-driver", "test.vol.name"), false),
  133. },
  134. {
  135. name: "volume source with mixchars all",
  136. driverName: "test-driver",
  137. volName: "test.vol.name",
  138. spec: volume.NewSpecFromVolume(makeTestVol("test-pv", "test-driver")),
  139. shouldFail: true, // csi inline feature off
  140. },
  141. {
  142. name: "missing spec",
  143. shouldFail: true,
  144. },
  145. }
  146. for _, tc := range testCases {
  147. t.Logf("testing: %s", tc.name)
  148. registerFakePlugin(tc.driverName, "endpoint", []string{"1.3.0"}, t)
  149. name, err := plug.GetVolumeName(tc.spec)
  150. if tc.shouldFail != (err != nil) {
  151. t.Fatal("shouldFail does match expected error")
  152. }
  153. if tc.shouldFail && err != nil {
  154. t.Log(err)
  155. continue
  156. }
  157. if name != fmt.Sprintf("%s%s%s", tc.driverName, volNameSep, tc.volName) {
  158. t.Errorf("unexpected volume name %s", name)
  159. }
  160. }
  161. }
  162. func TestPluginGetVolumeNameWithInline(t *testing.T) {
  163. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  164. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  165. modes := []storagev1beta1.VolumeLifecycleMode{
  166. storagev1beta1.VolumeLifecyclePersistent,
  167. }
  168. driver := getTestCSIDriver(testDriver, nil, nil, modes)
  169. client := fakeclient.NewSimpleClientset(driver)
  170. plug, tmpDir := newTestPlugin(t, client)
  171. defer os.RemoveAll(tmpDir)
  172. testCases := []struct {
  173. name string
  174. driverName string
  175. volName string
  176. shouldFail bool
  177. spec *volume.Spec
  178. }{
  179. {
  180. name: "missing spec",
  181. shouldFail: true,
  182. },
  183. {
  184. name: "alphanum names for pv",
  185. driverName: "testdr",
  186. volName: "testvol",
  187. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "testdr", "testvol"), false),
  188. },
  189. {
  190. name: "alphanum names for vol source",
  191. driverName: "testdr",
  192. volName: "testvol",
  193. spec: volume.NewSpecFromVolume(makeTestVol("test-pv", "testdr")),
  194. shouldFail: true,
  195. },
  196. }
  197. for _, tc := range testCases {
  198. t.Logf("testing: %s", tc.name)
  199. registerFakePlugin(tc.driverName, "endpoint", []string{"1.3.0"}, t)
  200. name, err := plug.GetVolumeName(tc.spec)
  201. if tc.shouldFail != (err != nil) {
  202. t.Fatal("shouldFail does match expected error")
  203. }
  204. if tc.shouldFail && err != nil {
  205. t.Log(err)
  206. continue
  207. }
  208. if name != fmt.Sprintf("%s%s%s", tc.driverName, volNameSep, tc.volName) {
  209. t.Errorf("unexpected volume name %s", name)
  210. }
  211. }
  212. }
  213. func TestPluginCanSupport(t *testing.T) {
  214. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  215. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, false)()
  216. tests := []struct {
  217. name string
  218. spec *volume.Spec
  219. canSupport bool
  220. }{
  221. {
  222. name: "no spec provided",
  223. canSupport: false,
  224. },
  225. {
  226. name: "can support volume source",
  227. spec: volume.NewSpecFromVolume(makeTestVol("test-vol", testDriver)),
  228. canSupport: false, // csi inline not enabled
  229. },
  230. {
  231. name: "can support persistent volume source",
  232. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 20, testDriver, testVol), true),
  233. canSupport: true,
  234. },
  235. }
  236. plug, tmpDir := newTestPlugin(t, nil)
  237. defer os.RemoveAll(tmpDir)
  238. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  239. for _, tc := range tests {
  240. t.Run(tc.name, func(t *testing.T) {
  241. actual := plug.CanSupport(tc.spec)
  242. if tc.canSupport != actual {
  243. t.Errorf("expecting canSupport %t, got %t", tc.canSupport, actual)
  244. }
  245. })
  246. }
  247. }
  248. func TestPluginCanSupportWithInline(t *testing.T) {
  249. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  250. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  251. tests := []struct {
  252. name string
  253. spec *volume.Spec
  254. canSupport bool
  255. }{
  256. {
  257. name: "no spec provided",
  258. canSupport: false,
  259. },
  260. {
  261. name: "can support volume source",
  262. spec: volume.NewSpecFromVolume(makeTestVol("test-vol", testDriver)),
  263. canSupport: true,
  264. },
  265. {
  266. name: "can support persistent volume source",
  267. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 20, testDriver, testVol), true),
  268. canSupport: true,
  269. },
  270. }
  271. plug, tmpDir := newTestPlugin(t, nil)
  272. defer os.RemoveAll(tmpDir)
  273. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  274. for _, tc := range tests {
  275. t.Run(tc.name, func(t *testing.T) {
  276. actual := plug.CanSupport(tc.spec)
  277. if tc.canSupport != actual {
  278. t.Errorf("expecting canSupport %t, got %t", tc.canSupport, actual)
  279. }
  280. })
  281. }
  282. }
  283. func TestPluginConstructVolumeSpec(t *testing.T) {
  284. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  285. plug, tmpDir := newTestPlugin(t, nil)
  286. defer os.RemoveAll(tmpDir)
  287. testCases := []struct {
  288. name string
  289. originSpec *volume.Spec
  290. specVolID string
  291. volHandle string
  292. podUID types.UID
  293. shouldFail bool
  294. }{
  295. {
  296. name: "construct spec1 from original persistent spec",
  297. specVolID: "test.vol.id",
  298. volHandle: "testvol-handle1",
  299. originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true),
  300. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  301. },
  302. {
  303. name: "construct spec2 from original persistent spec",
  304. specVolID: "spec2",
  305. volHandle: "handle2",
  306. originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true),
  307. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  308. },
  309. {
  310. name: "construct spec from original volume spec",
  311. specVolID: "volspec",
  312. originSpec: volume.NewSpecFromVolume(makeTestVol("spec2", testDriver)),
  313. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  314. shouldFail: true, // csi inline off
  315. },
  316. }
  317. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  318. for _, tc := range testCases {
  319. t.Run(tc.name, func(t *testing.T) {
  320. mounter, err := plug.NewMounter(
  321. tc.originSpec,
  322. &api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
  323. volume.VolumeOptions{},
  324. )
  325. if tc.shouldFail && err != nil {
  326. t.Log(err)
  327. return
  328. }
  329. if !tc.shouldFail && err != nil {
  330. t.Fatal(err)
  331. }
  332. if mounter == nil {
  333. t.Fatal("failed to create CSI mounter")
  334. }
  335. csiMounter := mounter.(*csiMountMgr)
  336. // rebuild spec
  337. spec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath()))
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. if spec == nil {
  342. t.Fatal("nil volume.Spec constructed")
  343. }
  344. // inspect spec
  345. if spec.PersistentVolume == nil || spec.PersistentVolume.Spec.CSI == nil {
  346. t.Fatal("CSIPersistentVolume not found in constructed spec ")
  347. }
  348. volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
  349. if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle {
  350. t.Error("unexpected volumeHandle constructed:", volHandle)
  351. }
  352. driverName := spec.PersistentVolume.Spec.CSI.Driver
  353. if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver {
  354. t.Error("unexpected driverName constructed:", driverName)
  355. }
  356. if spec.PersistentVolume.Spec.VolumeMode == nil {
  357. t.Fatalf("Volume mode has not been set.")
  358. }
  359. if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
  360. t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
  361. }
  362. if spec.Name() != tc.specVolID {
  363. t.Errorf("Unexpected spec name constructed %s", spec.Name())
  364. }
  365. })
  366. }
  367. }
  368. func TestPluginConstructVolumeSpecWithInline(t *testing.T) {
  369. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  370. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  371. testCases := []struct {
  372. name string
  373. originSpec *volume.Spec
  374. specVolID string
  375. volHandle string
  376. podUID types.UID
  377. shouldFail bool
  378. modes []storagev1beta1.VolumeLifecycleMode
  379. }{
  380. {
  381. name: "construct spec1 from persistent spec",
  382. specVolID: "test.vol.id",
  383. volHandle: "testvol-handle1",
  384. originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true),
  385. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  386. modes: []storagev1beta1.VolumeLifecycleMode{storagev1beta1.VolumeLifecyclePersistent},
  387. },
  388. {
  389. name: "construct spec2 from persistent spec",
  390. specVolID: "spec2",
  391. volHandle: "handle2",
  392. originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true),
  393. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  394. modes: []storagev1beta1.VolumeLifecycleMode{storagev1beta1.VolumeLifecyclePersistent},
  395. },
  396. {
  397. name: "construct spec2 from persistent spec, missing mode",
  398. specVolID: "spec2",
  399. volHandle: "handle2",
  400. originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true),
  401. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  402. modes: []storagev1beta1.VolumeLifecycleMode{},
  403. shouldFail: true,
  404. },
  405. {
  406. name: "construct spec from volume spec",
  407. specVolID: "volspec",
  408. originSpec: volume.NewSpecFromVolume(makeTestVol("volspec", testDriver)),
  409. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  410. modes: []storagev1beta1.VolumeLifecycleMode{storagev1beta1.VolumeLifecycleEphemeral},
  411. },
  412. {
  413. name: "construct spec from volume spec2",
  414. specVolID: "volspec2",
  415. originSpec: volume.NewSpecFromVolume(makeTestVol("volspec2", testDriver)),
  416. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  417. modes: []storagev1beta1.VolumeLifecycleMode{storagev1beta1.VolumeLifecycleEphemeral},
  418. },
  419. {
  420. name: "construct spec from volume spec2, missing mode",
  421. specVolID: "volspec2",
  422. originSpec: volume.NewSpecFromVolume(makeTestVol("volspec2", testDriver)),
  423. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  424. modes: []storagev1beta1.VolumeLifecycleMode{},
  425. shouldFail: true,
  426. },
  427. {
  428. name: "missing spec",
  429. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  430. shouldFail: true,
  431. },
  432. }
  433. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  434. for _, tc := range testCases {
  435. t.Run(tc.name, func(t *testing.T) {
  436. driver := getTestCSIDriver(testDriver, nil, nil, tc.modes)
  437. client := fakeclient.NewSimpleClientset(driver)
  438. plug, tmpDir := newTestPlugin(t, client)
  439. defer os.RemoveAll(tmpDir)
  440. mounter, err := plug.NewMounter(
  441. tc.originSpec,
  442. &api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
  443. volume.VolumeOptions{},
  444. )
  445. if tc.shouldFail && err != nil {
  446. t.Log(err)
  447. return
  448. }
  449. if !tc.shouldFail && err != nil {
  450. t.Fatal(err)
  451. }
  452. if mounter == nil {
  453. t.Fatal("failed to create CSI mounter")
  454. }
  455. csiMounter := mounter.(*csiMountMgr)
  456. // rebuild spec
  457. spec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath()))
  458. if err != nil {
  459. t.Fatal(err)
  460. }
  461. if spec == nil {
  462. t.Fatal("nil volume.Spec constructed")
  463. }
  464. if spec.Name() != tc.specVolID {
  465. t.Errorf("unexpected spec name constructed volume.Spec: %s", spec.Name())
  466. }
  467. switch {
  468. case spec.Volume != nil:
  469. if spec.Volume.CSI == nil {
  470. t.Error("missing CSIVolumeSource in constructed volume.Spec")
  471. }
  472. if spec.Volume.CSI.Driver != tc.originSpec.Volume.CSI.Driver {
  473. t.Error("unexpected driver in constructed volume source:", spec.Volume.CSI.Driver)
  474. }
  475. case spec.PersistentVolume != nil:
  476. if spec.PersistentVolume.Spec.CSI == nil {
  477. t.Fatal("missing CSIPersistentVolumeSource in constructed volume.spec")
  478. }
  479. volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
  480. if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle {
  481. t.Error("unexpected volumeHandle constructed in persistent volume source:", volHandle)
  482. }
  483. driverName := spec.PersistentVolume.Spec.CSI.Driver
  484. if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver {
  485. t.Error("unexpected driverName constructed in persistent volume source:", driverName)
  486. }
  487. if spec.PersistentVolume.Spec.VolumeMode == nil {
  488. t.Fatalf("Volume mode has not been set.")
  489. }
  490. if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
  491. t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
  492. }
  493. default:
  494. t.Fatal("invalid volume.Spec constructed")
  495. }
  496. })
  497. }
  498. }
  499. func TestPluginNewMounter(t *testing.T) {
  500. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  501. tests := []struct {
  502. name string
  503. spec *volume.Spec
  504. podUID types.UID
  505. namespace string
  506. volumeLifecycleMode storagev1beta1.VolumeLifecycleMode
  507. shouldFail bool
  508. }{
  509. {
  510. name: "mounter from persistent volume source",
  511. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv1", 20, testDriver, testVol), true),
  512. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  513. namespace: "test-ns1",
  514. volumeLifecycleMode: storagev1beta1.VolumeLifecyclePersistent,
  515. },
  516. {
  517. name: "mounter from volume source",
  518. spec: volume.NewSpecFromVolume(makeTestVol("test-vol1", testDriver)),
  519. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  520. namespace: "test-ns2",
  521. volumeLifecycleMode: storagev1beta1.VolumeLifecycleEphemeral,
  522. shouldFail: true, // csi inline not enabled
  523. },
  524. {
  525. name: "mounter from no spec provided",
  526. shouldFail: true,
  527. },
  528. }
  529. for _, test := range tests {
  530. t.Run(test.name, func(t *testing.T) {
  531. plug, tmpDir := newTestPlugin(t, nil)
  532. defer os.RemoveAll(tmpDir)
  533. registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t)
  534. mounter, err := plug.NewMounter(
  535. test.spec,
  536. &api.Pod{ObjectMeta: meta.ObjectMeta{UID: test.podUID, Namespace: test.namespace}},
  537. volume.VolumeOptions{},
  538. )
  539. if test.shouldFail != (err != nil) {
  540. t.Fatal("Unexpected error:", err)
  541. }
  542. if test.shouldFail && err != nil {
  543. t.Log(err)
  544. return
  545. }
  546. if mounter == nil {
  547. t.Fatal("failed to create CSI mounter")
  548. }
  549. csiMounter := mounter.(*csiMountMgr)
  550. // validate mounter fields
  551. if string(csiMounter.driverName) != testDriver {
  552. t.Error("mounter driver name not set")
  553. }
  554. if csiMounter.volumeID == "" {
  555. t.Error("mounter volume id not set")
  556. }
  557. if csiMounter.pod == nil {
  558. t.Error("mounter pod not set")
  559. }
  560. if string(csiMounter.podUID) != string(test.podUID) {
  561. t.Error("mounter podUID not set")
  562. }
  563. csiClient, err := csiMounter.csiClientGetter.Get()
  564. if csiClient == nil {
  565. t.Error("mounter csiClient is nil")
  566. }
  567. if err != nil {
  568. t.Fatal(err)
  569. }
  570. if csiMounter.volumeLifecycleMode != test.volumeLifecycleMode {
  571. t.Error("unexpected driver mode:", csiMounter.volumeLifecycleMode)
  572. }
  573. // ensure data file is created
  574. dataDir := filepath.Dir(mounter.GetPath())
  575. dataFile := filepath.Join(dataDir, volDataFileName)
  576. if _, err := os.Stat(dataFile); err != nil {
  577. if os.IsNotExist(err) {
  578. t.Errorf("data file not created %s", dataFile)
  579. } else {
  580. t.Fatal(err)
  581. }
  582. }
  583. data, err := loadVolumeData(dataDir, volDataFileName)
  584. if err != nil {
  585. t.Fatal(err)
  586. }
  587. if data[volDataKey.specVolID] != csiMounter.spec.Name() {
  588. t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID])
  589. }
  590. if data[volDataKey.volHandle] != csiMounter.volumeID {
  591. t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle])
  592. }
  593. if data[volDataKey.driverName] != string(csiMounter.driverName) {
  594. t.Error("volume data file unexpected driverName:", data[volDataKey.driverName])
  595. }
  596. if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) {
  597. t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName])
  598. }
  599. if data[volDataKey.volumeLifecycleMode] != string(test.volumeLifecycleMode) {
  600. t.Error("volume data file unexpected volumeLifecycleMode:", data[volDataKey.volumeLifecycleMode])
  601. }
  602. })
  603. }
  604. }
  605. func TestPluginNewMounterWithInline(t *testing.T) {
  606. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  607. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  608. bothModes := []storagev1beta1.VolumeLifecycleMode{
  609. storagev1beta1.VolumeLifecycleEphemeral,
  610. storagev1beta1.VolumeLifecyclePersistent,
  611. }
  612. persistentMode := []storagev1beta1.VolumeLifecycleMode{
  613. storagev1beta1.VolumeLifecyclePersistent,
  614. }
  615. ephemeralMode := []storagev1beta1.VolumeLifecycleMode{
  616. storagev1beta1.VolumeLifecycleEphemeral,
  617. }
  618. tests := []struct {
  619. name string
  620. spec *volume.Spec
  621. podUID types.UID
  622. namespace string
  623. volumeLifecycleMode storagev1beta1.VolumeLifecycleMode
  624. shouldFail bool
  625. }{
  626. {
  627. name: "mounter with missing spec",
  628. shouldFail: true,
  629. },
  630. {
  631. name: "mounter with spec with both volSrc and pvSrc",
  632. spec: &volume.Spec{
  633. Volume: makeTestVol("test-vol1", testDriver),
  634. PersistentVolume: makeTestPV("test-pv1", 20, testDriver, testVol),
  635. ReadOnly: true,
  636. },
  637. shouldFail: true,
  638. },
  639. {
  640. name: "mounter with persistent volume source",
  641. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-pv1", 20, testDriver, testVol), true),
  642. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  643. namespace: "test-ns1",
  644. volumeLifecycleMode: storagev1beta1.VolumeLifecyclePersistent,
  645. },
  646. {
  647. name: "mounter with volume source",
  648. spec: volume.NewSpecFromVolume(makeTestVol("test-vol1", testDriver)),
  649. podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())),
  650. namespace: "test-ns2",
  651. volumeLifecycleMode: storagev1beta1.VolumeLifecycleEphemeral,
  652. },
  653. }
  654. runAll := func(t *testing.T, supported []storagev1beta1.VolumeLifecycleMode) {
  655. for _, test := range tests {
  656. t.Run(test.name, func(t *testing.T) {
  657. driver := getTestCSIDriver(testDriver, nil, nil, supported)
  658. fakeClient := fakeclient.NewSimpleClientset(driver)
  659. plug, tmpDir := newTestPlugin(t, fakeClient)
  660. defer os.RemoveAll(tmpDir)
  661. registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t)
  662. mounter, err := plug.NewMounter(
  663. test.spec,
  664. &api.Pod{ObjectMeta: meta.ObjectMeta{UID: test.podUID, Namespace: test.namespace}},
  665. volume.VolumeOptions{},
  666. )
  667. // Some test cases are meant to fail because their input data is broken.
  668. shouldFail := test.shouldFail
  669. // Others fail if the driver does not support the volume mode.
  670. if !containsVolumeMode(supported, test.volumeLifecycleMode) {
  671. shouldFail = true
  672. }
  673. if shouldFail != (err != nil) {
  674. t.Fatal("Unexpected error:", err)
  675. }
  676. if shouldFail && err != nil {
  677. t.Log(err)
  678. return
  679. }
  680. if mounter == nil {
  681. t.Fatal("failed to create CSI mounter")
  682. }
  683. csiMounter := mounter.(*csiMountMgr)
  684. // validate mounter fields
  685. if string(csiMounter.driverName) != testDriver {
  686. t.Error("mounter driver name not set")
  687. }
  688. if csiMounter.volumeID == "" {
  689. t.Error("mounter volume id not set")
  690. }
  691. if csiMounter.pod == nil {
  692. t.Error("mounter pod not set")
  693. }
  694. if string(csiMounter.podUID) != string(test.podUID) {
  695. t.Error("mounter podUID not set")
  696. }
  697. csiClient, err := csiMounter.csiClientGetter.Get()
  698. if csiClient == nil {
  699. t.Error("mounter csiClient is nil")
  700. }
  701. if csiMounter.volumeLifecycleMode != test.volumeLifecycleMode {
  702. t.Error("unexpected driver mode:", csiMounter.volumeLifecycleMode)
  703. }
  704. // ensure data file is created
  705. dataDir := filepath.Dir(mounter.GetPath())
  706. dataFile := filepath.Join(dataDir, volDataFileName)
  707. if _, err := os.Stat(dataFile); err != nil {
  708. if os.IsNotExist(err) {
  709. t.Errorf("data file not created %s", dataFile)
  710. } else {
  711. t.Fatal(err)
  712. }
  713. }
  714. data, err := loadVolumeData(dataDir, volDataFileName)
  715. if err != nil {
  716. t.Fatal(err)
  717. }
  718. if data[volDataKey.specVolID] != csiMounter.spec.Name() {
  719. t.Error("volume data file unexpected specVolID:", data[volDataKey.specVolID])
  720. }
  721. if data[volDataKey.volHandle] != csiMounter.volumeID {
  722. t.Error("volume data file unexpected volHandle:", data[volDataKey.volHandle])
  723. }
  724. if data[volDataKey.driverName] != string(csiMounter.driverName) {
  725. t.Error("volume data file unexpected driverName:", data[volDataKey.driverName])
  726. }
  727. if data[volDataKey.nodeName] != string(csiMounter.plugin.host.GetNodeName()) {
  728. t.Error("volume data file unexpected nodeName:", data[volDataKey.nodeName])
  729. }
  730. if data[volDataKey.volumeLifecycleMode] != string(csiMounter.volumeLifecycleMode) {
  731. t.Error("volume data file unexpected volumeLifecycleMode:", data[volDataKey.volumeLifecycleMode])
  732. }
  733. })
  734. }
  735. }
  736. t.Run("both supported", func(t *testing.T) {
  737. runAll(t, bothModes)
  738. })
  739. t.Run("persistent supported", func(t *testing.T) {
  740. runAll(t, persistentMode)
  741. })
  742. t.Run("ephemeral supported", func(t *testing.T) {
  743. runAll(t, ephemeralMode)
  744. })
  745. }
  746. func TestPluginNewUnmounter(t *testing.T) {
  747. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  748. plug, tmpDir := newTestPlugin(t, nil)
  749. defer os.RemoveAll(tmpDir)
  750. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  751. pv := makeTestPV("test-pv", 10, testDriver, testVol)
  752. // save the data file to re-create client
  753. dir := filepath.Join(getTargetPath(testPodUID, pv.ObjectMeta.Name, plug.host), "/mount")
  754. if err := os.MkdirAll(dir, 0755); err != nil && !os.IsNotExist(err) {
  755. t.Errorf("failed to create dir [%s]: %v", dir, err)
  756. }
  757. if err := saveVolumeData(
  758. filepath.Dir(dir),
  759. volDataFileName,
  760. map[string]string{
  761. volDataKey.specVolID: pv.ObjectMeta.Name,
  762. volDataKey.driverName: testDriver,
  763. volDataKey.volHandle: testVol,
  764. },
  765. ); err != nil {
  766. t.Fatalf("failed to save volume data: %v", err)
  767. }
  768. // test unmounter
  769. unmounter, err := plug.NewUnmounter(pv.ObjectMeta.Name, testPodUID)
  770. csiUnmounter := unmounter.(*csiMountMgr)
  771. if err != nil {
  772. t.Fatalf("Failed to make a new Unmounter: %v", err)
  773. }
  774. if csiUnmounter == nil {
  775. t.Fatal("failed to create CSI Unmounter")
  776. }
  777. if csiUnmounter.podUID != testPodUID {
  778. t.Error("podUID not set")
  779. }
  780. csiClient, err := csiUnmounter.csiClientGetter.Get()
  781. if csiClient == nil {
  782. t.Error("mounter csiClient is nil")
  783. }
  784. }
  785. func TestPluginNewAttacher(t *testing.T) {
  786. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  787. plug, tmpDir := newTestPlugin(t, nil)
  788. defer os.RemoveAll(tmpDir)
  789. attacher, err := plug.NewAttacher()
  790. if err != nil {
  791. t.Fatalf("failed to create new attacher: %v", err)
  792. }
  793. csiAttacher := attacher.(*csiAttacher)
  794. if csiAttacher.plugin == nil {
  795. t.Error("plugin not set for attacher")
  796. }
  797. if csiAttacher.k8s == nil {
  798. t.Error("Kubernetes client not set for attacher")
  799. }
  800. }
  801. func TestPluginNewDetacher(t *testing.T) {
  802. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  803. plug, tmpDir := newTestPlugin(t, nil)
  804. defer os.RemoveAll(tmpDir)
  805. detacher, err := plug.NewDetacher()
  806. if err != nil {
  807. t.Fatalf("failed to create new detacher: %v", err)
  808. }
  809. csiDetacher := detacher.(*csiAttacher)
  810. if csiDetacher.plugin == nil {
  811. t.Error("plugin not set for detacher")
  812. }
  813. if csiDetacher.k8s == nil {
  814. t.Error("Kubernetes client not set for detacher")
  815. }
  816. }
  817. func TestPluginCanAttach(t *testing.T) {
  818. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIDriverRegistry, true)()
  819. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  820. tests := []struct {
  821. name string
  822. driverName string
  823. spec *volume.Spec
  824. canAttach bool
  825. shouldFail bool
  826. }{
  827. {
  828. name: "non-attachable inline",
  829. driverName: "attachable-inline",
  830. spec: volume.NewSpecFromVolume(makeTestVol("test-vol", "attachable-inline")),
  831. canAttach: false,
  832. },
  833. {
  834. name: "attachable PV",
  835. driverName: "attachable-pv",
  836. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-vol", 20, "attachable-pv", testVol), true),
  837. canAttach: true,
  838. },
  839. {
  840. name: "incomplete spec",
  841. driverName: "attachable-pv",
  842. spec: &volume.Spec{ReadOnly: true},
  843. canAttach: false,
  844. shouldFail: true,
  845. },
  846. {
  847. name: "nil spec",
  848. driverName: "attachable-pv",
  849. canAttach: false,
  850. shouldFail: true,
  851. },
  852. }
  853. for _, test := range tests {
  854. t.Run(test.name, func(t *testing.T) {
  855. csiDriver := getTestCSIDriver(test.driverName, nil, &test.canAttach, nil)
  856. fakeCSIClient := fakeclient.NewSimpleClientset(csiDriver)
  857. plug, tmpDir := newTestPlugin(t, fakeCSIClient)
  858. defer os.RemoveAll(tmpDir)
  859. pluginCanAttach, err := plug.CanAttach(test.spec)
  860. if err != nil && !test.shouldFail {
  861. t.Fatalf("unexected plugin.CanAttach error: %s", err)
  862. }
  863. if pluginCanAttach != test.canAttach {
  864. t.Fatalf("expecting plugin.CanAttach %t got %t", test.canAttach, pluginCanAttach)
  865. }
  866. })
  867. }
  868. }
  869. func TestPluginFindAttachablePlugin(t *testing.T) {
  870. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  871. tests := []struct {
  872. name string
  873. driverName string
  874. spec *volume.Spec
  875. canAttach bool
  876. shouldFail bool
  877. }{
  878. {
  879. name: "non-attachable inline",
  880. driverName: "attachable-inline",
  881. spec: volume.NewSpecFromVolume(makeTestVol("test-vol", "attachable-inline")),
  882. canAttach: false,
  883. },
  884. {
  885. name: "attachable PV",
  886. driverName: "attachable-pv",
  887. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-vol", 20, "attachable-pv", testVol), true),
  888. canAttach: true,
  889. },
  890. {
  891. name: "incomplete spec",
  892. driverName: "attachable-pv",
  893. spec: &volume.Spec{ReadOnly: true},
  894. canAttach: false,
  895. shouldFail: true,
  896. },
  897. {
  898. name: "nil spec",
  899. driverName: "attachable-pv",
  900. canAttach: false,
  901. shouldFail: true,
  902. },
  903. }
  904. for _, test := range tests {
  905. t.Run(test.name, func(t *testing.T) {
  906. tmpDir, err := utiltesting.MkTmpdir("csi-test")
  907. if err != nil {
  908. t.Fatalf("can't create temp dir: %v", err)
  909. }
  910. defer os.RemoveAll(tmpDir)
  911. client := fakeclient.NewSimpleClientset(
  912. getTestCSIDriver(test.driverName, nil, &test.canAttach, nil),
  913. &v1.Node{
  914. ObjectMeta: metav1.ObjectMeta{
  915. Name: "fakeNode",
  916. },
  917. Spec: v1.NodeSpec{},
  918. },
  919. )
  920. factory := informers.NewSharedInformerFactory(client, CsiResyncPeriod)
  921. host := volumetest.NewFakeVolumeHostWithCSINodeName(t,
  922. tmpDir,
  923. client,
  924. ProbeVolumePlugins(),
  925. "fakeNode",
  926. factory.Storage().V1beta1().CSIDrivers().Lister(),
  927. )
  928. plugMgr := host.GetPluginMgr()
  929. plugin, err := plugMgr.FindAttachablePluginBySpec(test.spec)
  930. if err != nil && !test.shouldFail {
  931. t.Fatalf("unexected error calling pluginMgr.FindAttachablePluginBySpec: %s", err)
  932. }
  933. if (plugin != nil) != test.canAttach {
  934. t.Fatal("expecting attachable plugin, but got nil")
  935. }
  936. })
  937. }
  938. }
  939. func TestPluginCanDeviceMount(t *testing.T) {
  940. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  941. tests := []struct {
  942. name string
  943. driverName string
  944. spec *volume.Spec
  945. canDeviceMount bool
  946. shouldFail bool
  947. }{
  948. {
  949. name: "non device mountable inline",
  950. driverName: "inline-driver",
  951. spec: volume.NewSpecFromVolume(makeTestVol("test-vol", "inline-driver")),
  952. canDeviceMount: false,
  953. },
  954. {
  955. name: "device mountable PV",
  956. driverName: "device-mountable-pv",
  957. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-vol", 20, "device-mountable-pv", testVol), true),
  958. canDeviceMount: true,
  959. },
  960. {
  961. name: "incomplete spec",
  962. driverName: "device-unmountable",
  963. spec: &volume.Spec{ReadOnly: true},
  964. canDeviceMount: false,
  965. shouldFail: true,
  966. },
  967. {
  968. name: "missing spec",
  969. driverName: "device-unmountable",
  970. canDeviceMount: false,
  971. shouldFail: true,
  972. },
  973. }
  974. for _, test := range tests {
  975. t.Run(test.name, func(t *testing.T) {
  976. plug, tmpDir := newTestPlugin(t, nil)
  977. defer os.RemoveAll(tmpDir)
  978. pluginCanDeviceMount, err := plug.CanDeviceMount(test.spec)
  979. if err != nil && !test.shouldFail {
  980. t.Fatalf("unexpected error in plug.CanDeviceMount: %s", err)
  981. }
  982. if pluginCanDeviceMount != test.canDeviceMount {
  983. t.Fatalf("expecting plugin.CanAttach %t got %t", test.canDeviceMount, pluginCanDeviceMount)
  984. }
  985. })
  986. }
  987. }
  988. func TestPluginFindDeviceMountablePluginBySpec(t *testing.T) {
  989. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)()
  990. tests := []struct {
  991. name string
  992. driverName string
  993. spec *volume.Spec
  994. canDeviceMount bool
  995. shouldFail bool
  996. }{
  997. {
  998. name: "non device mountable inline",
  999. driverName: "inline-driver",
  1000. spec: volume.NewSpecFromVolume(makeTestVol("test-vol", "inline-driver")),
  1001. canDeviceMount: false,
  1002. },
  1003. {
  1004. name: "device mountable PV",
  1005. driverName: "device-mountable-pv",
  1006. spec: volume.NewSpecFromPersistentVolume(makeTestPV("test-vol", 20, "device-mountable-pv", testVol), true),
  1007. canDeviceMount: true,
  1008. },
  1009. {
  1010. name: "incomplete spec",
  1011. driverName: "device-unmountable",
  1012. spec: &volume.Spec{ReadOnly: true},
  1013. canDeviceMount: false,
  1014. shouldFail: true,
  1015. },
  1016. {
  1017. name: "missing spec",
  1018. driverName: "device-unmountable",
  1019. canDeviceMount: false,
  1020. shouldFail: true,
  1021. },
  1022. }
  1023. for _, test := range tests {
  1024. t.Run(test.name, func(t *testing.T) {
  1025. tmpDir, err := utiltesting.MkTmpdir("csi-test")
  1026. if err != nil {
  1027. t.Fatalf("can't create temp dir: %v", err)
  1028. }
  1029. defer os.RemoveAll(tmpDir)
  1030. client := fakeclient.NewSimpleClientset(
  1031. &v1.Node{
  1032. ObjectMeta: metav1.ObjectMeta{
  1033. Name: "fakeNode",
  1034. },
  1035. Spec: v1.NodeSpec{},
  1036. },
  1037. )
  1038. host := volumetest.NewFakeVolumeHostWithCSINodeName(t, tmpDir, client, ProbeVolumePlugins(), "fakeNode", nil)
  1039. plugMgr := host.GetPluginMgr()
  1040. plug, err := plugMgr.FindDeviceMountablePluginBySpec(test.spec)
  1041. if err != nil && !test.shouldFail {
  1042. t.Fatalf("unexpected error in plugMgr.FindDeviceMountablePluginBySpec: %s", err)
  1043. }
  1044. if (plug != nil) != test.canDeviceMount {
  1045. t.Fatalf("expecting deviceMountablePlugin, but got nil")
  1046. }
  1047. })
  1048. }
  1049. }
  1050. func TestPluginNewBlockMapper(t *testing.T) {
  1051. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  1052. plug, tmpDir := newTestPlugin(t, nil)
  1053. defer os.RemoveAll(tmpDir)
  1054. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  1055. pv := makeTestPV("test-block-pv", 10, testDriver, testVol)
  1056. mounter, err := plug.NewBlockVolumeMapper(
  1057. volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly),
  1058. &api.Pod{ObjectMeta: meta.ObjectMeta{UID: testPodUID, Namespace: testns}},
  1059. volume.VolumeOptions{},
  1060. )
  1061. if err != nil {
  1062. t.Fatalf("Failed to make a new BlockMapper: %v", err)
  1063. }
  1064. if mounter == nil {
  1065. t.Fatal("failed to create CSI BlockMapper, mapper is nill")
  1066. }
  1067. csiMapper := mounter.(*csiBlockMapper)
  1068. // validate mounter fields
  1069. if string(csiMapper.driverName) != testDriver {
  1070. t.Error("CSI block mapper missing driver name")
  1071. }
  1072. if csiMapper.volumeID != testVol {
  1073. t.Error("CSI block mapper missing volumeID")
  1074. }
  1075. if csiMapper.podUID == types.UID("") {
  1076. t.Error("CSI block mapper missing pod.UID")
  1077. }
  1078. csiClient, err := csiMapper.csiClientGetter.Get()
  1079. if csiClient == nil {
  1080. t.Error("mapper csiClient is nil")
  1081. }
  1082. // ensure data file is created
  1083. dataFile := getVolumeDeviceDataDir(csiMapper.spec.Name(), plug.host)
  1084. if _, err := os.Stat(dataFile); err != nil {
  1085. if os.IsNotExist(err) {
  1086. t.Errorf("data file not created %s", dataFile)
  1087. } else {
  1088. t.Fatal(err)
  1089. }
  1090. }
  1091. }
  1092. func TestPluginNewUnmapper(t *testing.T) {
  1093. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  1094. plug, tmpDir := newTestPlugin(t, nil)
  1095. defer os.RemoveAll(tmpDir)
  1096. registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
  1097. pv := makeTestPV("test-pv", 10, testDriver, testVol)
  1098. // save the data file to re-create client
  1099. dir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
  1100. if err := os.MkdirAll(dir, 0755); err != nil && !os.IsNotExist(err) {
  1101. t.Errorf("failed to create dir [%s]: %v", dir, err)
  1102. }
  1103. if err := saveVolumeData(
  1104. dir,
  1105. volDataFileName,
  1106. map[string]string{
  1107. volDataKey.specVolID: pv.ObjectMeta.Name,
  1108. volDataKey.driverName: testDriver,
  1109. volDataKey.volHandle: testVol,
  1110. },
  1111. ); err != nil {
  1112. t.Fatalf("failed to save volume data: %v", err)
  1113. }
  1114. // test unmounter
  1115. unmapper, err := plug.NewBlockVolumeUnmapper(pv.ObjectMeta.Name, testPodUID)
  1116. csiUnmapper := unmapper.(*csiBlockMapper)
  1117. if err != nil {
  1118. t.Fatalf("Failed to make a new Unmounter: %v", err)
  1119. }
  1120. if csiUnmapper == nil {
  1121. t.Fatal("failed to create CSI Unmounter")
  1122. }
  1123. if csiUnmapper.podUID != testPodUID {
  1124. t.Error("podUID not set")
  1125. }
  1126. if csiUnmapper.specName != pv.ObjectMeta.Name {
  1127. t.Error("specName not set")
  1128. }
  1129. csiClient, err := csiUnmapper.csiClientGetter.Get()
  1130. if csiClient == nil {
  1131. t.Error("unmapper csiClient is nil")
  1132. }
  1133. // test loaded vol data
  1134. if string(csiUnmapper.driverName) != testDriver {
  1135. t.Error("unmapper driverName not set")
  1136. }
  1137. if csiUnmapper.volumeID != testVol {
  1138. t.Error("unmapper volumeHandle not set")
  1139. }
  1140. }
  1141. func TestPluginConstructBlockVolumeSpec(t *testing.T) {
  1142. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
  1143. plug, tmpDir := newTestPlugin(t, nil)
  1144. defer os.RemoveAll(tmpDir)
  1145. testCases := []struct {
  1146. name string
  1147. specVolID string
  1148. data map[string]string
  1149. shouldFail bool
  1150. }{
  1151. {
  1152. name: "valid spec name",
  1153. specVolID: "test.vol.id",
  1154. data: map[string]string{volDataKey.specVolID: "test.vol.id", volDataKey.volHandle: "test-vol0", volDataKey.driverName: "test-driver0"},
  1155. },
  1156. }
  1157. for _, tc := range testCases {
  1158. t.Logf("test case: %s", tc.name)
  1159. deviceDataDir := getVolumeDeviceDataDir(tc.specVolID, plug.host)
  1160. // create data file in csi plugin dir
  1161. if tc.data != nil {
  1162. if err := os.MkdirAll(deviceDataDir, 0755); err != nil && !os.IsNotExist(err) {
  1163. t.Errorf("failed to create dir [%s]: %v", deviceDataDir, err)
  1164. }
  1165. if err := saveVolumeData(deviceDataDir, volDataFileName, tc.data); err != nil {
  1166. t.Fatal(err)
  1167. }
  1168. }
  1169. // rebuild spec
  1170. spec, err := plug.ConstructBlockVolumeSpec("test-podUID", tc.specVolID, getVolumeDevicePluginDir(tc.specVolID, plug.host))
  1171. if tc.shouldFail {
  1172. if err == nil {
  1173. t.Fatal("expecting ConstructVolumeSpec to fail, but got nil error")
  1174. }
  1175. continue
  1176. }
  1177. if spec.PersistentVolume.Spec.VolumeMode == nil {
  1178. t.Fatalf("Volume mode has not been set.")
  1179. }
  1180. if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeBlock {
  1181. t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode)
  1182. }
  1183. volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle
  1184. if volHandle != tc.data[volDataKey.volHandle] {
  1185. t.Errorf("expected volID %s, got volID %s", tc.data[volDataKey.volHandle], volHandle)
  1186. }
  1187. if spec.Name() != tc.specVolID {
  1188. t.Errorf("Unexpected spec name %s", spec.Name())
  1189. }
  1190. }
  1191. }
  1192. func TestValidatePlugin(t *testing.T) {
  1193. testCases := []struct {
  1194. pluginName string
  1195. endpoint string
  1196. versions []string
  1197. shouldFail bool
  1198. }{
  1199. {
  1200. pluginName: "test.plugin",
  1201. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1202. versions: []string{"v1.0.0"},
  1203. shouldFail: false,
  1204. },
  1205. {
  1206. pluginName: "test.plugin",
  1207. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1208. versions: []string{"0.3.0"},
  1209. shouldFail: true,
  1210. },
  1211. {
  1212. pluginName: "test.plugin",
  1213. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1214. versions: []string{"0.2.0"},
  1215. shouldFail: true,
  1216. },
  1217. {
  1218. pluginName: "test.plugin",
  1219. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1220. versions: []string{"0.2.0", "v0.3.0"},
  1221. shouldFail: true,
  1222. },
  1223. {
  1224. pluginName: "test.plugin",
  1225. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1226. versions: []string{"0.2.0", "v1.0.0"},
  1227. shouldFail: false,
  1228. },
  1229. {
  1230. pluginName: "test.plugin",
  1231. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1232. versions: []string{"0.2.0", "v1.2.3"},
  1233. shouldFail: false,
  1234. },
  1235. {
  1236. pluginName: "test.plugin",
  1237. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1238. versions: []string{"v1.2.3", "v0.3.0"},
  1239. shouldFail: false,
  1240. },
  1241. {
  1242. pluginName: "test.plugin",
  1243. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1244. versions: []string{"v1.2.3", "v0.3.0", "2.0.1"},
  1245. shouldFail: false,
  1246. },
  1247. {
  1248. pluginName: "test.plugin",
  1249. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1250. versions: []string{"v1.2.3", "4.9.12", "v0.3.0", "2.0.1"},
  1251. shouldFail: false,
  1252. },
  1253. {
  1254. pluginName: "test.plugin",
  1255. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1256. versions: []string{"v1.2.3", "boo", "v0.3.0", "2.0.1"},
  1257. shouldFail: false,
  1258. },
  1259. {
  1260. pluginName: "test.plugin",
  1261. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1262. versions: []string{"4.9.12", "2.0.1"},
  1263. shouldFail: true,
  1264. },
  1265. {
  1266. pluginName: "test.plugin",
  1267. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1268. versions: []string{},
  1269. shouldFail: true,
  1270. },
  1271. {
  1272. pluginName: "test.plugin",
  1273. endpoint: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1274. versions: []string{"var", "boo", "foo"},
  1275. shouldFail: true,
  1276. },
  1277. }
  1278. for _, tc := range testCases {
  1279. // Arrange & Act
  1280. err := PluginHandler.ValidatePlugin(tc.pluginName, tc.endpoint, tc.versions)
  1281. // Assert
  1282. if tc.shouldFail && err == nil {
  1283. t.Fatalf("expecting ValidatePlugin to fail, but got nil error for testcase: %#v", tc)
  1284. }
  1285. if !tc.shouldFail && err != nil {
  1286. t.Fatalf("unexpected error during ValidatePlugin for testcase: %#v\r\n err:%v", tc, err)
  1287. }
  1288. }
  1289. }
  1290. func TestValidatePluginExistingDriver(t *testing.T) {
  1291. testCases := []struct {
  1292. pluginName1 string
  1293. endpoint1 string
  1294. versions1 []string
  1295. pluginName2 string
  1296. endpoint2 string
  1297. versions2 []string
  1298. shouldFail bool
  1299. }{
  1300. {
  1301. pluginName1: "test.plugin",
  1302. endpoint1: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1303. versions1: []string{"v1.0.0"},
  1304. pluginName2: "test.plugin2",
  1305. endpoint2: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1306. versions2: []string{"v1.0.0"},
  1307. shouldFail: false,
  1308. },
  1309. {
  1310. pluginName1: "test.plugin",
  1311. endpoint1: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1312. versions1: []string{"v1.0.0"},
  1313. pluginName2: "test.plugin",
  1314. endpoint2: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1315. versions2: []string{"v1.0.0"},
  1316. shouldFail: true,
  1317. },
  1318. {
  1319. pluginName1: "test.plugin",
  1320. endpoint1: "/var/log/kubelet/plugins/myplugin/csi.sock",
  1321. versions1: []string{"v0.3.0", "v0.2.0", "v1.0.0"},
  1322. pluginName2: "test.plugin",
  1323. endpoint2: "/var/log/kubelet/plugins_registry/myplugin/csi.sock",
  1324. versions2: []string{"v1.0.1"},
  1325. shouldFail: false,
  1326. },
  1327. }
  1328. for _, tc := range testCases {
  1329. // Arrange & Act
  1330. highestSupportedVersions1, err := highestSupportedVersion(tc.versions1)
  1331. if err != nil {
  1332. t.Fatalf("unexpected error parsing version for testcase: %#v: %v", tc, err)
  1333. }
  1334. csiDrivers.Clear()
  1335. csiDrivers.Set(tc.pluginName1, Driver{
  1336. endpoint: tc.endpoint1,
  1337. highestSupportedVersion: highestSupportedVersions1,
  1338. })
  1339. // Arrange & Act
  1340. err = PluginHandler.ValidatePlugin(tc.pluginName2, tc.endpoint2, tc.versions2)
  1341. // Assert
  1342. if tc.shouldFail && err == nil {
  1343. t.Fatalf("expecting ValidatePlugin to fail, but got nil error for testcase: %#v", tc)
  1344. }
  1345. if !tc.shouldFail && err != nil {
  1346. t.Fatalf("unexpected error during ValidatePlugin for testcase: %#v\r\n err:%v", tc, err)
  1347. }
  1348. }
  1349. }
  1350. func TestHighestSupportedVersion(t *testing.T) {
  1351. testCases := []struct {
  1352. versions []string
  1353. expectedHighestSupportedVersion string
  1354. shouldFail bool
  1355. }{
  1356. {
  1357. versions: []string{"v1.0.0"},
  1358. expectedHighestSupportedVersion: "1.0.0",
  1359. shouldFail: false,
  1360. },
  1361. {
  1362. versions: []string{"0.3.0"},
  1363. shouldFail: true,
  1364. },
  1365. {
  1366. versions: []string{"0.2.0"},
  1367. shouldFail: true,
  1368. },
  1369. {
  1370. versions: []string{"1.0.0"},
  1371. expectedHighestSupportedVersion: "1.0.0",
  1372. shouldFail: false,
  1373. },
  1374. {
  1375. versions: []string{"v0.3.0"},
  1376. shouldFail: true,
  1377. },
  1378. {
  1379. versions: []string{"0.2.0"},
  1380. shouldFail: true,
  1381. },
  1382. {
  1383. versions: []string{"0.2.0", "v0.3.0"},
  1384. shouldFail: true,
  1385. },
  1386. {
  1387. versions: []string{"0.2.0", "v1.0.0"},
  1388. expectedHighestSupportedVersion: "1.0.0",
  1389. shouldFail: false,
  1390. },
  1391. {
  1392. versions: []string{"0.2.0", "v1.2.3"},
  1393. expectedHighestSupportedVersion: "1.2.3",
  1394. shouldFail: false,
  1395. },
  1396. {
  1397. versions: []string{"v1.2.3", "v0.3.0"},
  1398. expectedHighestSupportedVersion: "1.2.3",
  1399. shouldFail: false,
  1400. },
  1401. {
  1402. versions: []string{"v1.2.3", "v0.3.0", "2.0.1"},
  1403. expectedHighestSupportedVersion: "1.2.3",
  1404. shouldFail: false,
  1405. },
  1406. {
  1407. versions: []string{"v1.2.3", "4.9.12", "v0.3.0", "2.0.1"},
  1408. expectedHighestSupportedVersion: "1.2.3",
  1409. shouldFail: false,
  1410. },
  1411. {
  1412. versions: []string{"4.9.12", "2.0.1"},
  1413. expectedHighestSupportedVersion: "",
  1414. shouldFail: true,
  1415. },
  1416. {
  1417. versions: []string{"v1.2.3", "boo", "v0.3.0", "2.0.1"},
  1418. expectedHighestSupportedVersion: "1.2.3",
  1419. shouldFail: false,
  1420. },
  1421. {
  1422. versions: []string{},
  1423. expectedHighestSupportedVersion: "",
  1424. shouldFail: true,
  1425. },
  1426. {
  1427. versions: []string{"var", "boo", "foo"},
  1428. expectedHighestSupportedVersion: "",
  1429. shouldFail: true,
  1430. },
  1431. }
  1432. for _, tc := range testCases {
  1433. // Arrange & Act
  1434. actual, err := highestSupportedVersion(tc.versions)
  1435. // Assert
  1436. if tc.shouldFail && err == nil {
  1437. t.Fatalf("expecting highestSupportedVersion to fail, but got nil error for testcase: %#v", tc)
  1438. }
  1439. if !tc.shouldFail && err != nil {
  1440. t.Fatalf("unexpected error during ValidatePlugin for testcase: %#v\r\n err:%v", tc, err)
  1441. }
  1442. if tc.expectedHighestSupportedVersion != "" {
  1443. result, err := actual.Compare(tc.expectedHighestSupportedVersion)
  1444. if err != nil {
  1445. t.Fatalf("comparison failed with %v for testcase %#v", err, tc)
  1446. }
  1447. if result != 0 {
  1448. t.Fatalf("expectedHighestSupportedVersion %v, but got %v for tc: %#v", tc.expectedHighestSupportedVersion, actual, tc)
  1449. }
  1450. }
  1451. }
  1452. }