attacher_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. // +build !providerless
  2. /*
  3. Copyright 2016 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package cinder
  15. import (
  16. "context"
  17. "errors"
  18. "reflect"
  19. "testing"
  20. v1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/api/resource"
  22. cloudprovider "k8s.io/cloud-provider"
  23. "k8s.io/kubernetes/pkg/volume"
  24. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  25. "fmt"
  26. "sort"
  27. "k8s.io/apimachinery/pkg/types"
  28. "k8s.io/klog"
  29. )
  30. const (
  31. VolumeStatusPending = "pending"
  32. VolumeStatusDone = "done"
  33. )
  34. var attachStatus = "Attach"
  35. var detachStatus = "Detach"
  36. func TestGetDeviceName_Volume(t *testing.T) {
  37. plugin := newPlugin(t)
  38. name := "my-cinder-volume"
  39. spec := createVolSpec(name, false)
  40. deviceName, err := plugin.GetVolumeName(spec)
  41. if err != nil {
  42. t.Errorf("GetDeviceName error: %v", err)
  43. }
  44. if deviceName != name {
  45. t.Errorf("GetDeviceName error: expected %s, got %s", name, deviceName)
  46. }
  47. }
  48. func TestGetDeviceName_PersistentVolume(t *testing.T) {
  49. plugin := newPlugin(t)
  50. name := "my-cinder-pv"
  51. spec := createPVSpec(name, true)
  52. deviceName, err := plugin.GetVolumeName(spec)
  53. if err != nil {
  54. t.Errorf("GetDeviceName error: %v", err)
  55. }
  56. if deviceName != name {
  57. t.Errorf("GetDeviceName error: expected %s, got %s", name, deviceName)
  58. }
  59. }
  60. func TestGetDeviceMountPath(t *testing.T) {
  61. name := "cinder-volume-id"
  62. spec := createVolSpec(name, false)
  63. rootDir := "/var/lib/kubelet/"
  64. host := volumetest.NewFakeVolumeHost(t, rootDir, nil, nil)
  65. attacher := &cinderDiskAttacher{
  66. host: host,
  67. }
  68. //test the path
  69. path, err := attacher.GetDeviceMountPath(spec)
  70. if err != nil {
  71. t.Errorf("Get device mount path error")
  72. }
  73. expectedPath := rootDir + "plugins/kubernetes.io/cinder/mounts/" + name
  74. if path != expectedPath {
  75. t.Errorf("Device mount path error: expected %s, got %s ", expectedPath, path)
  76. }
  77. }
  78. // One testcase for TestAttachDetach table test below
  79. type testcase struct {
  80. name string
  81. // For fake GCE:
  82. attach attachCall
  83. detach detachCall
  84. operationPending operationPendingCall
  85. diskIsAttached diskIsAttachedCall
  86. disksAreAttached disksAreAttachedCall
  87. diskPath diskPathCall
  88. t *testing.T
  89. attachOrDetach *string
  90. instanceID string
  91. // Actual test to run
  92. test func(test *testcase) (string, error)
  93. // Expected return of the test
  94. expectedResult string
  95. expectedError error
  96. }
  97. func TestAttachDetach(t *testing.T) {
  98. volumeID := "disk"
  99. instanceID := "instance"
  100. pending := VolumeStatusPending
  101. done := VolumeStatusDone
  102. nodeName := types.NodeName("nodeName")
  103. readOnly := false
  104. spec := createVolSpec(volumeID, readOnly)
  105. attachError := errors.New("Fake attach error")
  106. detachError := errors.New("Fake detach error")
  107. diskCheckError := errors.New("Fake DiskIsAttached error")
  108. diskPathError := errors.New("Fake GetAttachmentDiskPath error")
  109. disksCheckError := errors.New("Fake DisksAreAttached error")
  110. operationFinishTimeout := errors.New("Fake waitOperationFinished error")
  111. tests := []testcase{
  112. // Successful Attach call
  113. {
  114. name: "Attach_Positive",
  115. instanceID: instanceID,
  116. operationPending: operationPendingCall{volumeID, false, done, nil},
  117. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil},
  118. attach: attachCall{instanceID, volumeID, "", nil},
  119. diskPath: diskPathCall{instanceID, volumeID, "/dev/sda", nil},
  120. test: func(testcase *testcase) (string, error) {
  121. attacher := newAttacher(testcase)
  122. return attacher.Attach(spec, nodeName)
  123. },
  124. expectedResult: "/dev/sda",
  125. },
  126. // Disk is already attached
  127. {
  128. name: "Attach_Positive_AlreadyAttached",
  129. instanceID: instanceID,
  130. operationPending: operationPendingCall{volumeID, false, done, nil},
  131. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, true, nil},
  132. diskPath: diskPathCall{instanceID, volumeID, "/dev/sda", nil},
  133. test: func(testcase *testcase) (string, error) {
  134. attacher := newAttacher(testcase)
  135. return attacher.Attach(spec, nodeName)
  136. },
  137. expectedResult: "/dev/sda",
  138. },
  139. // Disk is attaching
  140. {
  141. name: "Attach_is_attaching",
  142. instanceID: instanceID,
  143. operationPending: operationPendingCall{volumeID, true, pending, operationFinishTimeout},
  144. test: func(testcase *testcase) (string, error) {
  145. attacher := newAttacher(testcase)
  146. return attacher.Attach(spec, nodeName)
  147. },
  148. expectedError: operationFinishTimeout,
  149. },
  150. // Attach call fails
  151. {
  152. name: "Attach_Negative",
  153. instanceID: instanceID,
  154. operationPending: operationPendingCall{volumeID, false, done, nil},
  155. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError},
  156. attach: attachCall{instanceID, volumeID, "/dev/sda", attachError},
  157. test: func(testcase *testcase) (string, error) {
  158. attacher := newAttacher(testcase)
  159. return attacher.Attach(spec, nodeName)
  160. },
  161. expectedError: attachError,
  162. },
  163. // GetAttachmentDiskPath call fails
  164. {
  165. name: "Attach_Negative_DiskPatchFails",
  166. instanceID: instanceID,
  167. operationPending: operationPendingCall{volumeID, false, done, nil},
  168. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil},
  169. attach: attachCall{instanceID, volumeID, "", nil},
  170. diskPath: diskPathCall{instanceID, volumeID, "", diskPathError},
  171. test: func(testcase *testcase) (string, error) {
  172. attacher := newAttacher(testcase)
  173. return attacher.Attach(spec, nodeName)
  174. },
  175. expectedError: diskPathError,
  176. },
  177. // Successful VolumesAreAttached call, attached
  178. {
  179. name: "VolumesAreAttached_Positive",
  180. instanceID: instanceID,
  181. disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, map[string]bool{volumeID: true}, nil},
  182. test: func(testcase *testcase) (string, error) {
  183. attacher := newAttacher(testcase)
  184. attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName)
  185. return serializeAttachments(attachments), err
  186. },
  187. expectedResult: serializeAttachments(map[*volume.Spec]bool{spec: true}),
  188. },
  189. // Successful VolumesAreAttached call, not attached
  190. {
  191. name: "VolumesAreAttached_Negative",
  192. instanceID: instanceID,
  193. disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, map[string]bool{volumeID: false}, nil},
  194. test: func(testcase *testcase) (string, error) {
  195. attacher := newAttacher(testcase)
  196. attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName)
  197. return serializeAttachments(attachments), err
  198. },
  199. expectedResult: serializeAttachments(map[*volume.Spec]bool{spec: false}),
  200. },
  201. // Treat as attached when DisksAreAttached call fails
  202. {
  203. name: "VolumesAreAttached_CinderFailed",
  204. instanceID: instanceID,
  205. disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, nil, disksCheckError},
  206. test: func(testcase *testcase) (string, error) {
  207. attacher := newAttacher(testcase)
  208. attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName)
  209. return serializeAttachments(attachments), err
  210. },
  211. expectedResult: serializeAttachments(map[*volume.Spec]bool{spec: true}),
  212. expectedError: disksCheckError,
  213. },
  214. // Detach succeeds
  215. {
  216. name: "Detach_Positive",
  217. instanceID: instanceID,
  218. operationPending: operationPendingCall{volumeID, false, done, nil},
  219. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, true, nil},
  220. detach: detachCall{instanceID, volumeID, nil},
  221. test: func(testcase *testcase) (string, error) {
  222. detacher := newDetacher(testcase)
  223. return "", detacher.Detach(volumeID, nodeName)
  224. },
  225. },
  226. // Disk is already detached
  227. {
  228. name: "Detach_Positive_AlreadyDetached",
  229. instanceID: instanceID,
  230. operationPending: operationPendingCall{volumeID, false, done, nil},
  231. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil},
  232. test: func(testcase *testcase) (string, error) {
  233. detacher := newDetacher(testcase)
  234. return "", detacher.Detach(volumeID, nodeName)
  235. },
  236. },
  237. // Detach succeeds when DiskIsAttached fails
  238. {
  239. name: "Detach_Positive_CheckFails",
  240. instanceID: instanceID,
  241. operationPending: operationPendingCall{volumeID, false, done, nil},
  242. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError},
  243. detach: detachCall{instanceID, volumeID, nil},
  244. test: func(testcase *testcase) (string, error) {
  245. detacher := newDetacher(testcase)
  246. return "", detacher.Detach(volumeID, nodeName)
  247. },
  248. },
  249. // Detach fails
  250. {
  251. name: "Detach_Negative",
  252. instanceID: instanceID,
  253. operationPending: operationPendingCall{volumeID, false, done, nil},
  254. diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError},
  255. detach: detachCall{instanceID, volumeID, detachError},
  256. test: func(testcase *testcase) (string, error) {
  257. detacher := newDetacher(testcase)
  258. return "", detacher.Detach(volumeID, nodeName)
  259. },
  260. expectedError: detachError,
  261. },
  262. // // Disk is detaching
  263. {
  264. name: "Detach_Is_Detaching",
  265. instanceID: instanceID,
  266. operationPending: operationPendingCall{volumeID, true, pending, operationFinishTimeout},
  267. test: func(testcase *testcase) (string, error) {
  268. detacher := newDetacher(testcase)
  269. return "", detacher.Detach(volumeID, nodeName)
  270. },
  271. expectedError: operationFinishTimeout,
  272. },
  273. }
  274. for _, testcase := range tests {
  275. testcase.t = t
  276. attachOrDetach := ""
  277. testcase.attachOrDetach = &attachOrDetach
  278. result, err := testcase.test(&testcase)
  279. if err != testcase.expectedError {
  280. t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedError, err)
  281. }
  282. if result != testcase.expectedResult {
  283. t.Errorf("%s failed: expected result=%q, got %q", testcase.name, testcase.expectedResult, result)
  284. }
  285. }
  286. }
  287. type volumeAttachmentFlag struct {
  288. volumeID string
  289. attached bool
  290. }
  291. type volumeAttachmentFlags []volumeAttachmentFlag
  292. func (va volumeAttachmentFlags) Len() int {
  293. return len(va)
  294. }
  295. func (va volumeAttachmentFlags) Swap(i, j int) {
  296. va[i], va[j] = va[j], va[i]
  297. }
  298. func (va volumeAttachmentFlags) Less(i, j int) bool {
  299. if va[i].volumeID < va[j].volumeID {
  300. return true
  301. }
  302. if va[i].volumeID > va[j].volumeID {
  303. return false
  304. }
  305. return va[j].attached
  306. }
  307. func serializeAttachments(attachments map[*volume.Spec]bool) string {
  308. var attachmentFlags volumeAttachmentFlags
  309. for spec, attached := range attachments {
  310. attachmentFlags = append(attachmentFlags, volumeAttachmentFlag{spec.Name(), attached})
  311. }
  312. sort.Sort(attachmentFlags)
  313. return fmt.Sprint(attachmentFlags)
  314. }
  315. // newPlugin creates a new gcePersistentDiskPlugin with fake cloud, NewAttacher
  316. // and NewDetacher won't work.
  317. func newPlugin(t *testing.T) *cinderPlugin {
  318. host := volumetest.NewFakeVolumeHost(t, "/tmp", nil, nil)
  319. plugins := ProbeVolumePlugins()
  320. plugin := plugins[0]
  321. plugin.Init(host)
  322. return plugin.(*cinderPlugin)
  323. }
  324. func newAttacher(testcase *testcase) *cinderDiskAttacher {
  325. return &cinderDiskAttacher{
  326. host: nil,
  327. cinderProvider: testcase,
  328. }
  329. }
  330. func newDetacher(testcase *testcase) *cinderDiskDetacher {
  331. return &cinderDiskDetacher{
  332. cinderProvider: testcase,
  333. }
  334. }
  335. func createVolSpec(name string, readOnly bool) *volume.Spec {
  336. return &volume.Spec{
  337. Volume: &v1.Volume{
  338. Name: name,
  339. VolumeSource: v1.VolumeSource{
  340. Cinder: &v1.CinderVolumeSource{
  341. VolumeID: name,
  342. ReadOnly: readOnly,
  343. },
  344. },
  345. },
  346. }
  347. }
  348. func createPVSpec(name string, readOnly bool) *volume.Spec {
  349. return &volume.Spec{
  350. PersistentVolume: &v1.PersistentVolume{
  351. Spec: v1.PersistentVolumeSpec{
  352. PersistentVolumeSource: v1.PersistentVolumeSource{
  353. Cinder: &v1.CinderPersistentVolumeSource{
  354. VolumeID: name,
  355. ReadOnly: readOnly,
  356. },
  357. },
  358. },
  359. },
  360. }
  361. }
  362. // Fake GCE implementation
  363. type attachCall struct {
  364. instanceID string
  365. volumeID string
  366. retDeviceName string
  367. ret error
  368. }
  369. type detachCall struct {
  370. instanceID string
  371. devicePath string
  372. ret error
  373. }
  374. type operationPendingCall struct {
  375. diskName string
  376. pending bool
  377. volumeStatus string
  378. ret error
  379. }
  380. type diskIsAttachedCall struct {
  381. instanceID string
  382. nodeName types.NodeName
  383. volumeID string
  384. isAttached bool
  385. ret error
  386. }
  387. type diskPathCall struct {
  388. instanceID string
  389. volumeID string
  390. retPath string
  391. ret error
  392. }
  393. type disksAreAttachedCall struct {
  394. instanceID string
  395. nodeName types.NodeName
  396. volumeIDs []string
  397. areAttached map[string]bool
  398. ret error
  399. }
  400. func (testcase *testcase) AttachDisk(instanceID, volumeID string) (string, error) {
  401. expected := &testcase.attach
  402. if expected.volumeID == "" && expected.instanceID == "" {
  403. // testcase.attach looks uninitialized, test did not expect to call
  404. // AttachDisk
  405. testcase.t.Errorf("unexpected AttachDisk call")
  406. return "", errors.New("unexpected AttachDisk call")
  407. }
  408. if expected.volumeID != volumeID {
  409. testcase.t.Errorf("unexpected AttachDisk call: expected volumeID %s, got %s", expected.volumeID, volumeID)
  410. return "", errors.New("unexpected AttachDisk call: wrong volumeID")
  411. }
  412. if expected.instanceID != instanceID {
  413. testcase.t.Errorf("unexpected AttachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  414. return "", errors.New("unexpected AttachDisk call: wrong instanceID")
  415. }
  416. klog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", volumeID, instanceID, expected.retDeviceName, expected.ret)
  417. testcase.attachOrDetach = &attachStatus
  418. return expected.retDeviceName, expected.ret
  419. }
  420. func (testcase *testcase) DetachDisk(instanceID, volumeID string) error {
  421. expected := &testcase.detach
  422. if expected.devicePath == "" && expected.instanceID == "" {
  423. // testcase.detach looks uninitialized, test did not expect to call
  424. // DetachDisk
  425. testcase.t.Errorf("unexpected DetachDisk call")
  426. return errors.New("unexpected DetachDisk call")
  427. }
  428. if expected.devicePath != volumeID {
  429. testcase.t.Errorf("unexpected DetachDisk call: expected volumeID %s, got %s", expected.devicePath, volumeID)
  430. return errors.New("unexpected DetachDisk call: wrong volumeID")
  431. }
  432. if expected.instanceID != instanceID {
  433. testcase.t.Errorf("unexpected DetachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  434. return errors.New("unexpected DetachDisk call: wrong instanceID")
  435. }
  436. klog.V(4).Infof("DetachDisk call: %s, %s, returning %v", volumeID, instanceID, expected.ret)
  437. testcase.attachOrDetach = &detachStatus
  438. return expected.ret
  439. }
  440. func (testcase *testcase) OperationPending(diskName string) (bool, string, error) {
  441. expected := &testcase.operationPending
  442. if expected.volumeStatus == VolumeStatusPending {
  443. klog.V(4).Infof("OperationPending call: %s, returning %v, %v, %v", diskName, expected.pending, expected.volumeStatus, expected.ret)
  444. return true, expected.volumeStatus, expected.ret
  445. }
  446. klog.V(4).Infof("OperationPending call: %s, returning %v, %v, %v", diskName, expected.pending, expected.volumeStatus, expected.ret)
  447. return false, expected.volumeStatus, expected.ret
  448. }
  449. func (testcase *testcase) DiskIsAttached(instanceID, volumeID string) (bool, error) {
  450. expected := &testcase.diskIsAttached
  451. // If testcase call DetachDisk*, return false
  452. if *testcase.attachOrDetach == detachStatus {
  453. return false, nil
  454. }
  455. // If testcase call AttachDisk*, return true
  456. if *testcase.attachOrDetach == attachStatus {
  457. return true, nil
  458. }
  459. if expected.volumeID == "" && expected.instanceID == "" {
  460. // testcase.diskIsAttached looks uninitialized, test did not expect to
  461. // call DiskIsAttached
  462. testcase.t.Errorf("unexpected DiskIsAttached call")
  463. return false, errors.New("unexpected DiskIsAttached call")
  464. }
  465. if expected.volumeID != volumeID {
  466. testcase.t.Errorf("unexpected DiskIsAttached call: expected volumeID %s, got %s", expected.volumeID, volumeID)
  467. return false, errors.New("unexpected DiskIsAttached call: wrong volumeID")
  468. }
  469. if expected.instanceID != instanceID {
  470. testcase.t.Errorf("unexpected DiskIsAttached call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  471. return false, errors.New("unexpected DiskIsAttached call: wrong instanceID")
  472. }
  473. klog.V(4).Infof("DiskIsAttached call: %s, %s, returning %v, %v", volumeID, instanceID, expected.isAttached, expected.ret)
  474. return expected.isAttached, expected.ret
  475. }
  476. func (testcase *testcase) GetAttachmentDiskPath(instanceID, volumeID string) (string, error) {
  477. expected := &testcase.diskPath
  478. if expected.volumeID == "" && expected.instanceID == "" {
  479. // testcase.diskPath looks uninitialized, test did not expect to
  480. // call GetAttachmentDiskPath
  481. testcase.t.Errorf("unexpected GetAttachmentDiskPath call")
  482. return "", errors.New("unexpected GetAttachmentDiskPath call")
  483. }
  484. if expected.volumeID != volumeID {
  485. testcase.t.Errorf("unexpected GetAttachmentDiskPath call: expected volumeID %s, got %s", expected.volumeID, volumeID)
  486. return "", errors.New("unexpected GetAttachmentDiskPath call: wrong volumeID")
  487. }
  488. if expected.instanceID != instanceID {
  489. testcase.t.Errorf("unexpected GetAttachmentDiskPath call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  490. return "", errors.New("unexpected GetAttachmentDiskPath call: wrong instanceID")
  491. }
  492. klog.V(4).Infof("GetAttachmentDiskPath call: %s, %s, returning %v, %v", volumeID, instanceID, expected.retPath, expected.ret)
  493. return expected.retPath, expected.ret
  494. }
  495. func (testcase *testcase) ShouldTrustDevicePath() bool {
  496. return true
  497. }
  498. func (testcase *testcase) DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error) {
  499. expected := &testcase.diskIsAttached
  500. instanceID := expected.instanceID
  501. // If testcase call DetachDisk*, return false
  502. if *testcase.attachOrDetach == detachStatus {
  503. return false, instanceID, nil
  504. }
  505. // If testcase call AttachDisk*, return true
  506. if *testcase.attachOrDetach == attachStatus {
  507. return true, instanceID, nil
  508. }
  509. if expected.nodeName != nodeName {
  510. testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected nodename %s, got %s", expected.nodeName, nodeName)
  511. return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong nodename")
  512. }
  513. if expected.volumeID == "" && expected.instanceID == "" {
  514. // testcase.diskIsAttached looks uninitialized, test did not expect to
  515. // call DiskIsAttached
  516. testcase.t.Errorf("unexpected DiskIsAttachedByName call")
  517. return false, instanceID, errors.New("unexpected DiskIsAttachedByName call")
  518. }
  519. if expected.volumeID != volumeID {
  520. testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected volumeID %s, got %s", expected.volumeID, volumeID)
  521. return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong volumeID")
  522. }
  523. if expected.instanceID != instanceID {
  524. testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  525. return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong instanceID")
  526. }
  527. klog.V(4).Infof("DiskIsAttachedByName call: %s, %s, returning %v, %v, %v", volumeID, nodeName, expected.isAttached, expected.instanceID, expected.ret)
  528. return expected.isAttached, expected.instanceID, expected.ret
  529. }
  530. func (testcase *testcase) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, string, bool, error) {
  531. return "", "", "", false, errors.New("Not implemented")
  532. }
  533. func (testcase *testcase) GetDevicePath(volumeID string) string {
  534. return ""
  535. }
  536. func (testcase *testcase) InstanceID() (string, error) {
  537. return testcase.instanceID, nil
  538. }
  539. func (testcase *testcase) ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
  540. return resource.Quantity{}, nil
  541. }
  542. func (testcase *testcase) DeleteVolume(volumeID string) error {
  543. return errors.New("Not implemented")
  544. }
  545. func (testcase *testcase) GetAutoLabelsForPD(name string) (map[string]string, error) {
  546. return map[string]string{}, errors.New("Not implemented")
  547. }
  548. func (testcase *testcase) Instances() (cloudprovider.Instances, bool) {
  549. return &instances{testcase.instanceID}, true
  550. }
  551. func (testcase *testcase) DisksAreAttached(instanceID string, volumeIDs []string) (map[string]bool, error) {
  552. expected := &testcase.disksAreAttached
  553. areAttached := make(map[string]bool)
  554. if len(expected.volumeIDs) == 0 && expected.instanceID == "" {
  555. // testcase.volumeIDs looks uninitialized, test did not expect to call DisksAreAttached
  556. testcase.t.Errorf("Unexpected DisksAreAttached call!")
  557. return areAttached, errors.New("Unexpected DisksAreAttached call")
  558. }
  559. if !reflect.DeepEqual(expected.volumeIDs, volumeIDs) {
  560. testcase.t.Errorf("Unexpected DisksAreAttached call: expected volumeIDs %v, got %v", expected.volumeIDs, volumeIDs)
  561. return areAttached, errors.New("Unexpected DisksAreAttached call: wrong volumeID")
  562. }
  563. if expected.instanceID != instanceID {
  564. testcase.t.Errorf("Unexpected DisksAreAttached call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  565. return areAttached, errors.New("Unexpected DisksAreAttached call: wrong instanceID")
  566. }
  567. klog.V(4).Infof("DisksAreAttached call: %v, %s, returning %v, %v", volumeIDs, instanceID, expected.areAttached, expected.ret)
  568. return expected.areAttached, expected.ret
  569. }
  570. func (testcase *testcase) DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error) {
  571. expected := &testcase.disksAreAttached
  572. areAttached := make(map[string]bool)
  573. instanceID := expected.instanceID
  574. if expected.nodeName != nodeName {
  575. testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected nodeName %s, got %s", expected.nodeName, nodeName)
  576. return areAttached, errors.New("Unexpected DisksAreAttachedByName call: wrong nodename")
  577. }
  578. if len(expected.volumeIDs) == 0 && expected.instanceID == "" {
  579. // testcase.volumeIDs looks uninitialized, test did not expect to call DisksAreAttached
  580. testcase.t.Errorf("Unexpected DisksAreAttachedByName call!")
  581. return areAttached, errors.New("Unexpected DisksAreAttachedByName call")
  582. }
  583. if !reflect.DeepEqual(expected.volumeIDs, volumeIDs) {
  584. testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected volumeIDs %v, got %v", expected.volumeIDs, volumeIDs)
  585. return areAttached, errors.New("Unexpected DisksAreAttachedByName call: wrong volumeID")
  586. }
  587. if expected.instanceID != instanceID {
  588. testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected instanceID %s, got %s", expected.instanceID, instanceID)
  589. return areAttached, errors.New("Unexpected DisksAreAttachedByName call: wrong instanceID")
  590. }
  591. klog.V(4).Infof("DisksAreAttachedByName call: %v, %s, returning %v, %v", volumeIDs, nodeName, expected.areAttached, expected.ret)
  592. return expected.areAttached, expected.ret
  593. }
  594. // Implementation of fake cloudprovider.Instances
  595. type instances struct {
  596. instanceID string
  597. }
  598. func (instances *instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
  599. return []v1.NodeAddress{}, errors.New("Not implemented")
  600. }
  601. func (instances *instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
  602. return []v1.NodeAddress{}, errors.New("Not implemented")
  603. }
  604. func (instances *instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
  605. return instances.instanceID, nil
  606. }
  607. func (instances *instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
  608. return "", errors.New("Not implemented")
  609. }
  610. func (instances *instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
  611. return "", errors.New("Not implemented")
  612. }
  613. func (instances *instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
  614. return false, errors.New("unimplemented")
  615. }
  616. func (instances *instances) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) {
  617. return false, errors.New("unimplemented")
  618. }
  619. func (instances *instances) List(filter string) ([]types.NodeName, error) {
  620. return []types.NodeName{}, errors.New("Not implemented")
  621. }
  622. func (instances *instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
  623. return cloudprovider.NotImplemented
  624. }
  625. func (instances *instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) {
  626. return "", errors.New("Not implemented")
  627. }