scheduler_assume_cache_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. Copyright 2017 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 scheduling
  14. import (
  15. "fmt"
  16. "testing"
  17. "k8s.io/api/core/v1"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
  20. )
  21. func makePV(name, version, storageClass string) *v1.PersistentVolume {
  22. return &v1.PersistentVolume{
  23. ObjectMeta: metav1.ObjectMeta{
  24. Name: name,
  25. ResourceVersion: version,
  26. },
  27. Spec: v1.PersistentVolumeSpec{
  28. StorageClassName: storageClass,
  29. },
  30. }
  31. }
  32. func verifyListPVs(t *testing.T, cache PVAssumeCache, expectedPVs map[string]*v1.PersistentVolume, storageClassName string) {
  33. pvList := cache.ListPVs(storageClassName)
  34. if len(pvList) != len(expectedPVs) {
  35. t.Errorf("ListPVs() returned %v PVs, expected %v", len(pvList), len(expectedPVs))
  36. }
  37. for _, pv := range pvList {
  38. expectedPV, ok := expectedPVs[pv.Name]
  39. if !ok {
  40. t.Errorf("ListPVs() returned unexpected PV %q", pv.Name)
  41. }
  42. if expectedPV != pv {
  43. t.Errorf("ListPVs() returned PV %p, expected %p", pv, expectedPV)
  44. }
  45. }
  46. }
  47. func verifyPV(cache PVAssumeCache, name string, expectedPV *v1.PersistentVolume) error {
  48. pv, err := cache.GetPV(name)
  49. if err != nil {
  50. return err
  51. }
  52. if pv != expectedPV {
  53. return fmt.Errorf("GetPV() returned %p, expected %p", pv, expectedPV)
  54. }
  55. return nil
  56. }
  57. func TestAssumePV(t *testing.T) {
  58. scenarios := map[string]struct {
  59. oldPV *v1.PersistentVolume
  60. newPV *v1.PersistentVolume
  61. shouldSucceed bool
  62. }{
  63. "success-same-version": {
  64. oldPV: makePV("pv1", "5", ""),
  65. newPV: makePV("pv1", "5", ""),
  66. shouldSucceed: true,
  67. },
  68. "success-storageclass-same-version": {
  69. oldPV: makePV("pv1", "5", "class1"),
  70. newPV: makePV("pv1", "5", "class1"),
  71. shouldSucceed: true,
  72. },
  73. "success-new-higher-version": {
  74. oldPV: makePV("pv1", "5", ""),
  75. newPV: makePV("pv1", "6", ""),
  76. shouldSucceed: true,
  77. },
  78. "fail-old-not-found": {
  79. oldPV: makePV("pv2", "5", ""),
  80. newPV: makePV("pv1", "5", ""),
  81. shouldSucceed: false,
  82. },
  83. "fail-new-lower-version": {
  84. oldPV: makePV("pv1", "5", ""),
  85. newPV: makePV("pv1", "4", ""),
  86. shouldSucceed: false,
  87. },
  88. "fail-new-bad-version": {
  89. oldPV: makePV("pv1", "5", ""),
  90. newPV: makePV("pv1", "a", ""),
  91. shouldSucceed: false,
  92. },
  93. "fail-old-bad-version": {
  94. oldPV: makePV("pv1", "a", ""),
  95. newPV: makePV("pv1", "5", ""),
  96. shouldSucceed: false,
  97. },
  98. }
  99. for name, scenario := range scenarios {
  100. cache := NewPVAssumeCache(nil)
  101. internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
  102. if !ok {
  103. t.Fatalf("Failed to get internal cache")
  104. }
  105. // Add oldPV to cache
  106. internalCache.add(scenario.oldPV)
  107. if err := verifyPV(cache, scenario.oldPV.Name, scenario.oldPV); err != nil {
  108. t.Errorf("Failed to GetPV() after initial update: %v", err)
  109. continue
  110. }
  111. // Assume newPV
  112. err := cache.Assume(scenario.newPV)
  113. if scenario.shouldSucceed && err != nil {
  114. t.Errorf("Test %q failed: Assume() returned error %v", name, err)
  115. }
  116. if !scenario.shouldSucceed && err == nil {
  117. t.Errorf("Test %q failed: Assume() returned success but expected error", name)
  118. }
  119. // Check that GetPV returns correct PV
  120. expectedPV := scenario.newPV
  121. if !scenario.shouldSucceed {
  122. expectedPV = scenario.oldPV
  123. }
  124. if err := verifyPV(cache, scenario.oldPV.Name, expectedPV); err != nil {
  125. t.Errorf("Failed to GetPV() after initial update: %v", err)
  126. }
  127. }
  128. }
  129. func TestRestorePV(t *testing.T) {
  130. cache := NewPVAssumeCache(nil)
  131. internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
  132. if !ok {
  133. t.Fatalf("Failed to get internal cache")
  134. }
  135. oldPV := makePV("pv1", "5", "")
  136. newPV := makePV("pv1", "5", "")
  137. // Restore PV that doesn't exist
  138. cache.Restore("nothing")
  139. // Add oldPV to cache
  140. internalCache.add(oldPV)
  141. if err := verifyPV(cache, oldPV.Name, oldPV); err != nil {
  142. t.Fatalf("Failed to GetPV() after initial update: %v", err)
  143. }
  144. // Restore PV
  145. cache.Restore(oldPV.Name)
  146. if err := verifyPV(cache, oldPV.Name, oldPV); err != nil {
  147. t.Fatalf("Failed to GetPV() after iniital restore: %v", err)
  148. }
  149. // Assume newPV
  150. if err := cache.Assume(newPV); err != nil {
  151. t.Fatalf("Assume() returned error %v", err)
  152. }
  153. if err := verifyPV(cache, oldPV.Name, newPV); err != nil {
  154. t.Fatalf("Failed to GetPV() after Assume: %v", err)
  155. }
  156. // Restore PV
  157. cache.Restore(oldPV.Name)
  158. if err := verifyPV(cache, oldPV.Name, oldPV); err != nil {
  159. t.Fatalf("Failed to GetPV() after restore: %v", err)
  160. }
  161. }
  162. func TestBasicPVCache(t *testing.T) {
  163. cache := NewPVAssumeCache(nil)
  164. internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
  165. if !ok {
  166. t.Fatalf("Failed to get internal cache")
  167. }
  168. // Get object that doesn't exist
  169. pv, err := cache.GetPV("nothere")
  170. if err == nil {
  171. t.Errorf("GetPV() returned unexpected success")
  172. }
  173. if pv != nil {
  174. t.Errorf("GetPV() returned unexpected PV %q", pv.Name)
  175. }
  176. // Add a bunch of PVs
  177. pvs := map[string]*v1.PersistentVolume{}
  178. for i := 0; i < 10; i++ {
  179. pv := makePV(fmt.Sprintf("test-pv%v", i), "1", "")
  180. pvs[pv.Name] = pv
  181. internalCache.add(pv)
  182. }
  183. // List them
  184. verifyListPVs(t, cache, pvs, "")
  185. // Update a PV
  186. updatedPV := makePV("test-pv3", "2", "")
  187. pvs[updatedPV.Name] = updatedPV
  188. internalCache.update(nil, updatedPV)
  189. // List them
  190. verifyListPVs(t, cache, pvs, "")
  191. // Delete a PV
  192. deletedPV := pvs["test-pv7"]
  193. delete(pvs, deletedPV.Name)
  194. internalCache.delete(deletedPV)
  195. // List them
  196. verifyListPVs(t, cache, pvs, "")
  197. }
  198. func TestPVCacheWithStorageClasses(t *testing.T) {
  199. cache := NewPVAssumeCache(nil)
  200. internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
  201. if !ok {
  202. t.Fatalf("Failed to get internal cache")
  203. }
  204. // Add a bunch of PVs
  205. pvs1 := map[string]*v1.PersistentVolume{}
  206. for i := 0; i < 10; i++ {
  207. pv := makePV(fmt.Sprintf("test-pv%v", i), "1", "class1")
  208. pvs1[pv.Name] = pv
  209. internalCache.add(pv)
  210. }
  211. // Add a bunch of PVs
  212. pvs2 := map[string]*v1.PersistentVolume{}
  213. for i := 0; i < 10; i++ {
  214. pv := makePV(fmt.Sprintf("test2-pv%v", i), "1", "class2")
  215. pvs2[pv.Name] = pv
  216. internalCache.add(pv)
  217. }
  218. // List them
  219. verifyListPVs(t, cache, pvs1, "class1")
  220. verifyListPVs(t, cache, pvs2, "class2")
  221. // Update a PV
  222. updatedPV := makePV("test-pv3", "2", "class1")
  223. pvs1[updatedPV.Name] = updatedPV
  224. internalCache.update(nil, updatedPV)
  225. // List them
  226. verifyListPVs(t, cache, pvs1, "class1")
  227. verifyListPVs(t, cache, pvs2, "class2")
  228. // Delete a PV
  229. deletedPV := pvs1["test-pv7"]
  230. delete(pvs1, deletedPV.Name)
  231. internalCache.delete(deletedPV)
  232. // List them
  233. verifyListPVs(t, cache, pvs1, "class1")
  234. verifyListPVs(t, cache, pvs2, "class2")
  235. }
  236. func TestAssumeUpdatePVCache(t *testing.T) {
  237. cache := NewPVAssumeCache(nil)
  238. internalCache, ok := cache.(*pvAssumeCache).AssumeCache.(*assumeCache)
  239. if !ok {
  240. t.Fatalf("Failed to get internal cache")
  241. }
  242. pvName := "test-pv0"
  243. // Add a PV
  244. pv := makePV(pvName, "1", "")
  245. internalCache.add(pv)
  246. if err := verifyPV(cache, pvName, pv); err != nil {
  247. t.Fatalf("failed to get PV: %v", err)
  248. }
  249. // Assume PV
  250. newPV := pv.DeepCopy()
  251. newPV.Spec.ClaimRef = &v1.ObjectReference{Name: "test-claim"}
  252. if err := cache.Assume(newPV); err != nil {
  253. t.Fatalf("failed to assume PV: %v", err)
  254. }
  255. if err := verifyPV(cache, pvName, newPV); err != nil {
  256. t.Fatalf("failed to get PV after assume: %v", err)
  257. }
  258. // Add old PV
  259. internalCache.add(pv)
  260. if err := verifyPV(cache, pvName, newPV); err != nil {
  261. t.Fatalf("failed to get PV after old PV added: %v", err)
  262. }
  263. }
  264. func makeClaim(name, version, namespace string) *v1.PersistentVolumeClaim {
  265. return &v1.PersistentVolumeClaim{
  266. ObjectMeta: metav1.ObjectMeta{
  267. Name: name,
  268. Namespace: namespace,
  269. ResourceVersion: version,
  270. Annotations: map[string]string{},
  271. },
  272. }
  273. }
  274. func verifyPVC(cache PVCAssumeCache, pvcKey string, expectedPVC *v1.PersistentVolumeClaim) error {
  275. pvc, err := cache.GetPVC(pvcKey)
  276. if err != nil {
  277. return err
  278. }
  279. if pvc != expectedPVC {
  280. return fmt.Errorf("GetPVC() returned %p, expected %p", pvc, expectedPVC)
  281. }
  282. return nil
  283. }
  284. func TestAssumePVC(t *testing.T) {
  285. scenarios := map[string]struct {
  286. oldPVC *v1.PersistentVolumeClaim
  287. newPVC *v1.PersistentVolumeClaim
  288. shouldSucceed bool
  289. }{
  290. "success-same-version": {
  291. oldPVC: makeClaim("pvc1", "5", "ns1"),
  292. newPVC: makeClaim("pvc1", "5", "ns1"),
  293. shouldSucceed: true,
  294. },
  295. "success-new-higher-version": {
  296. oldPVC: makeClaim("pvc1", "5", "ns1"),
  297. newPVC: makeClaim("pvc1", "6", "ns1"),
  298. shouldSucceed: true,
  299. },
  300. "fail-old-not-found": {
  301. oldPVC: makeClaim("pvc2", "5", "ns1"),
  302. newPVC: makeClaim("pvc1", "5", "ns1"),
  303. shouldSucceed: false,
  304. },
  305. "fail-new-lower-version": {
  306. oldPVC: makeClaim("pvc1", "5", "ns1"),
  307. newPVC: makeClaim("pvc1", "4", "ns1"),
  308. shouldSucceed: false,
  309. },
  310. "fail-new-bad-version": {
  311. oldPVC: makeClaim("pvc1", "5", "ns1"),
  312. newPVC: makeClaim("pvc1", "a", "ns1"),
  313. shouldSucceed: false,
  314. },
  315. "fail-old-bad-version": {
  316. oldPVC: makeClaim("pvc1", "a", "ns1"),
  317. newPVC: makeClaim("pvc1", "5", "ns1"),
  318. shouldSucceed: false,
  319. },
  320. }
  321. for name, scenario := range scenarios {
  322. cache := NewPVCAssumeCache(nil)
  323. internalCache, ok := cache.(*pvcAssumeCache).AssumeCache.(*assumeCache)
  324. if !ok {
  325. t.Fatalf("Failed to get internal cache")
  326. }
  327. // Add oldPVC to cache
  328. internalCache.add(scenario.oldPVC)
  329. if err := verifyPVC(cache, getPVCName(scenario.oldPVC), scenario.oldPVC); err != nil {
  330. t.Errorf("Failed to GetPVC() after initial update: %v", err)
  331. continue
  332. }
  333. // Assume newPVC
  334. err := cache.Assume(scenario.newPVC)
  335. if scenario.shouldSucceed && err != nil {
  336. t.Errorf("Test %q failed: Assume() returned error %v", name, err)
  337. }
  338. if !scenario.shouldSucceed && err == nil {
  339. t.Errorf("Test %q failed: Assume() returned success but expected error", name)
  340. }
  341. // Check that GetPVC returns correct PVC
  342. expectedPV := scenario.newPVC
  343. if !scenario.shouldSucceed {
  344. expectedPV = scenario.oldPVC
  345. }
  346. if err := verifyPVC(cache, getPVCName(scenario.oldPVC), expectedPV); err != nil {
  347. t.Errorf("Failed to GetPVC() after initial update: %v", err)
  348. }
  349. }
  350. }
  351. func TestRestorePVC(t *testing.T) {
  352. cache := NewPVCAssumeCache(nil)
  353. internalCache, ok := cache.(*pvcAssumeCache).AssumeCache.(*assumeCache)
  354. if !ok {
  355. t.Fatalf("Failed to get internal cache")
  356. }
  357. oldPVC := makeClaim("pvc1", "5", "ns1")
  358. newPVC := makeClaim("pvc1", "5", "ns1")
  359. // Restore PVC that doesn't exist
  360. cache.Restore("nothing")
  361. // Add oldPVC to cache
  362. internalCache.add(oldPVC)
  363. if err := verifyPVC(cache, getPVCName(oldPVC), oldPVC); err != nil {
  364. t.Fatalf("Failed to GetPVC() after initial update: %v", err)
  365. }
  366. // Restore PVC
  367. cache.Restore(getPVCName(oldPVC))
  368. if err := verifyPVC(cache, getPVCName(oldPVC), oldPVC); err != nil {
  369. t.Fatalf("Failed to GetPVC() after iniital restore: %v", err)
  370. }
  371. // Assume newPVC
  372. if err := cache.Assume(newPVC); err != nil {
  373. t.Fatalf("Assume() returned error %v", err)
  374. }
  375. if err := verifyPVC(cache, getPVCName(oldPVC), newPVC); err != nil {
  376. t.Fatalf("Failed to GetPVC() after Assume: %v", err)
  377. }
  378. // Restore PVC
  379. cache.Restore(getPVCName(oldPVC))
  380. if err := verifyPVC(cache, getPVCName(oldPVC), oldPVC); err != nil {
  381. t.Fatalf("Failed to GetPVC() after restore: %v", err)
  382. }
  383. }
  384. func TestAssumeUpdatePVCCache(t *testing.T) {
  385. cache := NewPVCAssumeCache(nil)
  386. internalCache, ok := cache.(*pvcAssumeCache).AssumeCache.(*assumeCache)
  387. if !ok {
  388. t.Fatalf("Failed to get internal cache")
  389. }
  390. pvcName := "test-pvc0"
  391. pvcNamespace := "test-ns"
  392. // Add a PVC
  393. pvc := makeClaim(pvcName, "1", pvcNamespace)
  394. internalCache.add(pvc)
  395. if err := verifyPVC(cache, getPVCName(pvc), pvc); err != nil {
  396. t.Fatalf("failed to get PVC: %v", err)
  397. }
  398. // Assume PVC
  399. newPVC := pvc.DeepCopy()
  400. newPVC.Annotations[pvutil.AnnSelectedNode] = "test-node"
  401. if err := cache.Assume(newPVC); err != nil {
  402. t.Fatalf("failed to assume PVC: %v", err)
  403. }
  404. if err := verifyPVC(cache, getPVCName(pvc), newPVC); err != nil {
  405. t.Fatalf("failed to get PVC after assume: %v", err)
  406. }
  407. // Add old PVC
  408. internalCache.add(pvc)
  409. if err := verifyPVC(cache, getPVCName(pvc), newPVC); err != nil {
  410. t.Fatalf("failed to get PVC after old PVC added: %v", err)
  411. }
  412. }