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