recycle_test.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 persistentvolume
  14. import (
  15. "errors"
  16. "testing"
  17. "k8s.io/kubernetes/pkg/api"
  18. "k8s.io/kubernetes/pkg/apis/extensions"
  19. )
  20. // Test single call to syncVolume, expecting recycling to happen.
  21. // 1. Fill in the controller with initial data
  22. // 2. Call the syncVolume *once*.
  23. // 3. Compare resulting volumes with expected volumes.
  24. func TestRecycleSync(t *testing.T) {
  25. tests := []controllerTest{
  26. {
  27. // recycle volume bound by controller
  28. "6-1 - successful recycle",
  29. newVolumeArray("volume6-1", "1Gi", "uid6-1", "claim6-1", api.VolumeBound, api.PersistentVolumeReclaimRecycle, annBoundByController),
  30. newVolumeArray("volume6-1", "1Gi", "", "", api.VolumeAvailable, api.PersistentVolumeReclaimRecycle),
  31. noclaims,
  32. noclaims,
  33. noevents, noerrors,
  34. // Inject recycler into the controller and call syncVolume. The
  35. // recycler simulates one recycle() call that succeeds.
  36. wrapTestWithReclaimCalls(operationRecycle, []error{nil}, testSyncVolume),
  37. },
  38. {
  39. // recycle volume bound by user
  40. "6-2 - successful recycle with prebound volume",
  41. newVolumeArray("volume6-2", "1Gi", "uid6-2", "claim6-2", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  42. newVolumeArray("volume6-2", "1Gi", "", "claim6-2", api.VolumeAvailable, api.PersistentVolumeReclaimRecycle),
  43. noclaims,
  44. noclaims,
  45. noevents, noerrors,
  46. // Inject recycler into the controller and call syncVolume. The
  47. // recycler simulates one recycle() call that succeeds.
  48. wrapTestWithReclaimCalls(operationRecycle, []error{nil}, testSyncVolume),
  49. },
  50. {
  51. // recycle failure - plugin not found
  52. "6-3 - plugin not found",
  53. newVolumeArray("volume6-3", "1Gi", "uid6-3", "claim6-3", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  54. withMessage("No recycler plugin found for the volume!", newVolumeArray("volume6-3", "1Gi", "uid6-3", "claim6-3", api.VolumeFailed, api.PersistentVolumeReclaimRecycle)),
  55. noclaims,
  56. noclaims,
  57. []string{"Warning VolumeFailedRecycle"}, noerrors, testSyncVolume,
  58. },
  59. {
  60. // recycle failure - newRecycler returns error
  61. "6-4 - newRecycler returns error",
  62. newVolumeArray("volume6-4", "1Gi", "uid6-4", "claim6-4", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  63. withMessage("Failed to create recycler: Mock plugin error: no recycleCalls configured", newVolumeArray("volume6-4", "1Gi", "uid6-4", "claim6-4", api.VolumeFailed, api.PersistentVolumeReclaimRecycle)),
  64. noclaims,
  65. noclaims,
  66. []string{"Warning VolumeFailedRecycle"}, noerrors,
  67. wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume),
  68. },
  69. {
  70. // recycle failure - recycle returns error
  71. "6-5 - recycle returns error",
  72. newVolumeArray("volume6-5", "1Gi", "uid6-5", "claim6-5", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  73. withMessage("Recycler failed: Mock recycle error", newVolumeArray("volume6-5", "1Gi", "uid6-5", "claim6-5", api.VolumeFailed, api.PersistentVolumeReclaimRecycle)),
  74. noclaims,
  75. noclaims,
  76. []string{"Warning VolumeFailedRecycle"}, noerrors,
  77. wrapTestWithReclaimCalls(operationRecycle, []error{errors.New("Mock recycle error")}, testSyncVolume),
  78. },
  79. {
  80. // recycle success(?) - volume is deleted before doRecycle() starts
  81. "6-6 - volume is deleted before recycling",
  82. newVolumeArray("volume6-6", "1Gi", "uid6-6", "claim6-6", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  83. novolumes,
  84. noclaims,
  85. noclaims,
  86. noevents, noerrors,
  87. wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) {
  88. // Delete the volume before recycle operation starts
  89. reactor.lock.Lock()
  90. delete(reactor.volumes, "volume6-6")
  91. reactor.lock.Unlock()
  92. }),
  93. },
  94. {
  95. // recycle success(?) - volume is recycled by previous recycler just
  96. // at the time new doRecycle() starts. This simulates "volume no
  97. // longer needs recycling, skipping".
  98. "6-7 - volume is deleted before recycling",
  99. newVolumeArray("volume6-7", "1Gi", "uid6-7", "claim6-7", api.VolumeBound, api.PersistentVolumeReclaimRecycle, annBoundByController),
  100. newVolumeArray("volume6-7", "1Gi", "", "", api.VolumeAvailable, api.PersistentVolumeReclaimRecycle),
  101. noclaims,
  102. noclaims,
  103. noevents, noerrors,
  104. wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) {
  105. // Mark the volume as Available before the recycler starts
  106. reactor.lock.Lock()
  107. volume := reactor.volumes["volume6-7"]
  108. volume.Spec.ClaimRef = nil
  109. volume.Status.Phase = api.VolumeAvailable
  110. volume.Annotations = nil
  111. reactor.lock.Unlock()
  112. }),
  113. },
  114. {
  115. // recycle success(?) - volume bound by user is recycled by previous
  116. // recycler just at the time new doRecycle() starts. This simulates
  117. // "volume no longer needs recycling, skipping" with volume bound by
  118. // user.
  119. "6-8 - prebound volume is deleted before recycling",
  120. newVolumeArray("volume6-8", "1Gi", "uid6-8", "claim6-8", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  121. newVolumeArray("volume6-8", "1Gi", "", "claim6-8", api.VolumeAvailable, api.PersistentVolumeReclaimRecycle),
  122. noclaims,
  123. noclaims,
  124. noevents, noerrors,
  125. wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) {
  126. // Mark the volume as Available before the recycler starts
  127. reactor.lock.Lock()
  128. volume := reactor.volumes["volume6-8"]
  129. volume.Spec.ClaimRef.UID = ""
  130. volume.Status.Phase = api.VolumeAvailable
  131. reactor.lock.Unlock()
  132. }),
  133. },
  134. {
  135. // recycle success - volume bound by user is recycled, while a new
  136. // claim is created with another UID.
  137. "6-9 - prebound volume is recycled while the claim exists",
  138. newVolumeArray("volume6-9", "1Gi", "uid6-9", "claim6-9", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  139. newVolumeArray("volume6-9", "1Gi", "", "claim6-9", api.VolumeAvailable, api.PersistentVolumeReclaimRecycle),
  140. newClaimArray("claim6-9", "uid6-9-x", "10Gi", "", api.ClaimPending),
  141. newClaimArray("claim6-9", "uid6-9-x", "10Gi", "", api.ClaimPending),
  142. noevents, noerrors,
  143. // Inject recycler into the controller and call syncVolume. The
  144. // recycler simulates one recycle() call that succeeds.
  145. wrapTestWithReclaimCalls(operationRecycle, []error{nil}, testSyncVolume),
  146. },
  147. {
  148. // volume has unknown reclaim policy - failure expected
  149. "6-10 - unknown reclaim policy",
  150. newVolumeArray("volume6-10", "1Gi", "uid6-10", "claim6-10", api.VolumeBound, "Unknown"),
  151. withMessage("Volume has unrecognized PersistentVolumeReclaimPolicy", newVolumeArray("volume6-10", "1Gi", "uid6-10", "claim6-10", api.VolumeFailed, "Unknown")),
  152. noclaims,
  153. noclaims,
  154. []string{"Warning VolumeUnknownReclaimPolicy"}, noerrors, testSyncVolume,
  155. },
  156. }
  157. runSyncTests(t, tests, []*extensions.StorageClass{})
  158. }
  159. // Test multiple calls to syncClaim/syncVolume and periodic sync of all
  160. // volume/claims. The test follows this pattern:
  161. // 0. Load the controller with initial data.
  162. // 1. Call controllerTest.testCall() once as in TestSync()
  163. // 2. For all volumes/claims changed by previous syncVolume/syncClaim calls,
  164. // call appropriate syncVolume/syncClaim (simulating "volume/claim changed"
  165. // events). Go to 2. if these calls change anything.
  166. // 3. When all changes are processed and no new changes were made, call
  167. // syncVolume/syncClaim on all volumes/claims (simulating "periodic sync").
  168. // 4. If some changes were done by step 3., go to 2. (simulation of
  169. // "volume/claim updated" events, eventually performing step 3. again)
  170. // 5. When 3. does not do any changes, finish the tests and compare final set
  171. // of volumes/claims with expected claims/volumes and report differences.
  172. // Some limit of calls in enforced to prevent endless loops.
  173. func TestRecycleMultiSync(t *testing.T) {
  174. tests := []controllerTest{
  175. {
  176. // recycle failure - recycle returns error. The controller should
  177. // try again.
  178. "7-1 - recycle returns error",
  179. newVolumeArray("volume7-1", "1Gi", "uid7-1", "claim7-1", api.VolumeBound, api.PersistentVolumeReclaimRecycle),
  180. newVolumeArray("volume7-1", "1Gi", "", "claim7-1", api.VolumeAvailable, api.PersistentVolumeReclaimRecycle),
  181. noclaims,
  182. noclaims,
  183. []string{"Warning VolumeFailedRecycle"}, noerrors,
  184. wrapTestWithReclaimCalls(operationRecycle, []error{errors.New("Mock recycle error"), nil}, testSyncVolume),
  185. },
  186. }
  187. runMultisyncTests(t, tests, []*extensions.StorageClass{}, "")
  188. }