attacher_test.go 25 KB

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