sigs.k8s.io/kueue@v0.6.2/pkg/scheduler/preemption/preemption_test.go (about) 1 /* 2 Copyright 2023 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 preemption 18 19 import ( 20 "context" 21 "sort" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/google/go-cmp/cmp" 27 "github.com/google/go-cmp/cmp/cmpopts" 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/runtime" 31 "k8s.io/apimachinery/pkg/util/sets" 32 "k8s.io/client-go/tools/record" 33 "k8s.io/utils/ptr" 34 35 kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" 36 "sigs.k8s.io/kueue/pkg/cache" 37 "sigs.k8s.io/kueue/pkg/constants" 38 "sigs.k8s.io/kueue/pkg/features" 39 "sigs.k8s.io/kueue/pkg/scheduler/flavorassigner" 40 utiltesting "sigs.k8s.io/kueue/pkg/util/testing" 41 "sigs.k8s.io/kueue/pkg/workload" 42 ) 43 44 var snapCmpOpts = []cmp.Option{ 45 cmpopts.EquateEmpty(), 46 cmpopts.IgnoreUnexported(cache.ClusterQueue{}), 47 cmpopts.IgnoreFields(cache.Cohort{}, "AllocatableResourceGeneration"), 48 cmpopts.IgnoreFields(cache.ClusterQueue{}, "AllocatableResourceGeneration"), 49 cmp.Transformer("Cohort.Members", func(s sets.Set[*cache.ClusterQueue]) sets.Set[string] { 50 result := make(sets.Set[string], len(s)) 51 for cq := range s { 52 result.Insert(cq.Name) 53 } 54 return result 55 }), // avoid recursion. 56 } 57 58 func TestPreemption(t *testing.T) { 59 flavors := []*kueue.ResourceFlavor{ 60 utiltesting.MakeResourceFlavor("default").Obj(), 61 utiltesting.MakeResourceFlavor("alpha").Obj(), 62 utiltesting.MakeResourceFlavor("beta").Obj(), 63 } 64 clusterQueues := []*kueue.ClusterQueue{ 65 utiltesting.MakeClusterQueue("standalone"). 66 ResourceGroup( 67 *utiltesting.MakeFlavorQuotas("default"). 68 Resource(corev1.ResourceCPU, "6"). 69 Obj(), 70 ).ResourceGroup( 71 *utiltesting.MakeFlavorQuotas("alpha"). 72 Resource(corev1.ResourceMemory, "3Gi"). 73 Obj(), 74 *utiltesting.MakeFlavorQuotas("beta"). 75 Resource(corev1.ResourceMemory, "3Gi"). 76 Obj(), 77 ). 78 Preemption(kueue.ClusterQueuePreemption{ 79 WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, 80 }). 81 Obj(), 82 utiltesting.MakeClusterQueue("c1"). 83 Cohort("cohort"). 84 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 85 Resource(corev1.ResourceCPU, "6", "12"). 86 Resource(corev1.ResourceMemory, "3Gi", "6Gi"). 87 Obj(), 88 ). 89 Preemption(kueue.ClusterQueuePreemption{ 90 WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, 91 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 92 }). 93 Obj(), 94 utiltesting.MakeClusterQueue("c2"). 95 Cohort("cohort"). 96 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 97 Resource(corev1.ResourceCPU, "6", "12"). 98 Resource(corev1.ResourceMemory, "3Gi", "6Gi"). 99 Obj(), 100 ). 101 Preemption(kueue.ClusterQueuePreemption{ 102 WithinClusterQueue: kueue.PreemptionPolicyNever, 103 ReclaimWithinCohort: kueue.PreemptionPolicyAny, 104 }). 105 Obj(), 106 utiltesting.MakeClusterQueue("d1"). 107 Cohort("cohort-no-limits"). 108 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 109 Resource(corev1.ResourceCPU, "6"). 110 Resource(corev1.ResourceMemory, "3Gi"). 111 Obj(), 112 ). 113 Preemption(kueue.ClusterQueuePreemption{ 114 WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, 115 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 116 }). 117 Obj(), 118 utiltesting.MakeClusterQueue("d2"). 119 Cohort("cohort-no-limits"). 120 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 121 Resource(corev1.ResourceCPU, "6"). 122 Resource(corev1.ResourceMemory, "3Gi"). 123 Obj(), 124 ). 125 Preemption(kueue.ClusterQueuePreemption{ 126 WithinClusterQueue: kueue.PreemptionPolicyNever, 127 ReclaimWithinCohort: kueue.PreemptionPolicyAny, 128 }). 129 Obj(), 130 utiltesting.MakeClusterQueue("l1"). 131 Cohort("legion"). 132 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 133 Resource(corev1.ResourceCPU, "6", "12"). 134 Resource(corev1.ResourceMemory, "3Gi", "6Gi"). 135 Obj(), 136 ). 137 Preemption(kueue.ClusterQueuePreemption{ 138 WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, 139 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 140 }). 141 Obj(), 142 utiltesting.MakeClusterQueue("preventStarvation"). 143 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 144 Resource(corev1.ResourceCPU, "6"). 145 Obj(), 146 ). 147 Preemption(kueue.ClusterQueuePreemption{ 148 WithinClusterQueue: kueue.PreemptionPolicyLowerOrNewerEqualPriority, 149 }). 150 Obj(), 151 utiltesting.MakeClusterQueue("a_standard"). 152 Cohort("with_shared_cq"). 153 ResourceGroup( 154 *utiltesting.MakeFlavorQuotas("default"). 155 Resource(corev1.ResourceCPU, "1", "12"). 156 Obj(), 157 ). 158 Preemption(kueue.ClusterQueuePreemption{ 159 WithinClusterQueue: kueue.PreemptionPolicyNever, 160 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 161 BorrowWithinCohort: &kueue.BorrowWithinCohort{ 162 Policy: kueue.BorrowWithinCohortPolicyLowerPriority, 163 MaxPriorityThreshold: ptr.To[int32](0), 164 }, 165 }). 166 Obj(), 167 utiltesting.MakeClusterQueue("b_standard"). 168 Cohort("with_shared_cq"). 169 ResourceGroup( 170 *utiltesting.MakeFlavorQuotas("default"). 171 Resource(corev1.ResourceCPU, "1", "12"). 172 Obj(), 173 ). 174 Preemption(kueue.ClusterQueuePreemption{ 175 WithinClusterQueue: kueue.PreemptionPolicyNever, 176 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 177 BorrowWithinCohort: &kueue.BorrowWithinCohort{ 178 Policy: kueue.BorrowWithinCohortPolicyLowerPriority, 179 MaxPriorityThreshold: ptr.To[int32](0), 180 }, 181 }). 182 Obj(), 183 utiltesting.MakeClusterQueue("a_best_effort"). 184 Cohort("with_shared_cq"). 185 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 186 Resource(corev1.ResourceCPU, "1", "12"). 187 Obj(), 188 ). 189 Preemption(kueue.ClusterQueuePreemption{ 190 WithinClusterQueue: kueue.PreemptionPolicyNever, 191 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 192 BorrowWithinCohort: &kueue.BorrowWithinCohort{ 193 Policy: kueue.BorrowWithinCohortPolicyLowerPriority, 194 MaxPriorityThreshold: ptr.To[int32](0), 195 }, 196 }). 197 Obj(), 198 utiltesting.MakeClusterQueue("shared"). 199 Cohort("with_shared_cq"). 200 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 201 Resource(corev1.ResourceCPU, "10"). 202 Obj(), 203 ). 204 Obj(), 205 utiltesting.MakeClusterQueue("lend1"). 206 Cohort("cohort-lend"). 207 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 208 Resource(corev1.ResourceCPU, "6", "", "4"). 209 Obj(), 210 ). 211 Preemption(kueue.ClusterQueuePreemption{ 212 WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, 213 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 214 }). 215 Obj(), 216 utiltesting.MakeClusterQueue("lend2"). 217 Cohort("cohort-lend"). 218 ResourceGroup(*utiltesting.MakeFlavorQuotas("default"). 219 Resource(corev1.ResourceCPU, "6", "", "2"). 220 Obj(), 221 ). 222 Preemption(kueue.ClusterQueuePreemption{ 223 WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, 224 ReclaimWithinCohort: kueue.PreemptionPolicyLowerPriority, 225 }). 226 Obj(), 227 } 228 cases := map[string]struct { 229 admitted []kueue.Workload 230 incoming *kueue.Workload 231 targetCQ string 232 assignment flavorassigner.Assignment 233 wantPreempted sets.Set[string] 234 enableLendingLimit bool 235 }{ 236 "preempt lowest priority": { 237 admitted: []kueue.Workload{ 238 *utiltesting.MakeWorkload("low", ""). 239 Priority(-1). 240 Request(corev1.ResourceCPU, "2"). 241 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 242 Obj(), 243 *utiltesting.MakeWorkload("mid", ""). 244 Request(corev1.ResourceCPU, "2"). 245 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 246 Obj(), 247 *utiltesting.MakeWorkload("high", ""). 248 Priority(1). 249 Request(corev1.ResourceCPU, "2"). 250 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 251 Obj(), 252 }, 253 incoming: utiltesting.MakeWorkload("in", ""). 254 Priority(1). 255 Request(corev1.ResourceCPU, "2"). 256 Obj(), 257 targetCQ: "standalone", 258 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 259 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 260 Name: "default", 261 Mode: flavorassigner.Preempt, 262 }, 263 }), 264 wantPreempted: sets.New("/low"), 265 }, 266 "preempt multiple": { 267 admitted: []kueue.Workload{ 268 *utiltesting.MakeWorkload("low", ""). 269 Priority(-1). 270 Request(corev1.ResourceCPU, "2"). 271 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 272 Obj(), 273 *utiltesting.MakeWorkload("mid", ""). 274 Request(corev1.ResourceCPU, "2"). 275 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 276 Obj(), 277 *utiltesting.MakeWorkload("high", ""). 278 Priority(1). 279 Request(corev1.ResourceCPU, "2"). 280 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 281 Obj(), 282 }, 283 incoming: utiltesting.MakeWorkload("in", ""). 284 Priority(1). 285 Request(corev1.ResourceCPU, "3"). 286 Obj(), 287 targetCQ: "standalone", 288 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 289 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 290 Name: "default", 291 Mode: flavorassigner.Preempt, 292 }, 293 }), 294 wantPreempted: sets.New("/low", "/mid"), 295 }, 296 297 "no preemption for low priority": { 298 admitted: []kueue.Workload{ 299 *utiltesting.MakeWorkload("low", ""). 300 Priority(-1). 301 Request(corev1.ResourceCPU, "3"). 302 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 303 Obj(), 304 *utiltesting.MakeWorkload("mid", ""). 305 Request(corev1.ResourceCPU, "3"). 306 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 307 Obj(), 308 }, 309 incoming: utiltesting.MakeWorkload("in", ""). 310 Priority(-1). 311 Request(corev1.ResourceCPU, "1"). 312 Obj(), 313 targetCQ: "standalone", 314 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 315 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 316 Name: "default", 317 Mode: flavorassigner.Preempt, 318 }, 319 }), 320 }, 321 "not enough low priority workloads": { 322 admitted: []kueue.Workload{ 323 *utiltesting.MakeWorkload("low", ""). 324 Priority(-1). 325 Request(corev1.ResourceCPU, "3"). 326 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 327 Obj(), 328 *utiltesting.MakeWorkload("mid", ""). 329 Request(corev1.ResourceCPU, "3"). 330 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 331 Obj(), 332 }, 333 incoming: utiltesting.MakeWorkload("in", ""). 334 Request(corev1.ResourceCPU, "4"). 335 Obj(), 336 targetCQ: "standalone", 337 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 338 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 339 Name: "default", 340 Mode: flavorassigner.Preempt, 341 }, 342 }), 343 }, 344 "some free quota, preempt low priority": { 345 admitted: []kueue.Workload{ 346 *utiltesting.MakeWorkload("low", ""). 347 Priority(-1). 348 Request(corev1.ResourceCPU, "1"). 349 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "1000m").Obj()). 350 Obj(), 351 *utiltesting.MakeWorkload("mid", ""). 352 Request(corev1.ResourceCPU, "1"). 353 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "1000m").Obj()). 354 Obj(), 355 *utiltesting.MakeWorkload("high", ""). 356 Priority(1). 357 Request(corev1.ResourceCPU, "3"). 358 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 359 Obj(), 360 }, 361 incoming: utiltesting.MakeWorkload("in", ""). 362 Priority(1). 363 Request(corev1.ResourceCPU, "2"). 364 Obj(), 365 targetCQ: "standalone", 366 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 367 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 368 Name: "default", 369 Mode: flavorassigner.Preempt, 370 }, 371 }), 372 wantPreempted: sets.New("/low"), 373 }, 374 "minimal set excludes low priority": { 375 admitted: []kueue.Workload{ 376 *utiltesting.MakeWorkload("low", ""). 377 Priority(-1). 378 Request(corev1.ResourceCPU, "1"). 379 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "1000m").Obj()). 380 Obj(), 381 *utiltesting.MakeWorkload("mid", ""). 382 Request(corev1.ResourceCPU, "2"). 383 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 384 Obj(), 385 *utiltesting.MakeWorkload("high", ""). 386 Priority(1). 387 Request(corev1.ResourceCPU, "3"). 388 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 389 Obj(), 390 }, 391 incoming: utiltesting.MakeWorkload("in", ""). 392 Priority(1). 393 Request(corev1.ResourceCPU, "2"). 394 Obj(), 395 targetCQ: "standalone", 396 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 397 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 398 Name: "default", 399 Mode: flavorassigner.Preempt, 400 }, 401 }), 402 wantPreempted: sets.New("/mid"), 403 }, 404 "only preempt workloads using the chosen flavor": { 405 admitted: []kueue.Workload{ 406 *utiltesting.MakeWorkload("low", ""). 407 Priority(-1). 408 Request(corev1.ResourceMemory, "2Gi"). 409 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceMemory, "alpha", "2Gi").Obj()). 410 Obj(), 411 *utiltesting.MakeWorkload("mid", ""). 412 Request(corev1.ResourceMemory, "1Gi"). 413 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceMemory, "beta", "1Gi").Obj()). 414 Obj(), 415 *utiltesting.MakeWorkload("high", ""). 416 Priority(1). 417 Request(corev1.ResourceMemory, "1Gi"). 418 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceMemory, "beta", "1Gi").Obj()). 419 Obj(), 420 }, 421 incoming: utiltesting.MakeWorkload("in", ""). 422 Priority(1). 423 Request(corev1.ResourceCPU, "1"). 424 Request(corev1.ResourceMemory, "2Gi"). 425 Obj(), 426 targetCQ: "standalone", 427 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 428 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 429 Name: "default", 430 Mode: flavorassigner.Fit, 431 }, 432 corev1.ResourceMemory: &flavorassigner.FlavorAssignment{ 433 Name: "beta", 434 Mode: flavorassigner.Preempt, 435 }, 436 }), 437 wantPreempted: sets.New("/mid"), 438 }, 439 "reclaim quota from borrower": { 440 admitted: []kueue.Workload{ 441 *utiltesting.MakeWorkload("c1-low", ""). 442 Priority(-1). 443 Request(corev1.ResourceCPU, "3"). 444 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 445 Obj(), 446 *utiltesting.MakeWorkload("c2-mid", ""). 447 Request(corev1.ResourceCPU, "3"). 448 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 449 Obj(), 450 *utiltesting.MakeWorkload("c2-high", ""). 451 Priority(1). 452 Request(corev1.ResourceCPU, "6"). 453 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "6000m").Obj()). 454 Obj(), 455 }, 456 incoming: utiltesting.MakeWorkload("in", ""). 457 Priority(1). 458 Request(corev1.ResourceCPU, "3"). 459 Obj(), 460 targetCQ: "c1", 461 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 462 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 463 Name: "default", 464 Mode: flavorassigner.Preempt, 465 }, 466 }), 467 wantPreempted: sets.New("/c2-mid"), 468 }, 469 "no workloads borrowing": { 470 admitted: []kueue.Workload{ 471 *utiltesting.MakeWorkload("c1-high", ""). 472 Priority(1). 473 Request(corev1.ResourceCPU, "4"). 474 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 475 Obj(), 476 *utiltesting.MakeWorkload("c2-low-1", ""). 477 Priority(-1). 478 Request(corev1.ResourceCPU, "4"). 479 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 480 Obj(), 481 }, 482 incoming: utiltesting.MakeWorkload("in", ""). 483 Priority(1). 484 Request(corev1.ResourceCPU, "4"). 485 Obj(), 486 targetCQ: "c1", 487 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 488 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 489 Name: "default", 490 Mode: flavorassigner.Preempt, 491 }, 492 }), 493 }, 494 "not enough workloads borrowing": { 495 admitted: []kueue.Workload{ 496 *utiltesting.MakeWorkload("c1-high", ""). 497 Priority(1). 498 Request(corev1.ResourceCPU, "4"). 499 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 500 Obj(), 501 *utiltesting.MakeWorkload("c2-low-1", ""). 502 Priority(-1). 503 Request(corev1.ResourceCPU, "4"). 504 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 505 Obj(), 506 *utiltesting.MakeWorkload("c2-low-2", ""). 507 Priority(-1). 508 Request(corev1.ResourceCPU, "4"). 509 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 510 Obj(), 511 }, 512 incoming: utiltesting.MakeWorkload("in", ""). 513 Priority(1). 514 Request(corev1.ResourceCPU, "4"). 515 Obj(), 516 targetCQ: "c1", 517 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 518 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 519 Name: "default", 520 Mode: flavorassigner.Preempt, 521 }, 522 }), 523 }, 524 "preempting locally and borrowing other resources in cohort, without cohort candidates": { 525 admitted: []kueue.Workload{ 526 *utiltesting.MakeWorkload("c1-low", ""). 527 Priority(-1). 528 Request(corev1.ResourceCPU, "4"). 529 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 530 Obj(), 531 *utiltesting.MakeWorkload("c2-low-1", ""). 532 Priority(-1). 533 Request(corev1.ResourceCPU, "4"). 534 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 535 Obj(), 536 *utiltesting.MakeWorkload("c2-high-2", ""). 537 Priority(1). 538 Request(corev1.ResourceCPU, "4"). 539 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 540 Obj(), 541 }, 542 incoming: utiltesting.MakeWorkload("in", ""). 543 Priority(1). 544 Request(corev1.ResourceCPU, "4"). 545 Request(corev1.ResourceMemory, "5Gi"). 546 Obj(), 547 targetCQ: "c1", 548 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 549 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 550 Name: "default", 551 Mode: flavorassigner.Preempt, 552 }, 553 corev1.ResourceMemory: &flavorassigner.FlavorAssignment{ 554 Name: "alpha", 555 Mode: flavorassigner.Preempt, 556 }, 557 }), 558 wantPreempted: sets.New("/c1-low"), 559 }, 560 "preempting locally and borrowing same resource in cohort": { 561 admitted: []kueue.Workload{ 562 *utiltesting.MakeWorkload("c1-med", ""). 563 Priority(0). 564 Request(corev1.ResourceCPU, "4"). 565 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 566 Obj(), 567 *utiltesting.MakeWorkload("c1-low", ""). 568 Priority(-1). 569 Request(corev1.ResourceCPU, "4"). 570 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 571 Obj(), 572 *utiltesting.MakeWorkload("c2-low-1", ""). 573 Priority(-1). 574 Request(corev1.ResourceCPU, "4"). 575 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 576 Obj(), 577 }, 578 incoming: utiltesting.MakeWorkload("in", ""). 579 Priority(1). 580 Request(corev1.ResourceCPU, "4"). 581 Obj(), 582 targetCQ: "c1", 583 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 584 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 585 Name: "default", 586 Mode: flavorassigner.Preempt, 587 }, 588 }), 589 wantPreempted: sets.New("/c1-low"), 590 }, 591 "preempting locally and borrowing same resource in cohort; no borrowing limit in the cohort": { 592 admitted: []kueue.Workload{ 593 *utiltesting.MakeWorkload("d1-med", ""). 594 Priority(0). 595 Request(corev1.ResourceCPU, "4"). 596 ReserveQuota(utiltesting.MakeAdmission("d1").Assignment(corev1.ResourceCPU, "default", "4").Obj()). 597 Obj(), 598 *utiltesting.MakeWorkload("d1-low", ""). 599 Priority(-1). 600 Request(corev1.ResourceCPU, "4"). 601 ReserveQuota(utiltesting.MakeAdmission("d1").Assignment(corev1.ResourceCPU, "default", "4").Obj()). 602 Obj(), 603 *utiltesting.MakeWorkload("d2-low-1", ""). 604 Priority(-1). 605 Request(corev1.ResourceCPU, "4"). 606 ReserveQuota(utiltesting.MakeAdmission("d2").Assignment(corev1.ResourceCPU, "default", "4").Obj()). 607 Obj(), 608 }, 609 incoming: utiltesting.MakeWorkload("in", ""). 610 Priority(1). 611 Request(corev1.ResourceCPU, "4"). 612 Obj(), 613 targetCQ: "d1", 614 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 615 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 616 Name: "default", 617 Mode: flavorassigner.Preempt, 618 }, 619 }), 620 wantPreempted: sets.New("/d1-low"), 621 }, 622 "preempting locally and borrowing other resources in cohort, with cohort candidates": { 623 admitted: []kueue.Workload{ 624 *utiltesting.MakeWorkload("c1-med", ""). 625 Priority(0). 626 Request(corev1.ResourceCPU, "4"). 627 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 628 Obj(), 629 *utiltesting.MakeWorkload("c2-low-1", ""). 630 Priority(-1). 631 Request(corev1.ResourceCPU, "5"). 632 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "5000m").Obj()). 633 Obj(), 634 *utiltesting.MakeWorkload("c2-low-2", ""). 635 Priority(-1). 636 Request(corev1.ResourceCPU, "1"). 637 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "1000m").Obj()). 638 Obj(), 639 *utiltesting.MakeWorkload("c2-low-3", ""). 640 Priority(-1). 641 Request(corev1.ResourceCPU, "1"). 642 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "1000m").Obj()). 643 Obj(), 644 }, 645 incoming: utiltesting.MakeWorkload("in", ""). 646 Priority(1). 647 Request(corev1.ResourceCPU, "2"). 648 Request(corev1.ResourceMemory, "5Gi"). 649 Obj(), 650 targetCQ: "c1", 651 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 652 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 653 Name: "default", 654 Mode: flavorassigner.Preempt, 655 }, 656 corev1.ResourceMemory: &flavorassigner.FlavorAssignment{ 657 Name: "default", 658 Mode: flavorassigner.Preempt, 659 }, 660 }), 661 wantPreempted: sets.New("/c1-med"), 662 }, 663 "preempting locally and not borrowing same resource in 1-queue cohort": { 664 admitted: []kueue.Workload{ 665 *utiltesting.MakeWorkload("l1-med", ""). 666 Priority(0). 667 Request(corev1.ResourceCPU, "4"). 668 ReserveQuota(utiltesting.MakeAdmission("l1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 669 Obj(), 670 *utiltesting.MakeWorkload("l1-low", ""). 671 Priority(-1). 672 Request(corev1.ResourceCPU, "2"). 673 ReserveQuota(utiltesting.MakeAdmission("l1").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 674 Obj(), 675 }, 676 incoming: utiltesting.MakeWorkload("in", ""). 677 Priority(1). 678 Request(corev1.ResourceCPU, "4"). 679 Obj(), 680 targetCQ: "l1", 681 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 682 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 683 Name: "default", 684 Mode: flavorassigner.Preempt, 685 }, 686 }), 687 wantPreempted: sets.New("/l1-med"), 688 }, 689 "do not reclaim borrowed quota from same priority for withinCohort=ReclaimFromLowerPriority": { 690 admitted: []kueue.Workload{ 691 *utiltesting.MakeWorkload("c1", ""). 692 Request(corev1.ResourceCPU, "2"). 693 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 694 Obj(), 695 *utiltesting.MakeWorkload("c2-1", ""). 696 Request(corev1.ResourceCPU, "4"). 697 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 698 Obj(), 699 *utiltesting.MakeWorkload("c2-2", ""). 700 Request(corev1.ResourceCPU, "4"). 701 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 702 Obj(), 703 }, 704 incoming: utiltesting.MakeWorkload("in", ""). 705 Request(corev1.ResourceCPU, "4"). 706 Obj(), 707 targetCQ: "c1", 708 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 709 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 710 Name: "default", 711 Mode: flavorassigner.Preempt, 712 }, 713 }), 714 }, 715 "reclaim borrowed quota from same priority for withinCohort=ReclaimFromAny": { 716 admitted: []kueue.Workload{ 717 *utiltesting.MakeWorkload("c1-1", ""). 718 Request(corev1.ResourceCPU, "4"). 719 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 720 Obj(), 721 *utiltesting.MakeWorkload("c1-2", ""). 722 Priority(1). 723 Request(corev1.ResourceCPU, "4"). 724 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 725 Obj(), 726 *utiltesting.MakeWorkload("c2", ""). 727 Request(corev1.ResourceCPU, "2"). 728 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 729 Obj(), 730 }, 731 incoming: utiltesting.MakeWorkload("in", ""). 732 Request(corev1.ResourceCPU, "4"). 733 Obj(), 734 targetCQ: "c2", 735 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 736 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 737 Name: "default", 738 Mode: flavorassigner.Preempt, 739 }, 740 }), 741 wantPreempted: sets.New("/c1-1"), 742 }, 743 "preempt from all ClusterQueues in cohort": { 744 admitted: []kueue.Workload{ 745 *utiltesting.MakeWorkload("c1-low", ""). 746 Priority(-1). 747 Request(corev1.ResourceCPU, "3"). 748 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 749 Obj(), 750 *utiltesting.MakeWorkload("c1-mid", ""). 751 Request(corev1.ResourceCPU, "2"). 752 ReserveQuota(utiltesting.MakeAdmission("c1").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 753 Obj(), 754 *utiltesting.MakeWorkload("c2-low", ""). 755 Priority(-1). 756 Request(corev1.ResourceCPU, "3"). 757 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 758 Obj(), 759 *utiltesting.MakeWorkload("c2-mid", ""). 760 Request(corev1.ResourceCPU, "4"). 761 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 762 Obj(), 763 }, 764 incoming: utiltesting.MakeWorkload("in", ""). 765 Request(corev1.ResourceCPU, "4"). 766 Obj(), 767 targetCQ: "c1", 768 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 769 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 770 Name: "default", 771 Mode: flavorassigner.Preempt, 772 }, 773 }), 774 wantPreempted: sets.New("/c1-low", "/c2-low"), 775 }, 776 "can't preempt workloads in ClusterQueue for withinClusterQueue=Never": { 777 admitted: []kueue.Workload{ 778 *utiltesting.MakeWorkload("c2-low", ""). 779 Priority(-1). 780 Request(corev1.ResourceCPU, "3"). 781 ReserveQuota(utiltesting.MakeAdmission("c2").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 782 Obj(), 783 }, 784 incoming: utiltesting.MakeWorkload("in", ""). 785 Priority(1). 786 Request(corev1.ResourceCPU, "4"). 787 Obj(), 788 targetCQ: "c2", 789 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 790 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 791 Name: "default", 792 Mode: flavorassigner.Preempt, 793 }, 794 }), 795 }, 796 "each podset preempts a different flavor": { 797 admitted: []kueue.Workload{ 798 *utiltesting.MakeWorkload("low-alpha", ""). 799 Priority(-1). 800 Request(corev1.ResourceMemory, "2Gi"). 801 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceMemory, "alpha", "2Gi").Obj()). 802 Obj(), 803 *utiltesting.MakeWorkload("low-beta", ""). 804 Priority(-1). 805 Request(corev1.ResourceMemory, "2Gi"). 806 ReserveQuota(utiltesting.MakeAdmission("standalone").Assignment(corev1.ResourceMemory, "beta", "2Gi").Obj()). 807 Obj(), 808 }, 809 incoming: utiltesting.MakeWorkload("in", ""). 810 PodSets( 811 *utiltesting.MakePodSet("launcher", 1). 812 Request(corev1.ResourceMemory, "2Gi").Obj(), 813 *utiltesting.MakePodSet("workers", 2). 814 Request(corev1.ResourceMemory, "1Gi").Obj(), 815 ). 816 Obj(), 817 targetCQ: "standalone", 818 assignment: flavorassigner.Assignment{ 819 PodSets: []flavorassigner.PodSetAssignment{ 820 { 821 Name: "launcher", 822 Flavors: flavorassigner.ResourceAssignment{ 823 corev1.ResourceMemory: { 824 Name: "alpha", 825 Mode: flavorassigner.Preempt, 826 }, 827 }, 828 }, 829 { 830 Name: "workers", 831 Flavors: flavorassigner.ResourceAssignment{ 832 corev1.ResourceMemory: { 833 Name: "beta", 834 Mode: flavorassigner.Preempt, 835 }, 836 }, 837 }, 838 }, 839 }, 840 wantPreempted: sets.New("/low-alpha", "/low-beta"), 841 }, 842 "preempt newer workloads with the same priority": { 843 admitted: []kueue.Workload{ 844 *utiltesting.MakeWorkload("wl1", ""). 845 Priority(2). 846 Request(corev1.ResourceCPU, "2"). 847 ReserveQuota(utiltesting.MakeAdmission("preventStarvation").Assignment(corev1.ResourceCPU, "default", "2").Obj()). 848 Obj(), 849 *utiltesting.MakeWorkload("wl2", ""). 850 Priority(1). 851 Creation(time.Now()). 852 Request(corev1.ResourceCPU, "2"). 853 ReserveQuota(utiltesting.MakeAdmission("preventStarvation").Assignment(corev1.ResourceCPU, "default", "2").Obj()). 854 SetOrReplaceCondition(metav1.Condition{ 855 Type: kueue.WorkloadQuotaReserved, 856 Status: metav1.ConditionTrue, 857 LastTransitionTime: metav1.NewTime(time.Now().Add(time.Second)), 858 }). 859 Obj(), 860 *utiltesting.MakeWorkload("wl3", ""). 861 Priority(1). 862 Creation(time.Now()). 863 Request(corev1.ResourceCPU, "2"). 864 ReserveQuota(utiltesting.MakeAdmission("preventStarvation").Assignment(corev1.ResourceCPU, "default", "2").Obj()). 865 Obj(), 866 }, 867 incoming: utiltesting.MakeWorkload("in", ""). 868 Priority(1). 869 Creation(time.Now().Add(-15 * time.Second)). 870 PodSets( 871 *utiltesting.MakePodSet("launcher", 1). 872 Request(corev1.ResourceCPU, "2").Obj(), 873 ). 874 Obj(), 875 targetCQ: "preventStarvation", 876 assignment: flavorassigner.Assignment{ 877 PodSets: []flavorassigner.PodSetAssignment{ 878 { 879 Name: "launcher", 880 Flavors: flavorassigner.ResourceAssignment{ 881 corev1.ResourceCPU: { 882 Name: "default", 883 Mode: flavorassigner.Preempt, 884 }, 885 }, 886 }, 887 }, 888 }, 889 wantPreempted: sets.New("/wl2"), 890 }, 891 "use BorrowWithinCohort; allow preempting a lower-priority workload from another ClusterQueue while borrowing": { 892 admitted: []kueue.Workload{ 893 *utiltesting.MakeWorkload("a_best_effort_low", ""). 894 Priority(-1). 895 Request(corev1.ResourceCPU, "10"). 896 ReserveQuota(utiltesting.MakeAdmission("a_best_effort").Assignment(corev1.ResourceCPU, "default", "10000m").Obj()). 897 Obj(), 898 *utiltesting.MakeWorkload("b_best_effort_low", ""). 899 Priority(-1). 900 Request(corev1.ResourceCPU, "1"). 901 ReserveQuota(utiltesting.MakeAdmission("b_best_effort").Assignment(corev1.ResourceCPU, "default", "1000m").Obj()). 902 Obj(), 903 }, 904 incoming: utiltesting.MakeWorkload("in", ""). 905 Request(corev1.ResourceCPU, "10"). 906 Obj(), 907 targetCQ: "a_standard", 908 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 909 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 910 Name: "default", 911 Mode: flavorassigner.Preempt, 912 }, 913 }), 914 wantPreempted: sets.New("/a_best_effort_low"), 915 }, 916 "use BorrowWithinCohort; don't allow preempting a lower-priority workload with priority above MaxPriorityThreshold, if borrowing is required even after the preemption": { 917 admitted: []kueue.Workload{ 918 *utiltesting.MakeWorkload("b_standard", ""). 919 Priority(1). 920 Request(corev1.ResourceCPU, "10"). 921 ReserveQuota(utiltesting.MakeAdmission("b_standard").Assignment(corev1.ResourceCPU, "default", "10000m").Obj()). 922 Obj(), 923 }, 924 incoming: utiltesting.MakeWorkload("in", ""). 925 Priority(2). 926 Request(corev1.ResourceCPU, "10"). 927 Obj(), 928 targetCQ: "a_standard", 929 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 930 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 931 Name: "default", 932 Mode: flavorassigner.Preempt, 933 }, 934 }), 935 }, 936 "use BorrowWithinCohort; allow preempting a lower-priority workload with priority above MaxPriorityThreshold, if borrowing is not required after the preemption": { 937 admitted: []kueue.Workload{ 938 // this admitted workload consumes all resources so it needs to be preempted to run a new workload 939 *utiltesting.MakeWorkload("b_standard", ""). 940 Priority(1). 941 Request(corev1.ResourceCPU, "13"). 942 ReserveQuota(utiltesting.MakeAdmission("b_standard").Assignment(corev1.ResourceCPU, "default", "13000m").Obj()). 943 Obj(), 944 }, 945 incoming: utiltesting.MakeWorkload("in", ""). 946 // this is a small workload which can be admitted without borrowing, if the b_standard workload is preempted 947 Priority(2). 948 Request(corev1.ResourceCPU, "1"). 949 Obj(), 950 targetCQ: "a_standard", 951 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 952 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 953 Name: "default", 954 Mode: flavorassigner.Preempt, 955 }, 956 }), 957 wantPreempted: sets.New("/b_standard"), 958 }, 959 "use BorrowWithinCohort; don't allow for preemption of lower-priority workload from the same ClusterQueue": { 960 admitted: []kueue.Workload{ 961 *utiltesting.MakeWorkload("a_standard", ""). 962 Priority(1). 963 Request(corev1.ResourceCPU, "13"). 964 ReserveQuota(utiltesting.MakeAdmission("a_standard").Assignment(corev1.ResourceCPU, "default", "13000m").Obj()). 965 Obj(), 966 }, 967 incoming: utiltesting.MakeWorkload("in", ""). 968 Priority(2). 969 Request(corev1.ResourceCPU, "1"). 970 Obj(), 971 targetCQ: "a_standard", 972 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 973 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 974 Name: "default", 975 Mode: flavorassigner.Preempt, 976 }, 977 }), 978 }, 979 "reclaim quota from lender": { 980 admitted: []kueue.Workload{ 981 *utiltesting.MakeWorkload("lend1-low", ""). 982 Priority(-1). 983 Request(corev1.ResourceCPU, "3"). 984 ReserveQuota(utiltesting.MakeAdmission("lend1").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 985 Obj(), 986 *utiltesting.MakeWorkload("lend2-mid", ""). 987 Request(corev1.ResourceCPU, "3"). 988 ReserveQuota(utiltesting.MakeAdmission("lend2").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 989 Obj(), 990 *utiltesting.MakeWorkload("lend2-high", ""). 991 Priority(1). 992 Request(corev1.ResourceCPU, "4"). 993 ReserveQuota(utiltesting.MakeAdmission("lend2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 994 Obj(), 995 }, 996 incoming: utiltesting.MakeWorkload("in", ""). 997 Priority(1). 998 Request(corev1.ResourceCPU, "3"). 999 Obj(), 1000 targetCQ: "lend1", 1001 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 1002 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 1003 Name: "default", 1004 Mode: flavorassigner.Preempt, 1005 }, 1006 }), 1007 wantPreempted: sets.New("/lend2-mid"), 1008 enableLendingLimit: true, 1009 }, 1010 "preempt from all ClusterQueues in cohort-lend": { 1011 admitted: []kueue.Workload{ 1012 *utiltesting.MakeWorkload("lend1-low", ""). 1013 Priority(-1). 1014 Request(corev1.ResourceCPU, "3"). 1015 ReserveQuota(utiltesting.MakeAdmission("lend1").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 1016 Obj(), 1017 *utiltesting.MakeWorkload("lend1-mid", ""). 1018 Request(corev1.ResourceCPU, "2"). 1019 ReserveQuota(utiltesting.MakeAdmission("lend1").Assignment(corev1.ResourceCPU, "default", "2000m").Obj()). 1020 Obj(), 1021 *utiltesting.MakeWorkload("lend2-low", ""). 1022 Priority(-1). 1023 Request(corev1.ResourceCPU, "3"). 1024 ReserveQuota(utiltesting.MakeAdmission("lend2").Assignment(corev1.ResourceCPU, "default", "3000m").Obj()). 1025 Obj(), 1026 *utiltesting.MakeWorkload("lend2-mid", ""). 1027 Request(corev1.ResourceCPU, "4"). 1028 ReserveQuota(utiltesting.MakeAdmission("lend2").Assignment(corev1.ResourceCPU, "default", "4000m").Obj()). 1029 Obj(), 1030 }, 1031 incoming: utiltesting.MakeWorkload("in", ""). 1032 Request(corev1.ResourceCPU, "4"). 1033 Obj(), 1034 targetCQ: "lend1", 1035 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 1036 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 1037 Name: "default", 1038 Mode: flavorassigner.Preempt, 1039 }, 1040 }), 1041 wantPreempted: sets.New("/lend1-low", "/lend2-low"), 1042 enableLendingLimit: true, 1043 }, 1044 "cannot preempt from other ClusterQueues if exceeds requestable quota including lending limit": { 1045 admitted: []kueue.Workload{ 1046 *utiltesting.MakeWorkload("lend2-low", ""). 1047 Priority(-1). 1048 Request(corev1.ResourceCPU, "10"). 1049 ReserveQuota(utiltesting.MakeAdmission("lend2").Assignment(corev1.ResourceCPU, "default", "10").Obj()). 1050 Obj(), 1051 }, 1052 incoming: utiltesting.MakeWorkload("in", ""). 1053 Request(corev1.ResourceCPU, "9"). 1054 Obj(), 1055 targetCQ: "lend1", 1056 assignment: singlePodSetAssignment(flavorassigner.ResourceAssignment{ 1057 corev1.ResourceCPU: &flavorassigner.FlavorAssignment{ 1058 Name: "default", 1059 Mode: flavorassigner.Preempt, 1060 }, 1061 }), 1062 wantPreempted: nil, 1063 enableLendingLimit: true, 1064 }, 1065 } 1066 for name, tc := range cases { 1067 t.Run(name, func(t *testing.T) { 1068 defer features.SetFeatureGateDuringTest(t, features.LendingLimit, tc.enableLendingLimit)() 1069 ctx, _ := utiltesting.ContextWithLog(t) 1070 cl := utiltesting.NewClientBuilder(). 1071 WithLists(&kueue.WorkloadList{Items: tc.admitted}). 1072 Build() 1073 1074 cqCache := cache.New(cl) 1075 for _, flv := range flavors { 1076 cqCache.AddOrUpdateResourceFlavor(flv) 1077 } 1078 for _, cq := range clusterQueues { 1079 if err := cqCache.AddClusterQueue(ctx, cq); err != nil { 1080 t.Fatalf("Couldn't add ClusterQueue to cache: %v", err) 1081 } 1082 } 1083 1084 var lock sync.Mutex 1085 gotPreempted := sets.New[string]() 1086 broadcaster := record.NewBroadcaster() 1087 scheme := runtime.NewScheme() 1088 recorder := broadcaster.NewRecorder(scheme, corev1.EventSource{Component: constants.AdmissionName}) 1089 preemptor := New(cl, workload.Ordering{}, recorder) 1090 preemptor.applyPreemption = func(ctx context.Context, w *kueue.Workload) error { 1091 lock.Lock() 1092 gotPreempted.Insert(workload.Key(w)) 1093 lock.Unlock() 1094 return nil 1095 } 1096 1097 startingSnapshot := cqCache.Snapshot() 1098 // make a working copy of the snapshot than preemption can temporarily modify 1099 snapshot := cqCache.Snapshot() 1100 wlInfo := workload.NewInfo(tc.incoming) 1101 wlInfo.ClusterQueue = tc.targetCQ 1102 targetClusterQueue := snapshot.ClusterQueues[wlInfo.ClusterQueue] 1103 targets := preemptor.GetTargets(*wlInfo, tc.assignment, &snapshot) 1104 preempted, err := preemptor.IssuePreemptions(ctx, targets, targetClusterQueue) 1105 if err != nil { 1106 t.Fatalf("Failed doing preemption") 1107 } 1108 if diff := cmp.Diff(tc.wantPreempted, gotPreempted, cmpopts.EquateEmpty()); diff != "" { 1109 t.Errorf("Issued preemptions (-want,+got):\n%s", diff) 1110 } 1111 if preempted != tc.wantPreempted.Len() { 1112 t.Errorf("Reported %d preemptions, want %d", preempted, tc.wantPreempted.Len()) 1113 } 1114 if diff := cmp.Diff(startingSnapshot, snapshot, snapCmpOpts...); diff != "" { 1115 t.Errorf("Snapshot was modified (-initial,+end):\n%s", diff) 1116 } 1117 }) 1118 } 1119 } 1120 1121 func TestCandidatesOrdering(t *testing.T) { 1122 now := time.Now() 1123 candidates := []*workload.Info{ 1124 workload.NewInfo(utiltesting.MakeWorkload("high", ""). 1125 ReserveQuota(utiltesting.MakeAdmission("self").Obj()). 1126 Priority(10). 1127 Obj()), 1128 workload.NewInfo(utiltesting.MakeWorkload("low", ""). 1129 ReserveQuota(utiltesting.MakeAdmission("self").Obj()). 1130 Priority(-10). 1131 Obj()), 1132 workload.NewInfo(utiltesting.MakeWorkload("other", ""). 1133 ReserveQuota(utiltesting.MakeAdmission("other").Obj()). 1134 Priority(10). 1135 Obj()), 1136 workload.NewInfo(utiltesting.MakeWorkload("evicted", ""). 1137 SetOrReplaceCondition(metav1.Condition{ 1138 Type: kueue.WorkloadEvicted, 1139 Status: metav1.ConditionTrue, 1140 }). 1141 Obj()), 1142 workload.NewInfo(utiltesting.MakeWorkload("old-a", ""). 1143 UID("old-a"). 1144 ReserveQuotaAt(utiltesting.MakeAdmission("self").Obj(), now). 1145 Obj()), 1146 workload.NewInfo(utiltesting.MakeWorkload("old-b", ""). 1147 UID("old-b"). 1148 ReserveQuotaAt(utiltesting.MakeAdmission("self").Obj(), now). 1149 Obj()), 1150 workload.NewInfo(utiltesting.MakeWorkload("current", ""). 1151 ReserveQuota(utiltesting.MakeAdmission("self").Obj()). 1152 SetOrReplaceCondition(metav1.Condition{ 1153 Type: kueue.WorkloadQuotaReserved, 1154 Status: metav1.ConditionTrue, 1155 LastTransitionTime: metav1.NewTime(now.Add(time.Second)), 1156 }). 1157 Obj()), 1158 } 1159 sort.Slice(candidates, candidatesOrdering(candidates, "self", now)) 1160 gotNames := make([]string, len(candidates)) 1161 for i, c := range candidates { 1162 gotNames[i] = workload.Key(c.Obj) 1163 } 1164 wantCandidates := []string{"/evicted", "/other", "/low", "/current", "/old-a", "/old-b", "/high"} 1165 if diff := cmp.Diff(wantCandidates, gotNames); diff != "" { 1166 t.Errorf("Sorted with wrong order (-want,+got):\n%s", diff) 1167 } 1168 } 1169 1170 func singlePodSetAssignment(assignments flavorassigner.ResourceAssignment) flavorassigner.Assignment { 1171 return flavorassigner.Assignment{ 1172 PodSets: []flavorassigner.PodSetAssignment{{ 1173 Name: kueue.DefaultPodSetName, 1174 Flavors: assignments, 1175 }}, 1176 } 1177 }