attacher_test.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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 awsebs
  15. import (
  16. "errors"
  17. "testing"
  18. "k8s.io/klog"
  19. v1 "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/api/resource"
  21. "k8s.io/apimachinery/pkg/types"
  22. "k8s.io/kubernetes/pkg/volume"
  23. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  24. "k8s.io/legacy-cloud-providers/aws"
  25. )
  26. func TestGetVolumeName_Volume(t *testing.T) {
  27. plugin := newPlugin(t)
  28. name := aws.KubernetesVolumeID("my-aws-volume")
  29. spec := createVolSpec(name, false)
  30. volumeName, err := plugin.GetVolumeName(spec)
  31. if err != nil {
  32. t.Errorf("GetVolumeName error: %v", err)
  33. }
  34. if volumeName != string(name) {
  35. t.Errorf("GetVolumeName error: expected %s, got %s", name, volumeName)
  36. }
  37. }
  38. func TestGetVolumeName_PersistentVolume(t *testing.T) {
  39. plugin := newPlugin(t)
  40. name := aws.KubernetesVolumeID("my-aws-pv")
  41. spec := createPVSpec(name, true)
  42. volumeName, err := plugin.GetVolumeName(spec)
  43. if err != nil {
  44. t.Errorf("GetVolumeName error: %v", err)
  45. }
  46. if volumeName != string(name) {
  47. t.Errorf("GetVolumeName error: expected %s, got %s", name, volumeName)
  48. }
  49. }
  50. // One testcase for TestAttachDetach table test below
  51. type testcase struct {
  52. name aws.KubernetesVolumeID
  53. // For fake AWS:
  54. attach attachCall
  55. detach detachCall
  56. t *testing.T
  57. // Actual test to run
  58. test func(test *testcase) (string, error)
  59. // Expected return of the test
  60. expectedDevice string
  61. expectedError error
  62. }
  63. func TestAttachDetach(t *testing.T) {
  64. diskName := aws.KubernetesVolumeID("disk")
  65. nodeName := types.NodeName("instance")
  66. spec := createVolSpec(diskName, false)
  67. attachError := errors.New("Fake attach error")
  68. detachError := errors.New("Fake detach error")
  69. tests := []testcase{
  70. // Successful Attach call
  71. {
  72. name: "Attach_Positive",
  73. attach: attachCall{diskName, nodeName, "/dev/sda", nil},
  74. test: func(testcase *testcase) (string, error) {
  75. attacher := newAttacher(testcase)
  76. return attacher.Attach(spec, nodeName)
  77. },
  78. expectedDevice: "/dev/sda",
  79. },
  80. // Attach call fails
  81. {
  82. name: "Attach_Negative",
  83. attach: attachCall{diskName, nodeName, "", attachError},
  84. test: func(testcase *testcase) (string, error) {
  85. attacher := newAttacher(testcase)
  86. return attacher.Attach(spec, nodeName)
  87. },
  88. expectedError: attachError,
  89. },
  90. // Detach succeeds
  91. {
  92. name: "Detach_Positive",
  93. detach: detachCall{diskName, nodeName, "/dev/sda", nil},
  94. test: func(testcase *testcase) (string, error) {
  95. detacher := newDetacher(testcase)
  96. mountPath := "/mnt/" + string(diskName)
  97. return "", detacher.Detach(mountPath, nodeName)
  98. },
  99. },
  100. // Detach fails
  101. {
  102. name: "Detach_Negative",
  103. detach: detachCall{diskName, nodeName, "", detachError},
  104. test: func(testcase *testcase) (string, error) {
  105. detacher := newDetacher(testcase)
  106. mountPath := "/mnt/" + string(diskName)
  107. return "", detacher.Detach(mountPath, nodeName)
  108. },
  109. expectedError: detachError,
  110. },
  111. }
  112. for _, testcase := range tests {
  113. testcase.t = t
  114. device, err := testcase.test(&testcase)
  115. if err != testcase.expectedError {
  116. t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedError.Error(), err.Error())
  117. }
  118. if device != testcase.expectedDevice {
  119. t.Errorf("%s failed: expected device=%q, got %q", testcase.name, testcase.expectedDevice, device)
  120. }
  121. t.Logf("Test %q succeeded", testcase.name)
  122. }
  123. }
  124. // newPlugin creates a new gcePersistentDiskPlugin with fake cloud, NewAttacher
  125. // and NewDetacher won't work.
  126. func newPlugin(t *testing.T) *awsElasticBlockStorePlugin {
  127. host := volumetest.NewFakeVolumeHost(t, "/tmp", nil, nil)
  128. plugins := ProbeVolumePlugins()
  129. plugin := plugins[0]
  130. plugin.Init(host)
  131. return plugin.(*awsElasticBlockStorePlugin)
  132. }
  133. func newAttacher(testcase *testcase) *awsElasticBlockStoreAttacher {
  134. return &awsElasticBlockStoreAttacher{
  135. host: nil,
  136. awsVolumes: testcase,
  137. }
  138. }
  139. func newDetacher(testcase *testcase) *awsElasticBlockStoreDetacher {
  140. return &awsElasticBlockStoreDetacher{
  141. awsVolumes: testcase,
  142. }
  143. }
  144. func createVolSpec(name aws.KubernetesVolumeID, readOnly bool) *volume.Spec {
  145. return &volume.Spec{
  146. Volume: &v1.Volume{
  147. VolumeSource: v1.VolumeSource{
  148. AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
  149. VolumeID: string(name),
  150. ReadOnly: readOnly,
  151. },
  152. },
  153. },
  154. }
  155. }
  156. func createPVSpec(name aws.KubernetesVolumeID, readOnly bool) *volume.Spec {
  157. return &volume.Spec{
  158. PersistentVolume: &v1.PersistentVolume{
  159. Spec: v1.PersistentVolumeSpec{
  160. PersistentVolumeSource: v1.PersistentVolumeSource{
  161. AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
  162. VolumeID: string(name),
  163. ReadOnly: readOnly,
  164. },
  165. },
  166. },
  167. },
  168. }
  169. }
  170. // Fake AWS implementation
  171. type attachCall struct {
  172. diskName aws.KubernetesVolumeID
  173. nodeName types.NodeName
  174. retDeviceName string
  175. ret error
  176. }
  177. type detachCall struct {
  178. diskName aws.KubernetesVolumeID
  179. nodeName types.NodeName
  180. retDeviceName string
  181. ret error
  182. }
  183. func (testcase *testcase) AttachDisk(diskName aws.KubernetesVolumeID, nodeName types.NodeName) (string, error) {
  184. expected := &testcase.attach
  185. if expected.diskName == "" && expected.nodeName == "" {
  186. // testcase.attach looks uninitialized, test did not expect to call
  187. // AttachDisk
  188. testcase.t.Errorf("Unexpected AttachDisk call!")
  189. return "", errors.New("unexpected AttachDisk call")
  190. }
  191. if expected.diskName != diskName {
  192. testcase.t.Errorf("Unexpected AttachDisk call: expected diskName %s, got %s", expected.diskName, diskName)
  193. return "", errors.New("Unexpected AttachDisk call: wrong diskName")
  194. }
  195. if expected.nodeName != nodeName {
  196. testcase.t.Errorf("Unexpected AttachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName)
  197. return "", errors.New("Unexpected AttachDisk call: wrong nodeName")
  198. }
  199. klog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", diskName, nodeName, expected.retDeviceName, expected.ret)
  200. return expected.retDeviceName, expected.ret
  201. }
  202. func (testcase *testcase) DetachDisk(diskName aws.KubernetesVolumeID, nodeName types.NodeName) (string, error) {
  203. expected := &testcase.detach
  204. if expected.diskName == "" && expected.nodeName == "" {
  205. // testcase.detach looks uninitialized, test did not expect to call
  206. // DetachDisk
  207. testcase.t.Errorf("Unexpected DetachDisk call!")
  208. return "", errors.New("unexpected DetachDisk call")
  209. }
  210. if expected.diskName != diskName {
  211. testcase.t.Errorf("Unexpected DetachDisk call: expected diskName %s, got %s", expected.diskName, diskName)
  212. return "", errors.New("Unexpected DetachDisk call: wrong diskName")
  213. }
  214. if expected.nodeName != nodeName {
  215. testcase.t.Errorf("Unexpected DetachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName)
  216. return "", errors.New("Unexpected DetachDisk call: wrong nodeName")
  217. }
  218. klog.V(4).Infof("DetachDisk call: %s, %s, returning %q, %v", diskName, nodeName, expected.retDeviceName, expected.ret)
  219. return expected.retDeviceName, expected.ret
  220. }
  221. func (testcase *testcase) DiskIsAttached(diskName aws.KubernetesVolumeID, nodeName types.NodeName) (bool, error) {
  222. // DetachDisk no longer relies on DiskIsAttached api call
  223. return false, nil
  224. }
  225. func (testcase *testcase) DisksAreAttached(nodeDisks map[types.NodeName][]aws.KubernetesVolumeID) (map[types.NodeName]map[aws.KubernetesVolumeID]bool, error) {
  226. return nil, errors.New("Not implemented")
  227. }
  228. func (testcase *testcase) CreateDisk(volumeOptions *aws.VolumeOptions) (volumeName aws.KubernetesVolumeID, err error) {
  229. return "", errors.New("Not implemented")
  230. }
  231. func (testcase *testcase) DeleteDisk(volumeName aws.KubernetesVolumeID) (bool, error) {
  232. return false, errors.New("Not implemented")
  233. }
  234. func (testcase *testcase) GetVolumeLabels(volumeName aws.KubernetesVolumeID) (map[string]string, error) {
  235. return map[string]string{}, errors.New("Not implemented")
  236. }
  237. func (testcase *testcase) GetDiskPath(volumeName aws.KubernetesVolumeID) (string, error) {
  238. return "", errors.New("Not implemented")
  239. }
  240. func (testcase *testcase) ResizeDisk(
  241. volumeName aws.KubernetesVolumeID,
  242. oldSize resource.Quantity,
  243. newSize resource.Quantity) (resource.Quantity, error) {
  244. return oldSize, errors.New("Not implemented")
  245. }