delete_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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/api/core/v1"
  18. storage "k8s.io/api/storage/v1"
  19. pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
  20. pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
  21. )
  22. // Test single call to syncVolume, expecting recycling to happen.
  23. // 1. Fill in the controller with initial data
  24. // 2. Call the syncVolume *once*.
  25. // 3. Compare resulting volumes with expected volumes.
  26. func TestDeleteSync(t *testing.T) {
  27. tests := []controllerTest{
  28. {
  29. // delete volume bound by controller
  30. "8-1 - successful delete",
  31. newVolumeArray("volume8-1", "1Gi", "uid8-1", "claim8-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnBoundByController),
  32. novolumes,
  33. noclaims,
  34. noclaims,
  35. noevents, noerrors,
  36. // Inject deleter into the controller and call syncVolume. The
  37. // deleter simulates one delete() call that succeeds.
  38. wrapTestWithReclaimCalls(operationDelete, []error{nil}, testSyncVolume),
  39. },
  40. {
  41. // delete volume bound by user
  42. "8-2 - successful delete with prebound volume",
  43. newVolumeArray("volume8-2", "1Gi", "uid8-2", "claim8-2", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  44. novolumes,
  45. noclaims,
  46. noclaims,
  47. noevents, noerrors,
  48. // Inject deleter into the controller and call syncVolume. The
  49. // deleter simulates one delete() call that succeeds.
  50. wrapTestWithReclaimCalls(operationDelete, []error{nil}, testSyncVolume),
  51. },
  52. {
  53. // delete failure - plugin not found
  54. "8-3 - plugin not found",
  55. newVolumeArray("volume8-3", "1Gi", "uid8-3", "claim8-3", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  56. withMessage("Error getting deleter volume plugin for volume \"volume8-3\": no volume plugin matched", newVolumeArray("volume8-3", "1Gi", "uid8-3", "claim8-3", v1.VolumeFailed, v1.PersistentVolumeReclaimDelete, classEmpty)),
  57. noclaims,
  58. noclaims,
  59. []string{"Warning VolumeFailedDelete"}, noerrors, testSyncVolume,
  60. },
  61. {
  62. // delete failure - newDeleter returns error
  63. "8-4 - newDeleter returns error",
  64. newVolumeArray("volume8-4", "1Gi", "uid8-4", "claim8-4", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  65. withMessage("Failed to create deleter for volume \"volume8-4\": Mock plugin error: no deleteCalls configured", newVolumeArray("volume8-4", "1Gi", "uid8-4", "claim8-4", v1.VolumeFailed, v1.PersistentVolumeReclaimDelete, classEmpty)),
  66. noclaims,
  67. noclaims,
  68. []string{"Warning VolumeFailedDelete"}, noerrors,
  69. wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume),
  70. },
  71. {
  72. // delete failure - delete() returns error
  73. "8-5 - delete returns error",
  74. newVolumeArray("volume8-5", "1Gi", "uid8-5", "claim8-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  75. withMessage("Mock delete error", newVolumeArray("volume8-5", "1Gi", "uid8-5", "claim8-5", v1.VolumeFailed, v1.PersistentVolumeReclaimDelete, classEmpty)),
  76. noclaims,
  77. noclaims,
  78. []string{"Warning VolumeFailedDelete"}, noerrors,
  79. wrapTestWithReclaimCalls(operationDelete, []error{errors.New("Mock delete error")}, testSyncVolume),
  80. },
  81. {
  82. // delete success(?) - volume is deleted before doDelete() starts
  83. "8-6 - volume is deleted before deleting",
  84. newVolumeArray("volume8-6", "1Gi", "uid8-6", "claim8-6", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  85. novolumes,
  86. noclaims,
  87. noclaims,
  88. noevents, noerrors,
  89. wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
  90. // Delete the volume before delete operation starts
  91. reactor.DeleteVolume("volume8-6")
  92. }),
  93. },
  94. {
  95. // delete success(?) - volume is bound just at the time doDelete()
  96. // starts. This simulates "volume no longer needs recycling,
  97. // skipping".
  98. "8-7 - volume is bound before deleting",
  99. newVolumeArray("volume8-7", "1Gi", "uid8-7", "claim8-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnBoundByController),
  100. newVolumeArray("volume8-7", "1Gi", "uid8-7", "claim8-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnBoundByController),
  101. noclaims,
  102. newClaimArray("claim8-7", "uid8-7", "10Gi", "volume8-7", v1.ClaimBound, nil),
  103. noevents, noerrors,
  104. wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
  105. // Bind the volume to resurrected claim (this should never
  106. // happen)
  107. claim := newClaim("claim8-7", "uid8-7", "10Gi", "volume8-7", v1.ClaimBound, nil)
  108. reactor.AddClaimBoundToVolume(claim)
  109. ctrl.claims.Add(claim)
  110. }),
  111. },
  112. {
  113. // delete success - volume bound by user is deleted, while a new
  114. // claim is created with another UID.
  115. "8-9 - prebound volume is deleted while the claim exists",
  116. newVolumeArray("volume8-9", "1Gi", "uid8-9", "claim8-9", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  117. novolumes,
  118. newClaimArray("claim8-9", "uid8-9-x", "10Gi", "", v1.ClaimPending, nil),
  119. newClaimArray("claim8-9", "uid8-9-x", "10Gi", "", v1.ClaimPending, nil),
  120. noevents, noerrors,
  121. // Inject deleter into the controller and call syncVolume. The
  122. // deleter simulates one delete() call that succeeds.
  123. wrapTestWithReclaimCalls(operationDelete, []error{nil}, testSyncVolume),
  124. },
  125. {
  126. // PV requires external deleter
  127. "8-10 - external deleter",
  128. newVolumeArray("volume8-10", "1Gi", "uid10-1", "claim10-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnBoundByController),
  129. newVolumeArray("volume8-10", "1Gi", "uid10-1", "claim10-1", v1.VolumeReleased, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnBoundByController),
  130. noclaims,
  131. noclaims,
  132. noevents, noerrors,
  133. func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
  134. // Inject external deleter annotation
  135. test.initialVolumes[0].Annotations[pvutil.AnnDynamicallyProvisioned] = "external.io/test"
  136. test.expectedVolumes[0].Annotations[pvutil.AnnDynamicallyProvisioned] = "external.io/test"
  137. return testSyncVolume(ctrl, reactor, test)
  138. },
  139. },
  140. {
  141. // delete success - two PVs are provisioned for a single claim.
  142. // One of the PVs is deleted.
  143. "8-11 - two PVs provisioned for a single claim",
  144. []*v1.PersistentVolume{
  145. newVolume("volume8-11-1", "1Gi", "uid8-11", "claim8-11", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  146. newVolume("volume8-11-2", "1Gi", "uid8-11", "claim8-11", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  147. },
  148. []*v1.PersistentVolume{
  149. newVolume("volume8-11-2", "1Gi", "uid8-11", "claim8-11", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  150. },
  151. // the claim is bound to volume8-11-2 -> volume8-11-1 has lost the race and will be deleted
  152. newClaimArray("claim8-11", "uid8-11", "10Gi", "volume8-11-2", v1.ClaimBound, nil),
  153. newClaimArray("claim8-11", "uid8-11", "10Gi", "volume8-11-2", v1.ClaimBound, nil),
  154. noevents, noerrors,
  155. // Inject deleter into the controller and call syncVolume. The
  156. // deleter simulates one delete() call that succeeds.
  157. wrapTestWithReclaimCalls(operationDelete, []error{nil}, testSyncVolume),
  158. },
  159. {
  160. // delete success - two PVs are externally provisioned for a single
  161. // claim. One of the PVs is marked as Released to be deleted by the
  162. // external provisioner.
  163. "8-12 - two PVs externally provisioned for a single claim",
  164. []*v1.PersistentVolume{
  165. newVolume("volume8-12-1", "1Gi", "uid8-12", "claim8-12", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  166. newVolume("volume8-12-2", "1Gi", "uid8-12", "claim8-12", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  167. },
  168. []*v1.PersistentVolume{
  169. newVolume("volume8-12-1", "1Gi", "uid8-12", "claim8-12", v1.VolumeReleased, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  170. newVolume("volume8-12-2", "1Gi", "uid8-12", "claim8-12", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty, pvutil.AnnDynamicallyProvisioned),
  171. },
  172. // the claim is bound to volume8-12-2 -> volume8-12-1 has lost the race and will be "Released"
  173. newClaimArray("claim8-12", "uid8-12", "10Gi", "volume8-12-2", v1.ClaimBound, nil),
  174. newClaimArray("claim8-12", "uid8-12", "10Gi", "volume8-12-2", v1.ClaimBound, nil),
  175. noevents, noerrors,
  176. func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
  177. // Inject external deleter annotation
  178. test.initialVolumes[0].Annotations[pvutil.AnnDynamicallyProvisioned] = "external.io/test"
  179. test.expectedVolumes[0].Annotations[pvutil.AnnDynamicallyProvisioned] = "external.io/test"
  180. return testSyncVolume(ctrl, reactor, test)
  181. },
  182. },
  183. }
  184. runSyncTests(t, tests, []*storage.StorageClass{}, []*v1.Pod{})
  185. }
  186. // Test multiple calls to syncClaim/syncVolume and periodic sync of all
  187. // volume/claims. The test follows this pattern:
  188. // 0. Load the controller with initial data.
  189. // 1. Call controllerTest.testCall() once as in TestSync()
  190. // 2. For all volumes/claims changed by previous syncVolume/syncClaim calls,
  191. // call appropriate syncVolume/syncClaim (simulating "volume/claim changed"
  192. // events). Go to 2. if these calls change anything.
  193. // 3. When all changes are processed and no new changes were made, call
  194. // syncVolume/syncClaim on all volumes/claims (simulating "periodic sync").
  195. // 4. If some changes were done by step 3., go to 2. (simulation of
  196. // "volume/claim updated" events, eventually performing step 3. again)
  197. // 5. When 3. does not do any changes, finish the tests and compare final set
  198. // of volumes/claims with expected claims/volumes and report differences.
  199. // Some limit of calls in enforced to prevent endless loops.
  200. func TestDeleteMultiSync(t *testing.T) {
  201. tests := []controllerTest{
  202. {
  203. // delete failure - delete returns error. The controller should
  204. // try again.
  205. "9-1 - delete returns error",
  206. newVolumeArray("volume9-1", "1Gi", "uid9-1", "claim9-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
  207. novolumes,
  208. noclaims,
  209. noclaims,
  210. []string{"Warning VolumeFailedDelete"}, noerrors,
  211. wrapTestWithReclaimCalls(operationDelete, []error{errors.New("Mock delete error"), nil}, testSyncVolume),
  212. },
  213. }
  214. runMultisyncTests(t, tests, []*storage.StorageClass{}, "")
  215. }