sigs.k8s.io/kueue@v0.6.2/pkg/controller/jobs/pod/pod_controller_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 pod 18 19 import ( 20 "context" 21 "fmt" 22 "syscall" 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 apierrors "k8s.io/apimachinery/pkg/api/errors" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 "k8s.io/apimachinery/pkg/types" 32 "k8s.io/client-go/tools/record" 33 "k8s.io/utils/ptr" 34 ctrl "sigs.k8s.io/controller-runtime" 35 "sigs.k8s.io/controller-runtime/pkg/client" 36 "sigs.k8s.io/controller-runtime/pkg/client/interceptor" 37 "sigs.k8s.io/controller-runtime/pkg/reconcile" 38 39 kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" 40 controllerconsts "sigs.k8s.io/kueue/pkg/controller/constants" 41 "sigs.k8s.io/kueue/pkg/controller/jobframework" 42 _ "sigs.k8s.io/kueue/pkg/controller/jobs/job" 43 "sigs.k8s.io/kueue/pkg/podset" 44 utiltesting "sigs.k8s.io/kueue/pkg/util/testing" 45 testingpod "sigs.k8s.io/kueue/pkg/util/testingjobs/pod" 46 ) 47 48 func TestPodsReady(t *testing.T) { 49 testCases := map[string]struct { 50 pod *corev1.Pod 51 want bool 52 }{ 53 "pod is ready": { 54 pod: testingpod.MakePod("test-pod", "test-ns"). 55 Queue("test-queue"). 56 StatusConditions( 57 corev1.PodCondition{ 58 Type: corev1.PodReady, 59 Status: corev1.ConditionTrue, 60 }, 61 ). 62 Obj(), 63 want: true, 64 }, 65 "pod is not ready": { 66 pod: testingpod.MakePod("test-pod", "test-ns"). 67 Queue("test-queue"). 68 StatusConditions(). 69 Obj(), 70 want: false, 71 }, 72 } 73 74 for name, tc := range testCases { 75 t.Run(name, func(t *testing.T) { 76 pod := fromObject(tc.pod) 77 got := pod.PodsReady() 78 if tc.want != got { 79 t.Errorf("Unexpected response (want: %v, got: %v)", tc.want, got) 80 } 81 }) 82 } 83 } 84 85 func TestRun(t *testing.T) { 86 testCases := map[string]struct { 87 pods []corev1.Pod 88 runInfo, restoreInfo []podset.PodSetInfo 89 wantErr error 90 }{ 91 "pod set info > 1 for the single pod": { 92 pods: []corev1.Pod{*testingpod.MakePod("test-pod", "test-namespace").Obj()}, 93 runInfo: make([]podset.PodSetInfo, 2), 94 wantErr: podset.ErrInvalidPodsetInfo, 95 }, 96 } 97 98 for name, tc := range testCases { 99 t.Run(name, func(t *testing.T) { 100 pod := fromObject(&tc.pods[0]) 101 102 ctx, _ := utiltesting.ContextWithLog(t) 103 clientBuilder := utiltesting.NewClientBuilder() 104 if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil { 105 t.Fatalf("Could not setup indexes: %v", err) 106 } 107 108 kClient := clientBuilder.WithLists(&corev1.PodList{Items: tc.pods}).Build() 109 110 gotErr := pod.Run(ctx, kClient, tc.runInfo, nil, "") 111 112 if diff := cmp.Diff(tc.wantErr, gotErr, cmpopts.EquateErrors()); diff != "" { 113 t.Errorf("error mismatch (-want +got):\n%s", diff) 114 } 115 }) 116 } 117 } 118 119 var ( 120 podCmpOpts = []cmp.Option{ 121 cmpopts.EquateEmpty(), 122 cmpopts.IgnoreFields(corev1.Pod{}, "TypeMeta", "ObjectMeta.ResourceVersion", 123 "ObjectMeta.DeletionTimestamp"), 124 cmpopts.IgnoreFields(corev1.PodCondition{}, "LastTransitionTime"), 125 } 126 defaultWorkloadCmpOpts = []cmp.Option{ 127 cmpopts.EquateEmpty(), 128 cmpopts.SortSlices(func(a, b kueue.Workload) bool { 129 return a.Name < b.Name 130 }), 131 cmpopts.SortSlices(func(a, b metav1.Condition) bool { 132 return a.Type < b.Type 133 }), 134 cmpopts.IgnoreFields( 135 kueue.Workload{}, "TypeMeta", 136 "ObjectMeta.ResourceVersion", 137 ), 138 cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime"), 139 } 140 ) 141 142 func TestReconciler(t *testing.T) { 143 basePodWrapper := testingpod.MakePod("pod", "ns"). 144 UID("test-uid"). 145 Queue("user-queue"). 146 Request(corev1.ResourceCPU, "1"). 147 Image("", nil) 148 149 now := time.Now() 150 151 testCases := map[string]struct { 152 reconcileKey *types.NamespacedName 153 initObjects []client.Object 154 pods []corev1.Pod 155 wantPods []corev1.Pod 156 workloads []kueue.Workload 157 wantWorkloads []kueue.Workload 158 wantErr error 159 workloadCmpOpts []cmp.Option 160 excessPodsExpectations []keyUIDs 161 // If true, the test will delete workloads before running reconcile 162 deleteWorkloads bool 163 164 wantEvents []utiltesting.EventRecord 165 }{ 166 "scheduling gate is removed and node selector is added if workload is admitted": { 167 initObjects: []client.Object{ 168 utiltesting.MakeResourceFlavor("unit-test-flavor").Label("kubernetes.io/arch", "arm64").Obj(), 169 }, 170 pods: []corev1.Pod{*basePodWrapper. 171 Clone(). 172 Label("kueue.x-k8s.io/managed", "true"). 173 KueueFinalizer(). 174 KueueSchedulingGate(). 175 Obj()}, 176 wantPods: []corev1.Pod{*basePodWrapper. 177 Clone(). 178 Label("kueue.x-k8s.io/managed", "true"). 179 NodeSelector("kubernetes.io/arch", "arm64"). 180 KueueFinalizer(). 181 Obj()}, 182 workloads: []kueue.Workload{ 183 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 184 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 185 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 186 ReserveQuota( 187 utiltesting.MakeAdmission("cq"). 188 Assignment(corev1.ResourceCPU, "unit-test-flavor", "1"). 189 AssignmentPodCount(1). 190 Obj(), 191 ). 192 Admitted(true). 193 Obj(), 194 }, 195 wantWorkloads: []kueue.Workload{ 196 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 197 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 198 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 199 ReserveQuota( 200 utiltesting.MakeAdmission("cq"). 201 Assignment(corev1.ResourceCPU, "unit-test-flavor", "1"). 202 AssignmentPodCount(1). 203 Obj(), 204 ). 205 Admitted(true). 206 Obj(), 207 }, 208 workloadCmpOpts: defaultWorkloadCmpOpts, 209 wantEvents: []utiltesting.EventRecord{ 210 { 211 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 212 EventType: "Normal", 213 Reason: "Started", 214 Message: "Admitted by clusterQueue cq", 215 }, 216 }, 217 }, 218 "non-matching admitted workload is deleted and pod is finalized": { 219 pods: []corev1.Pod{*basePodWrapper. 220 Clone(). 221 Label("kueue.x-k8s.io/managed", "true"). 222 KueueFinalizer(). 223 Obj()}, 224 wantPods: nil, 225 workloads: []kueue.Workload{ 226 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 227 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 2).Request(corev1.ResourceCPU, "1").Obj()). 228 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 229 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 230 Admitted(true). 231 Obj(), 232 }, 233 wantErr: jobframework.ErrNoMatchingWorkloads, 234 workloadCmpOpts: defaultWorkloadCmpOpts, 235 wantEvents: []utiltesting.EventRecord{ 236 { 237 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 238 EventType: "Normal", 239 Reason: "Stopped", 240 Message: "No matching Workload; restoring pod templates according to existent Workload", 241 }, 242 { 243 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 244 EventType: "Normal", 245 Reason: "DeletedWorkload", 246 Message: "Deleted not matching Workload: ns/unit-test", 247 }, 248 }, 249 }, 250 "the workload is created when queue name is set": { 251 pods: []corev1.Pod{*basePodWrapper. 252 Clone(). 253 Label("kueue.x-k8s.io/managed", "true"). 254 KueueFinalizer(). 255 KueueSchedulingGate(). 256 Queue("test-queue"). 257 Obj()}, 258 wantPods: []corev1.Pod{*basePodWrapper. 259 Clone(). 260 Label("kueue.x-k8s.io/managed", "true"). 261 KueueFinalizer(). 262 KueueSchedulingGate(). 263 Queue("test-queue"). 264 Obj()}, 265 wantWorkloads: []kueue.Workload{ 266 *utiltesting.MakeWorkload("pod-pod-a91e8", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 267 PodSets( 268 *utiltesting.MakePodSet(kueue.DefaultPodSetName, 1). 269 Request(corev1.ResourceCPU, "1"). 270 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 271 Obj(), 272 ). 273 Queue("test-queue"). 274 Priority(0). 275 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 276 Labels(map[string]string{ 277 controllerconsts.JobUIDLabel: "test-uid", 278 }). 279 Obj(), 280 }, 281 workloadCmpOpts: defaultWorkloadCmpOpts, 282 wantEvents: []utiltesting.EventRecord{ 283 { 284 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 285 EventType: "Normal", 286 Reason: "CreatedWorkload", 287 Message: "Created Workload: ns/pod-pod-a91e8", 288 }, 289 }, 290 }, 291 "the pod reconciliation is skipped when 'kueue.x-k8s.io/managed' label is not set": { 292 pods: []corev1.Pod{*basePodWrapper. 293 Clone(). 294 Obj()}, 295 wantPods: []corev1.Pod{*basePodWrapper. 296 Clone(). 297 Obj()}, 298 wantWorkloads: []kueue.Workload{}, 299 workloadCmpOpts: defaultWorkloadCmpOpts, 300 }, 301 "pod is stopped when workload is evicted": { 302 pods: []corev1.Pod{*basePodWrapper. 303 Clone(). 304 Label("kueue.x-k8s.io/managed", "true"). 305 KueueFinalizer(). 306 Queue("test-queue"). 307 Obj()}, 308 wantPods: []corev1.Pod{*basePodWrapper. 309 Clone(). 310 Label("kueue.x-k8s.io/managed", "true"). 311 KueueFinalizer(). 312 Queue("test-queue"). 313 StatusConditions(corev1.PodCondition{ 314 Type: "TerminationTarget", 315 Status: corev1.ConditionTrue, 316 Reason: "StoppedByKueue", 317 Message: "Preempted to accommodate a higher priority Workload", 318 }). 319 Obj()}, 320 workloads: []kueue.Workload{ 321 *utiltesting.MakeWorkload("job", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 322 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 323 Queue("test-queue"). 324 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 325 Condition(metav1.Condition{ 326 Type: kueue.WorkloadEvicted, 327 Status: metav1.ConditionTrue, 328 LastTransitionTime: metav1.Now(), 329 Reason: "Preempted", 330 Message: "Preempted to accommodate a higher priority Workload", 331 }). 332 Obj(), 333 }, 334 wantWorkloads: []kueue.Workload{ 335 *utiltesting.MakeWorkload("job", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 336 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 337 Queue("test-queue"). 338 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 339 Condition(metav1.Condition{ 340 Type: kueue.WorkloadEvicted, 341 Status: metav1.ConditionTrue, 342 LastTransitionTime: metav1.Now(), 343 Reason: "Preempted", 344 Message: "Preempted to accommodate a higher priority Workload", 345 }). 346 Obj(), 347 }, 348 workloadCmpOpts: defaultWorkloadCmpOpts, 349 wantEvents: []utiltesting.EventRecord{ 350 { 351 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 352 EventType: "Normal", 353 Reason: "Stopped", 354 Message: "Preempted to accommodate a higher priority Workload", 355 }, 356 }, 357 }, 358 "pod is finalized when it's succeeded": { 359 pods: []corev1.Pod{*basePodWrapper. 360 Clone(). 361 Label("kueue.x-k8s.io/managed", "true"). 362 KueueFinalizer(). 363 StatusPhase(corev1.PodSucceeded). 364 Obj()}, 365 wantPods: []corev1.Pod{*basePodWrapper. 366 Clone(). 367 Label("kueue.x-k8s.io/managed", "true"). 368 StatusPhase(corev1.PodSucceeded). 369 Obj()}, 370 workloads: []kueue.Workload{ 371 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 372 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 373 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 374 Admitted(true). 375 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 376 Obj(), 377 }, 378 wantWorkloads: []kueue.Workload{ 379 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 380 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 381 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 382 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 383 Admitted(true). 384 Condition(metav1.Condition{ 385 Type: "Finished", 386 Status: "True", 387 Reason: "JobFinished", 388 Message: "Job finished successfully", 389 }). 390 Obj(), 391 }, 392 workloadCmpOpts: append( 393 defaultWorkloadCmpOpts, 394 // This is required because SSA doesn't work properly for the fake k8s client. 395 // Reconciler appends "Finished" condition using SSA. Fake client will just 396 // replace all the older conditions. 397 // See: https://github.com/kubernetes-sigs/controller-runtime/issues/2341 398 cmpopts.IgnoreSliceElements(func(c metav1.Condition) bool { 399 return c.Type == "Admitted" 400 }), 401 ), 402 wantEvents: []utiltesting.EventRecord{ 403 { 404 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 405 EventType: "Normal", 406 Reason: "FinishedWorkload", 407 Message: "Workload 'ns/unit-test' is declared finished", 408 }, 409 }, 410 }, 411 "workload status condition is added even if the pod is finalized": { 412 pods: []corev1.Pod{*basePodWrapper. 413 Clone(). 414 Label("kueue.x-k8s.io/managed", "true"). 415 StatusPhase(corev1.PodSucceeded). 416 Obj()}, 417 wantPods: []corev1.Pod{*basePodWrapper. 418 Clone(). 419 Label("kueue.x-k8s.io/managed", "true"). 420 StatusPhase(corev1.PodSucceeded). 421 Obj()}, 422 workloads: []kueue.Workload{ 423 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 424 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 425 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 426 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 427 Admitted(true). 428 Obj(), 429 }, 430 wantWorkloads: []kueue.Workload{ 431 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 432 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 433 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 434 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 435 Admitted(true). 436 Condition(metav1.Condition{ 437 Type: "Finished", 438 Status: "True", 439 Reason: "JobFinished", 440 Message: "Job finished successfully", 441 }). 442 Obj(), 443 }, 444 workloadCmpOpts: defaultWorkloadCmpOpts, 445 wantEvents: []utiltesting.EventRecord{ 446 { 447 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 448 EventType: "Normal", 449 Reason: "FinishedWorkload", 450 Message: "Workload 'ns/unit-test' is declared finished", 451 }, 452 }, 453 }, 454 "pod without scheduling gate is terminated if workload is not admitted": { 455 pods: []corev1.Pod{*basePodWrapper. 456 Clone(). 457 Label("kueue.x-k8s.io/managed", "true"). 458 KueueFinalizer(). 459 Obj()}, 460 wantPods: []corev1.Pod{*basePodWrapper. 461 Clone(). 462 Label("kueue.x-k8s.io/managed", "true"). 463 KueueFinalizer(). 464 StatusConditions(corev1.PodCondition{ 465 Type: "TerminationTarget", 466 Status: corev1.ConditionTrue, 467 Reason: "StoppedByKueue", 468 Message: "Not admitted by cluster queue", 469 }). 470 Obj()}, 471 workloads: []kueue.Workload{ 472 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 473 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 474 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 475 Obj(), 476 }, 477 wantWorkloads: []kueue.Workload{ 478 *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 479 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 480 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 481 Obj(), 482 }, 483 workloadCmpOpts: defaultWorkloadCmpOpts, 484 wantEvents: []utiltesting.EventRecord{ 485 { 486 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 487 EventType: "Normal", 488 Reason: "Stopped", 489 Message: "Not admitted by cluster queue", 490 }, 491 }, 492 }, 493 "workload is composed and created for the pod group": { 494 pods: []corev1.Pod{ 495 *basePodWrapper. 496 Clone(). 497 Label("kueue.x-k8s.io/managed", "true"). 498 KueueFinalizer(). 499 KueueSchedulingGate(). 500 Group("test-group"). 501 GroupTotalCount("2"). 502 Obj(), 503 *basePodWrapper. 504 Clone(). 505 Name("pod2"). 506 Label("kueue.x-k8s.io/managed", "true"). 507 KueueFinalizer(). 508 KueueSchedulingGate(). 509 Group("test-group"). 510 GroupTotalCount("2"). 511 Obj(), 512 }, 513 wantPods: []corev1.Pod{ 514 *basePodWrapper. 515 Clone(). 516 Label("kueue.x-k8s.io/managed", "true"). 517 KueueFinalizer(). 518 KueueSchedulingGate(). 519 Group("test-group"). 520 GroupTotalCount("2"). 521 Obj(), 522 *basePodWrapper. 523 Clone(). 524 Name("pod2"). 525 Label("kueue.x-k8s.io/managed", "true"). 526 KueueFinalizer(). 527 KueueSchedulingGate(). 528 Group("test-group"). 529 GroupTotalCount("2"). 530 Obj(), 531 }, 532 wantWorkloads: []kueue.Workload{ 533 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 534 PodSets( 535 *utiltesting.MakePodSet("dc85db45", 2). 536 Request(corev1.ResourceCPU, "1"). 537 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 538 Obj(), 539 ). 540 Queue("user-queue"). 541 Priority(0). 542 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 543 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 544 Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}). 545 Obj(), 546 }, 547 workloadCmpOpts: defaultWorkloadCmpOpts, 548 wantEvents: []utiltesting.EventRecord{ 549 { 550 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 551 EventType: "Normal", 552 Reason: "CreatedWorkload", 553 Message: "Created Workload: ns/test-group", 554 }, 555 }, 556 }, 557 "workload is found for the pod group": { 558 pods: []corev1.Pod{ 559 *basePodWrapper. 560 Clone(). 561 Label("kueue.x-k8s.io/managed", "true"). 562 KueueFinalizer(). 563 KueueSchedulingGate(). 564 Group("test-group"). 565 GroupTotalCount("2"). 566 Obj(), 567 *basePodWrapper. 568 Clone(). 569 Name("pod2"). 570 Label("kueue.x-k8s.io/managed", "true"). 571 KueueFinalizer(). 572 KueueSchedulingGate(). 573 Group("test-group"). 574 GroupTotalCount("2"). 575 Obj(), 576 }, 577 wantPods: []corev1.Pod{ 578 *basePodWrapper. 579 Clone(). 580 Label("kueue.x-k8s.io/managed", "true"). 581 KueueFinalizer(). 582 KueueSchedulingGate(). 583 Group("test-group"). 584 GroupTotalCount("2"). 585 Obj(), 586 *basePodWrapper. 587 Clone(). 588 Name("pod2"). 589 Label("kueue.x-k8s.io/managed", "true"). 590 KueueFinalizer(). 591 KueueSchedulingGate(). 592 Group("test-group"). 593 GroupTotalCount("2"). 594 Obj(), 595 }, 596 workloads: []kueue.Workload{ 597 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 598 PodSets( 599 *utiltesting.MakePodSet("dc85db45", 2). 600 Request(corev1.ResourceCPU, "1"). 601 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 602 Obj(), 603 ). 604 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 605 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 606 Queue("user-queue"). 607 Priority(0). 608 Obj(), 609 }, 610 wantWorkloads: []kueue.Workload{ 611 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 612 PodSets( 613 *utiltesting.MakePodSet("dc85db45", 2). 614 Request(corev1.ResourceCPU, "1"). 615 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 616 Obj(), 617 ). 618 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 619 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 620 Queue("user-queue"). 621 Priority(0). 622 Obj(), 623 }, 624 workloadCmpOpts: defaultWorkloadCmpOpts, 625 }, 626 "scheduling gate is removed for all pods in the group if workload is admitted": { 627 initObjects: []client.Object{ 628 utiltesting.MakeResourceFlavor("unit-test-flavor").Label("kubernetes.io/arch", "arm64").Obj(), 629 }, 630 pods: []corev1.Pod{ 631 *basePodWrapper. 632 Clone(). 633 Label("kueue.x-k8s.io/managed", "true"). 634 KueueFinalizer(). 635 KueueSchedulingGate(). 636 Group("test-group"). 637 GroupTotalCount("2"). 638 Obj(), 639 *basePodWrapper. 640 Clone(). 641 Name("pod2"). 642 Label("kueue.x-k8s.io/managed", "true"). 643 KueueFinalizer(). 644 KueueSchedulingGate(). 645 Group("test-group"). 646 GroupTotalCount("2"). 647 Obj(), 648 }, 649 wantPods: []corev1.Pod{ 650 *basePodWrapper. 651 Clone(). 652 Label("kueue.x-k8s.io/managed", "true"). 653 KueueFinalizer(). 654 Group("test-group"). 655 GroupTotalCount("2"). 656 NodeSelector("kubernetes.io/arch", "arm64"). 657 Obj(), 658 *basePodWrapper. 659 Clone(). 660 Name("pod2"). 661 Label("kueue.x-k8s.io/managed", "true"). 662 KueueFinalizer(). 663 Group("test-group"). 664 GroupTotalCount("2"). 665 NodeSelector("kubernetes.io/arch", "arm64"). 666 Obj(), 667 }, 668 workloads: []kueue.Workload{ 669 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 670 PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()). 671 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 672 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 673 ReserveQuota( 674 utiltesting.MakeAdmission("cq", "dc85db45"). 675 Assignment(corev1.ResourceCPU, "unit-test-flavor", "2"). 676 AssignmentPodCount(2). 677 Obj(), 678 ). 679 Admitted(true). 680 Obj(), 681 }, 682 wantWorkloads: []kueue.Workload{ 683 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 684 PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()). 685 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 686 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 687 ReserveQuota( 688 utiltesting.MakeAdmission("cq", "dc85db45"). 689 Assignment(corev1.ResourceCPU, "unit-test-flavor", "2"). 690 AssignmentPodCount(2). 691 Obj(), 692 ). 693 Admitted(true). 694 Obj(), 695 }, 696 workloadCmpOpts: defaultWorkloadCmpOpts, 697 wantEvents: []utiltesting.EventRecord{ 698 { 699 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 700 EventType: "Normal", 701 Reason: "Started", 702 Message: "Admitted by clusterQueue cq", 703 }, 704 { 705 Key: types.NamespacedName{Name: "pod2", Namespace: "ns"}, 706 EventType: "Normal", 707 Reason: "Started", 708 Message: "Admitted by clusterQueue cq", 709 }, 710 }, 711 }, 712 "workload is not finished if the pod in the group is running": { 713 pods: []corev1.Pod{ 714 *basePodWrapper. 715 Clone(). 716 Label("kueue.x-k8s.io/managed", "true"). 717 KueueFinalizer(). 718 Group("test-group"). 719 GroupTotalCount("2"). 720 StatusPhase(corev1.PodSucceeded). 721 Obj(), 722 *basePodWrapper. 723 Clone(). 724 Name("pod2"). 725 Label("kueue.x-k8s.io/managed", "true"). 726 KueueFinalizer(). 727 Group("test-group"). 728 GroupTotalCount("2"). 729 Obj(), 730 }, 731 wantPods: []corev1.Pod{ 732 *basePodWrapper. 733 Clone(). 734 Label("kueue.x-k8s.io/managed", "true"). 735 KueueFinalizer(). 736 Group("test-group"). 737 GroupTotalCount("2"). 738 StatusPhase(corev1.PodSucceeded). 739 Obj(), 740 *basePodWrapper. 741 Clone(). 742 Name("pod2"). 743 Label("kueue.x-k8s.io/managed", "true"). 744 KueueFinalizer(). 745 Group("test-group"). 746 GroupTotalCount("2"). 747 Obj(), 748 }, 749 750 workloads: []kueue.Workload{ 751 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 752 PodSets( 753 *utiltesting.MakePodSet("dc85db45", 2). 754 Request(corev1.ResourceCPU, "1"). 755 Obj(), 756 ). 757 Queue("user-queue"). 758 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 759 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 760 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 761 Admitted(true). 762 Obj(), 763 }, 764 wantWorkloads: []kueue.Workload{ 765 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 766 PodSets( 767 *utiltesting.MakePodSet("dc85db45", 2). 768 Request(corev1.ResourceCPU, "1"). 769 Obj(), 770 ). 771 Queue("user-queue"). 772 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 773 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 774 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 775 Admitted(true). 776 ReclaimablePods(kueue.ReclaimablePod{Name: "dc85db45", Count: 1}). 777 Obj(), 778 }, 779 workloadCmpOpts: defaultWorkloadCmpOpts, 780 }, 781 "workload is finished if all pods in the group has finished": { 782 pods: []corev1.Pod{ 783 *basePodWrapper. 784 Clone(). 785 Label("kueue.x-k8s.io/managed", "true"). 786 KueueFinalizer(). 787 Group("test-group"). 788 GroupTotalCount("2"). 789 StatusPhase(corev1.PodSucceeded). 790 Obj(), 791 *basePodWrapper. 792 Clone(). 793 Name("pod2"). 794 Label("kueue.x-k8s.io/managed", "true"). 795 KueueFinalizer(). 796 Group("test-group"). 797 GroupTotalCount("2"). 798 StatusPhase(corev1.PodSucceeded). 799 Obj(), 800 }, 801 wantPods: []corev1.Pod{ 802 *basePodWrapper. 803 Clone(). 804 Label("kueue.x-k8s.io/managed", "true"). 805 Group("test-group"). 806 GroupTotalCount("2"). 807 StatusPhase(corev1.PodSucceeded). 808 Obj(), 809 *basePodWrapper. 810 Clone(). 811 Name("pod2"). 812 Label("kueue.x-k8s.io/managed", "true"). 813 Group("test-group"). 814 GroupTotalCount("2"). 815 StatusPhase(corev1.PodSucceeded). 816 Obj(), 817 }, 818 workloads: []kueue.Workload{ 819 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 820 PodSets( 821 *utiltesting.MakePodSet("dc85db45", 2). 822 Request(corev1.ResourceCPU, "1"). 823 Obj(), 824 ). 825 Queue("user-queue"). 826 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 827 Admitted(true). 828 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 829 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 830 Obj(), 831 }, 832 wantWorkloads: []kueue.Workload{ 833 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 834 PodSets( 835 *utiltesting.MakePodSet("dc85db45", 2). 836 Request(corev1.ResourceCPU, "1"). 837 Obj(), 838 ). 839 Queue("user-queue"). 840 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 841 Admitted(true). 842 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 843 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 844 Condition(metav1.Condition{ 845 Type: "Finished", 846 Status: "True", 847 Reason: "JobFinished", 848 Message: "Pods succeeded: 2/2.", 849 }). 850 Obj(), 851 }, 852 workloadCmpOpts: defaultWorkloadCmpOpts, 853 wantEvents: []utiltesting.EventRecord{ 854 { 855 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 856 EventType: "Normal", 857 Reason: "FinishedWorkload", 858 Message: "Workload 'ns/test-group' is declared finished", 859 }, 860 }, 861 }, 862 "workload is not deleted if the pod in group has been deleted after admission": { 863 pods: []corev1.Pod{*basePodWrapper. 864 Clone(). 865 Label("kueue.x-k8s.io/managed", "true"). 866 KueueFinalizer(). 867 Group("test-group"). 868 GroupTotalCount("2"). 869 Obj()}, 870 wantPods: []corev1.Pod{*basePodWrapper. 871 Clone(). 872 Label("kueue.x-k8s.io/managed", "true"). 873 KueueFinalizer(). 874 Group("test-group"). 875 GroupTotalCount("2"). 876 Obj()}, 877 workloads: []kueue.Workload{ 878 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 879 PodSets( 880 *utiltesting.MakePodSet("dc85db45", 2). 881 Request(corev1.ResourceCPU, "1"). 882 Obj(), 883 ). 884 Queue("user-queue"). 885 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 886 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 887 Admitted(true). 888 Obj(), 889 }, 890 wantWorkloads: []kueue.Workload{ 891 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 892 PodSets( 893 *utiltesting.MakePodSet("dc85db45", 2). 894 Request(corev1.ResourceCPU, "1"). 895 Obj(), 896 ). 897 Queue("user-queue"). 898 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 899 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 900 Admitted(true). 901 Obj(), 902 }, 903 workloadCmpOpts: defaultWorkloadCmpOpts, 904 }, 905 "pod group remains stopped when workload is evicted": { 906 pods: []corev1.Pod{ 907 *basePodWrapper. 908 Clone(). 909 Label("kueue.x-k8s.io/managed", "true"). 910 KueueFinalizer(). 911 KueueSchedulingGate(). 912 Queue("test-queue"). 913 Group("test-group"). 914 GroupTotalCount("2"). 915 Obj(), 916 *basePodWrapper. 917 Clone(). 918 Name("pod2"). 919 Label("kueue.x-k8s.io/managed", "true"). 920 KueueFinalizer(). 921 KueueSchedulingGate(). 922 Queue("test-queue"). 923 Group("test-group"). 924 GroupTotalCount("2"). 925 Obj(), 926 }, 927 wantPods: []corev1.Pod{ 928 *basePodWrapper. 929 Clone(). 930 Label("kueue.x-k8s.io/managed", "true"). 931 KueueFinalizer(). 932 KueueSchedulingGate(). 933 Queue("test-queue"). 934 Group("test-group"). 935 GroupTotalCount("2"). 936 Obj(), 937 *basePodWrapper. 938 Clone(). 939 Name("pod2"). 940 Label("kueue.x-k8s.io/managed", "true"). 941 KueueFinalizer(). 942 KueueSchedulingGate(). 943 Queue("test-queue"). 944 Group("test-group"). 945 GroupTotalCount("2"). 946 Obj(), 947 }, 948 workloads: []kueue.Workload{ 949 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 950 PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()). 951 Queue("test-queue"). 952 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 953 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 954 Condition(metav1.Condition{ 955 Type: kueue.WorkloadEvicted, 956 Status: metav1.ConditionTrue, 957 LastTransitionTime: metav1.Now(), 958 Reason: "Preempted", 959 Message: "Preempted to accommodate a higher priority Workload", 960 }). 961 Obj(), 962 }, 963 wantWorkloads: []kueue.Workload{ 964 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 965 PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()). 966 Queue("test-queue"). 967 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 968 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 969 Condition(metav1.Condition{ 970 Type: kueue.WorkloadEvicted, 971 Status: metav1.ConditionTrue, 972 LastTransitionTime: metav1.Now(), 973 Reason: "Preempted", 974 Message: "Preempted to accommodate a higher priority Workload", 975 }). 976 Obj(), 977 }, 978 workloadCmpOpts: defaultWorkloadCmpOpts, 979 }, 980 "Pods are finalized even if one of the pods in the finished group is absent": { 981 pods: []corev1.Pod{ 982 *basePodWrapper. 983 Clone(). 984 KueueFinalizer(). 985 Label("kueue.x-k8s.io/managed", "true"). 986 Group("test-group"). 987 GroupTotalCount("2"). 988 StatusPhase(corev1.PodSucceeded). 989 Obj(), 990 }, 991 wantPods: []corev1.Pod{ 992 *basePodWrapper. 993 Clone(). 994 Label("kueue.x-k8s.io/managed", "true"). 995 Group("test-group"). 996 GroupTotalCount("2"). 997 StatusPhase(corev1.PodSucceeded). 998 Obj(), 999 }, 1000 1001 workloads: []kueue.Workload{ 1002 *utiltesting.MakeWorkload("test-group", "ns"). 1003 PodSets( 1004 *utiltesting.MakePodSet("dc85db45", 2). 1005 Request(corev1.ResourceCPU, "1"). 1006 Obj(), 1007 ). 1008 Queue("user-queue"). 1009 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1010 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1011 Admitted(true). 1012 Condition(metav1.Condition{ 1013 Type: "Finished", 1014 Status: "True", 1015 Reason: "JobFinished", 1016 Message: "Pods succeeded: 1/2. Pods failed: 1/2", 1017 }). 1018 Obj(), 1019 }, 1020 wantWorkloads: []kueue.Workload{ 1021 *utiltesting.MakeWorkload("test-group", "ns"). 1022 PodSets( 1023 *utiltesting.MakePodSet("dc85db45", 2). 1024 Request(corev1.ResourceCPU, "1"). 1025 Obj(), 1026 ). 1027 Queue("user-queue"). 1028 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1029 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1030 Admitted(true). 1031 Condition(metav1.Condition{ 1032 Type: "Finished", 1033 Status: "True", 1034 Reason: "JobFinished", 1035 Message: "Pods succeeded: 1/2. Pods failed: 1/2", 1036 }). 1037 Obj(), 1038 }, 1039 workloadCmpOpts: defaultWorkloadCmpOpts, 1040 wantEvents: []utiltesting.EventRecord{ 1041 { 1042 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 1043 EventType: "Normal", 1044 Reason: "FinishedWorkload", 1045 Message: "Workload 'ns/test-group' is declared finished", 1046 }, 1047 }, 1048 }, 1049 "workload for pod group with different queue names shouldn't be created": { 1050 pods: []corev1.Pod{ 1051 *basePodWrapper. 1052 Clone(). 1053 Label("kueue.x-k8s.io/managed", "true"). 1054 KueueFinalizer(). 1055 KueueSchedulingGate(). 1056 Queue("test-queue"). 1057 Group("test-group"). 1058 GroupTotalCount("2"). 1059 Obj(), 1060 *basePodWrapper. 1061 Clone(). 1062 Name("pod2"). 1063 Label("kueue.x-k8s.io/managed", "true"). 1064 KueueFinalizer(). 1065 KueueSchedulingGate(). 1066 Queue("new-test-queue"). 1067 Group("test-group"). 1068 GroupTotalCount("2"). 1069 Obj(), 1070 }, 1071 wantPods: []corev1.Pod{ 1072 *basePodWrapper. 1073 Clone(). 1074 Label("kueue.x-k8s.io/managed", "true"). 1075 KueueFinalizer(). 1076 KueueSchedulingGate(). 1077 Queue("test-queue"). 1078 Group("test-group"). 1079 GroupTotalCount("2"). 1080 Obj(), 1081 *basePodWrapper. 1082 Clone(). 1083 Name("pod2"). 1084 Label("kueue.x-k8s.io/managed", "true"). 1085 KueueFinalizer(). 1086 KueueSchedulingGate(). 1087 Queue("new-test-queue"). 1088 Group("test-group"). 1089 GroupTotalCount("2"). 1090 Obj(), 1091 }, 1092 1093 workloads: []kueue.Workload{}, 1094 wantWorkloads: []kueue.Workload{}, 1095 workloadCmpOpts: defaultWorkloadCmpOpts, 1096 }, 1097 "all pods in group should be removed if workload is deleted": { 1098 pods: []corev1.Pod{ 1099 *basePodWrapper. 1100 Clone(). 1101 Label("kueue.x-k8s.io/managed", "true"). 1102 KueueFinalizer(). 1103 Queue("test-queue"). 1104 Group("test-group"). 1105 GroupTotalCount("2"). 1106 Obj(), 1107 *basePodWrapper. 1108 Clone(). 1109 Name("pod2"). 1110 Label("kueue.x-k8s.io/managed", "true"). 1111 KueueFinalizer(). 1112 Queue("test-queue"). 1113 Group("test-group"). 1114 GroupTotalCount("2"). 1115 StatusPhase(corev1.PodSucceeded). 1116 Obj(), 1117 }, 1118 wantPods: []corev1.Pod{}, 1119 workloads: []kueue.Workload{ 1120 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1121 PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()). 1122 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1123 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1124 Queue("test-queue"). 1125 ReserveQuota( 1126 utiltesting.MakeAdmission("cq"). 1127 Assignment(corev1.ResourceCPU, "unit-test-flavor", "2"). 1128 AssignmentPodCount(2). 1129 Obj(), 1130 ). 1131 Admitted(true). 1132 Obj(), 1133 }, 1134 workloadCmpOpts: append(defaultWorkloadCmpOpts, cmpopts.IgnoreFields(kueue.Workload{}, "ObjectMeta.DeletionTimestamp")), 1135 deleteWorkloads: true, 1136 wantEvents: []utiltesting.EventRecord{ 1137 { 1138 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 1139 EventType: "Normal", 1140 Reason: "Stopped", 1141 Message: "Workload is deleted", 1142 }, 1143 { 1144 Key: types.NamespacedName{Name: "pod2", Namespace: "ns"}, 1145 EventType: "Normal", 1146 Reason: "Stopped", 1147 Message: "Workload is deleted", 1148 }, 1149 }, 1150 }, 1151 "replacement pod should be started for pod group of size 1": { 1152 pods: []corev1.Pod{ 1153 *basePodWrapper. 1154 Clone(). 1155 Label("kueue.x-k8s.io/managed", "true"). 1156 KueueFinalizer(). 1157 Group("test-group"). 1158 GroupTotalCount("1"). 1159 StatusPhase(corev1.PodFailed). 1160 Obj(), 1161 *basePodWrapper. 1162 Clone(). 1163 Name("pod2"). 1164 Label("kueue.x-k8s.io/managed", "true"). 1165 KueueFinalizer(). 1166 KueueSchedulingGate(). 1167 Group("test-group"). 1168 GroupTotalCount("1"). 1169 Obj(), 1170 }, 1171 wantPods: []corev1.Pod{ 1172 *basePodWrapper. 1173 Clone(). 1174 Label("kueue.x-k8s.io/managed", "true"). 1175 KueueFinalizer(). 1176 Group("test-group"). 1177 GroupTotalCount("1"). 1178 StatusPhase(corev1.PodFailed). 1179 Obj(), 1180 *basePodWrapper. 1181 Clone(). 1182 Name("pod2"). 1183 Label("kueue.x-k8s.io/managed", "true"). 1184 KueueFinalizer(). 1185 Group("test-group"). 1186 GroupTotalCount("1"). 1187 Obj(), 1188 }, 1189 workloads: []kueue.Workload{ 1190 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1191 PodSets( 1192 *utiltesting.MakePodSet("dc85db45", 2). 1193 Request(corev1.ResourceCPU, "1"). 1194 Obj(), 1195 ). 1196 Queue("user-queue"). 1197 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1198 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1199 ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(1).Obj()). 1200 Admitted(true). 1201 Obj(), 1202 }, 1203 wantWorkloads: []kueue.Workload{ 1204 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1205 PodSets( 1206 *utiltesting.MakePodSet("dc85db45", 2). 1207 Request(corev1.ResourceCPU, "1"). 1208 Obj(), 1209 ). 1210 Queue("user-queue"). 1211 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1212 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1213 ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(1).Obj()). 1214 Admitted(true). 1215 Obj(), 1216 }, 1217 workloadCmpOpts: defaultWorkloadCmpOpts, 1218 wantEvents: []utiltesting.EventRecord{ 1219 { 1220 Key: types.NamespacedName{Name: "pod2", Namespace: "ns"}, 1221 EventType: "Normal", 1222 Reason: "Started", 1223 Message: "Admitted by clusterQueue cq", 1224 }, 1225 }, 1226 }, 1227 "replacement pod should be started for set of Running, Failed, Succeeded pods": { 1228 pods: []corev1.Pod{ 1229 *basePodWrapper. 1230 Clone(). 1231 Label("kueue.x-k8s.io/managed", "true"). 1232 KueueFinalizer(). 1233 Group("test-group"). 1234 GroupTotalCount("3"). 1235 StatusPhase(corev1.PodRunning). 1236 Obj(), 1237 *basePodWrapper. 1238 Clone(). 1239 Name("pod2"). 1240 Label("kueue.x-k8s.io/managed", "true"). 1241 KueueFinalizer(). 1242 Group("test-group"). 1243 GroupTotalCount("3"). 1244 StatusPhase(corev1.PodFailed). 1245 Obj(), 1246 *basePodWrapper. 1247 Clone(). 1248 Name("pod3"). 1249 Label("kueue.x-k8s.io/managed", "true"). 1250 KueueFinalizer(). 1251 Group("test-group"). 1252 GroupTotalCount("3"). 1253 StatusPhase(corev1.PodSucceeded). 1254 Obj(), 1255 *basePodWrapper. 1256 Clone(). 1257 Name("replacement"). 1258 Label("kueue.x-k8s.io/managed", "true"). 1259 KueueFinalizer(). 1260 KueueSchedulingGate(). 1261 Group("test-group"). 1262 GroupTotalCount("3"). 1263 Obj(), 1264 }, 1265 workloads: []kueue.Workload{ 1266 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1267 PodSets( 1268 *utiltesting.MakePodSet("dc85db45", 3). 1269 Request(corev1.ResourceCPU, "1"). 1270 Obj(), 1271 ). 1272 Queue("user-queue"). 1273 ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(3).Obj()). 1274 Admitted(true). 1275 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1276 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1277 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 1278 ReclaimablePods(kueue.ReclaimablePod{Name: "dc85db45", Count: 1}). 1279 Obj(), 1280 }, 1281 wantPods: []corev1.Pod{ 1282 *basePodWrapper. 1283 Clone(). 1284 Label("kueue.x-k8s.io/managed", "true"). 1285 KueueFinalizer(). 1286 Group("test-group"). 1287 GroupTotalCount("3"). 1288 StatusPhase(corev1.PodRunning). 1289 Obj(), 1290 *basePodWrapper. 1291 Clone(). 1292 Name("pod2"). 1293 Label("kueue.x-k8s.io/managed", "true"). 1294 Group("test-group"). 1295 GroupTotalCount("3"). 1296 StatusPhase(corev1.PodFailed). 1297 Obj(), 1298 *basePodWrapper. 1299 Clone(). 1300 Name("pod3"). 1301 Label("kueue.x-k8s.io/managed", "true"). 1302 KueueFinalizer(). 1303 Group("test-group"). 1304 GroupTotalCount("3"). 1305 StatusPhase(corev1.PodSucceeded). 1306 Obj(), 1307 *basePodWrapper. 1308 Clone(). 1309 Name("replacement"). 1310 Label("kueue.x-k8s.io/managed", "true"). 1311 KueueFinalizer(). 1312 Group("test-group"). 1313 GroupTotalCount("3"). 1314 Obj(), 1315 }, 1316 wantWorkloads: []kueue.Workload{ 1317 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1318 PodSets( 1319 *utiltesting.MakePodSet("dc85db45", 3). 1320 Request(corev1.ResourceCPU, "1"). 1321 Obj(), 1322 ). 1323 Queue("user-queue"). 1324 ReserveQuota(utiltesting.MakeAdmission("cq", "dc85db45").AssignmentPodCount(3).Obj()). 1325 ReclaimablePods(kueue.ReclaimablePod{ 1326 Name: "dc85db45", 1327 Count: 1, 1328 }). 1329 Admitted(true). 1330 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1331 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1332 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 1333 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement", "test-uid"). 1334 ReclaimablePods(kueue.ReclaimablePod{Name: "dc85db45", Count: 1}). 1335 Obj(), 1336 }, 1337 workloadCmpOpts: defaultWorkloadCmpOpts, 1338 wantEvents: []utiltesting.EventRecord{ 1339 { 1340 Key: types.NamespacedName{Name: "test-group", Namespace: "ns"}, 1341 EventType: "Normal", 1342 Reason: "OwnerReferencesAdded", 1343 Message: "Added 1 owner reference(s)", 1344 }, 1345 { 1346 Key: types.NamespacedName{Name: "replacement", Namespace: "ns"}, 1347 EventType: "Normal", 1348 Reason: "Started", 1349 Message: "Admitted by clusterQueue cq", 1350 }, 1351 }, 1352 }, 1353 "pod group of size 2 is finished when 2 pods has succeeded and 1 pod has failed": { 1354 pods: []corev1.Pod{ 1355 *basePodWrapper. 1356 Clone(). 1357 Label("kueue.x-k8s.io/managed", "true"). 1358 KueueFinalizer(). 1359 Group("test-group"). 1360 GroupTotalCount("2"). 1361 StatusPhase(corev1.PodFailed). 1362 Obj(), 1363 *basePodWrapper. 1364 Clone(). 1365 Name("pod2"). 1366 Label("kueue.x-k8s.io/managed", "true"). 1367 KueueFinalizer(). 1368 Group("test-group"). 1369 GroupTotalCount("2"). 1370 StatusPhase(corev1.PodSucceeded). 1371 Obj(), 1372 *basePodWrapper. 1373 Clone(). 1374 Name("pod3"). 1375 Label("kueue.x-k8s.io/managed", "true"). 1376 KueueFinalizer(). 1377 Group("test-group"). 1378 GroupTotalCount("2"). 1379 StatusPhase(corev1.PodSucceeded). 1380 Obj(), 1381 }, 1382 wantPods: []corev1.Pod{ 1383 *basePodWrapper. 1384 Clone(). 1385 Label("kueue.x-k8s.io/managed", "true"). 1386 Group("test-group"). 1387 GroupTotalCount("2"). 1388 StatusPhase(corev1.PodFailed). 1389 Obj(), 1390 *basePodWrapper. 1391 Clone(). 1392 Name("pod2"). 1393 Label("kueue.x-k8s.io/managed", "true"). 1394 Group("test-group"). 1395 GroupTotalCount("2"). 1396 StatusPhase(corev1.PodSucceeded). 1397 Obj(), 1398 *basePodWrapper. 1399 Clone(). 1400 Name("pod3"). 1401 Label("kueue.x-k8s.io/managed", "true"). 1402 Group("test-group"). 1403 GroupTotalCount("2"). 1404 StatusPhase(corev1.PodSucceeded). 1405 Obj(), 1406 }, 1407 workloads: []kueue.Workload{ 1408 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1409 PodSets( 1410 *utiltesting.MakePodSet("dc85db45", 2). 1411 Request(corev1.ResourceCPU, "1"). 1412 Obj(), 1413 ). 1414 Queue("user-queue"). 1415 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1416 Admitted(true). 1417 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1418 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1419 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 1420 Obj(), 1421 }, 1422 wantWorkloads: []kueue.Workload{ 1423 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1424 PodSets( 1425 *utiltesting.MakePodSet("dc85db45", 2). 1426 Request(corev1.ResourceCPU, "1"). 1427 Obj(), 1428 ). 1429 Queue("user-queue"). 1430 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1431 Admitted(true). 1432 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1433 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1434 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 1435 Condition(metav1.Condition{ 1436 Type: "Finished", 1437 Status: "True", 1438 Reason: "JobFinished", 1439 Message: "Pods succeeded: 2/2.", 1440 }). 1441 Obj(), 1442 }, 1443 workloadCmpOpts: defaultWorkloadCmpOpts, 1444 wantEvents: []utiltesting.EventRecord{ 1445 { 1446 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 1447 EventType: "Normal", 1448 Reason: "FinishedWorkload", 1449 Message: "Workload 'ns/test-group' is declared finished", 1450 }, 1451 }, 1452 }, 1453 "wl should not get the quota reservation cleared for a running pod group of size 1": { 1454 pods: []corev1.Pod{ 1455 *basePodWrapper. 1456 Clone(). 1457 Label("kueue.x-k8s.io/managed", "true"). 1458 KueueFinalizer(). 1459 Group("test-group"). 1460 GroupTotalCount("1"). 1461 StatusPhase(corev1.PodRunning). 1462 Delete(). 1463 Obj(), 1464 }, 1465 wantPods: []corev1.Pod{ 1466 *basePodWrapper. 1467 Clone(). 1468 Label("kueue.x-k8s.io/managed", "true"). 1469 KueueFinalizer(). 1470 Group("test-group"). 1471 GroupTotalCount("1"). 1472 StatusPhase(corev1.PodRunning). 1473 Delete(). 1474 Obj(), 1475 }, 1476 workloads: []kueue.Workload{ 1477 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1478 PodSets( 1479 *utiltesting.MakePodSet("dc85db45", 1). 1480 Request(corev1.ResourceCPU, "1"). 1481 Obj(), 1482 ). 1483 Queue("user-queue"). 1484 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1485 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1486 Admitted(true). 1487 Condition(metav1.Condition{ 1488 Type: kueue.WorkloadEvicted, 1489 Status: metav1.ConditionTrue, 1490 LastTransitionTime: metav1.Now(), 1491 Reason: "Preempted", 1492 Message: "Preempted to accommodate a higher priority Workload", 1493 }). 1494 Obj(), 1495 }, 1496 wantWorkloads: []kueue.Workload{ 1497 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1498 PodSets( 1499 *utiltesting.MakePodSet("dc85db45", 1). 1500 Request(corev1.ResourceCPU, "1"). 1501 Obj(), 1502 ). 1503 Queue("user-queue"). 1504 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1505 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1506 Admitted(true). 1507 Condition(metav1.Condition{ 1508 Type: kueue.WorkloadEvicted, 1509 Status: metav1.ConditionTrue, 1510 LastTransitionTime: metav1.Now(), 1511 Reason: "Preempted", 1512 Message: "Preempted to accommodate a higher priority Workload", 1513 }). 1514 Obj(), 1515 }, 1516 workloadCmpOpts: defaultWorkloadCmpOpts, 1517 }, 1518 "wl should get the quota reservation cleared for a failed pod group of size 1": { 1519 pods: []corev1.Pod{ 1520 *basePodWrapper. 1521 Clone(). 1522 Label("kueue.x-k8s.io/managed", "true"). 1523 KueueFinalizer(). 1524 Group("test-group"). 1525 GroupTotalCount("1"). 1526 StatusPhase(corev1.PodFailed). 1527 Delete(). 1528 Obj(), 1529 }, 1530 wantPods: []corev1.Pod{ 1531 *basePodWrapper. 1532 Clone(). 1533 Label("kueue.x-k8s.io/managed", "true"). 1534 KueueFinalizer(). 1535 Group("test-group"). 1536 GroupTotalCount("1"). 1537 StatusPhase(corev1.PodFailed). 1538 Delete(). 1539 Obj(), 1540 }, 1541 workloads: []kueue.Workload{ 1542 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1543 PodSets( 1544 *utiltesting.MakePodSet("dc85db45", 1). 1545 Request(corev1.ResourceCPU, "1"). 1546 Obj(), 1547 ). 1548 Queue("user-queue"). 1549 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1550 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1551 Admitted(true). 1552 Condition(metav1.Condition{ 1553 Type: kueue.WorkloadEvicted, 1554 Status: metav1.ConditionTrue, 1555 LastTransitionTime: metav1.Now(), 1556 Reason: "Preempted", 1557 Message: "Preempted to accommodate a higher priority Workload", 1558 }). 1559 Obj(), 1560 }, 1561 wantWorkloads: []kueue.Workload{ 1562 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1563 PodSets( 1564 *utiltesting.MakePodSet("dc85db45", 1). 1565 Request(corev1.ResourceCPU, "1"). 1566 Obj(), 1567 ). 1568 Queue("user-queue"). 1569 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1570 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1571 Condition(metav1.Condition{ 1572 Type: kueue.WorkloadAdmitted, 1573 Status: metav1.ConditionFalse, 1574 LastTransitionTime: metav1.Now(), 1575 Reason: "NoReservation", 1576 Message: "The workload has no reservation", 1577 }). 1578 Condition(metav1.Condition{ 1579 Type: kueue.WorkloadEvicted, 1580 Status: metav1.ConditionTrue, 1581 LastTransitionTime: metav1.Now(), 1582 Reason: "Preempted", 1583 Message: "Preempted to accommodate a higher priority Workload", 1584 }). 1585 SetOrReplaceCondition(metav1.Condition{ 1586 Type: kueue.WorkloadQuotaReserved, 1587 Status: metav1.ConditionFalse, 1588 LastTransitionTime: metav1.Now(), 1589 Reason: "Pending", 1590 Message: "Preempted to accommodate a higher priority Workload", 1591 }). 1592 Obj(), 1593 }, 1594 workloadCmpOpts: defaultWorkloadCmpOpts, 1595 }, 1596 "deleted pods in group should not be finalized if the workload doesn't match": { 1597 pods: []corev1.Pod{ 1598 *basePodWrapper. 1599 Clone(). 1600 Label("kueue.x-k8s.io/managed", "true"). 1601 KueueFinalizer(). 1602 Queue("test-queue"). 1603 Group("test-group"). 1604 GroupTotalCount("2"). 1605 Delete(). 1606 Obj(), 1607 *basePodWrapper. 1608 Clone(). 1609 Name("pod2"). 1610 Label("kueue.x-k8s.io/managed", "true"). 1611 KueueFinalizer(). 1612 Queue("test-queue"). 1613 Group("test-group"). 1614 GroupTotalCount("2"). 1615 Delete(). 1616 Obj(), 1617 }, 1618 wantPods: []corev1.Pod{ 1619 *basePodWrapper. 1620 Clone(). 1621 Label("kueue.x-k8s.io/managed", "true"). 1622 KueueFinalizer(). 1623 Queue("test-queue"). 1624 Group("test-group"). 1625 GroupTotalCount("2"). 1626 Delete(). 1627 Obj(), 1628 *basePodWrapper. 1629 Clone(). 1630 Name("pod2"). 1631 Label("kueue.x-k8s.io/managed", "true"). 1632 KueueFinalizer(). 1633 Queue("test-queue"). 1634 Group("test-group"). 1635 GroupTotalCount("2"). 1636 Delete(). 1637 Obj(), 1638 }, 1639 workloads: []kueue.Workload{ 1640 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1641 PodSets(*utiltesting.MakePodSet("incorrect-role-name", 1).Request(corev1.ResourceCPU, "1").Obj()). 1642 Queue("test-queue"). 1643 ReserveQuota( 1644 utiltesting.MakeAdmission("cq"). 1645 Assignment(corev1.ResourceCPU, "unit-test-flavor", "2"). 1646 AssignmentPodCount(2). 1647 Obj(), 1648 ). 1649 Admitted(true). 1650 Obj(), 1651 }, 1652 wantWorkloads: []kueue.Workload{ 1653 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1654 PodSets(*utiltesting.MakePodSet("dc85db45", 2).Request(corev1.ResourceCPU, "1").Obj()). 1655 Queue("test-queue"). 1656 Priority(0). 1657 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1658 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1659 Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}). 1660 Obj(), 1661 }, 1662 workloadCmpOpts: defaultWorkloadCmpOpts, 1663 deleteWorkloads: true, 1664 wantEvents: []utiltesting.EventRecord{ 1665 { 1666 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 1667 EventType: "Normal", 1668 Reason: "CreatedWorkload", 1669 Message: "Created Workload: ns/test-group", 1670 }, 1671 }, 1672 }, 1673 "workload is not deleted if all of the pods in the group are deleted": { 1674 pods: []corev1.Pod{ 1675 *basePodWrapper. 1676 Clone(). 1677 Label("kueue.x-k8s.io/managed", "true"). 1678 KueueFinalizer(). 1679 Group("test-group"). 1680 GroupTotalCount("2"). 1681 Delete(). 1682 Obj(), 1683 *basePodWrapper. 1684 Clone(). 1685 Name("pod2"). 1686 Label("kueue.x-k8s.io/managed", "true"). 1687 KueueFinalizer(). 1688 Group("test-group"). 1689 GroupTotalCount("2"). 1690 Delete(). 1691 Obj(), 1692 }, 1693 wantPods: []corev1.Pod{ 1694 *basePodWrapper. 1695 Clone(). 1696 Label("kueue.x-k8s.io/managed", "true"). 1697 KueueFinalizer(). 1698 Group("test-group"). 1699 GroupTotalCount("2"). 1700 Delete(). 1701 Obj(), 1702 *basePodWrapper. 1703 Clone(). 1704 Name("pod2"). 1705 Label("kueue.x-k8s.io/managed", "true"). 1706 KueueFinalizer(). 1707 Group("test-group"). 1708 GroupTotalCount("2"). 1709 Delete(). 1710 Obj(), 1711 }, 1712 workloads: []kueue.Workload{ 1713 *utiltesting.MakeWorkload("test-group", "ns"). 1714 PodSets( 1715 *utiltesting.MakePodSet("dc85db45", 2). 1716 Request(corev1.ResourceCPU, "1"). 1717 Obj(), 1718 ). 1719 Queue("user-queue"). 1720 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1721 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1722 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1723 Admitted(true). 1724 Obj(), 1725 }, 1726 wantWorkloads: []kueue.Workload{ 1727 *utiltesting.MakeWorkload("test-group", "ns"). 1728 PodSets( 1729 *utiltesting.MakePodSet("dc85db45", 2). 1730 Request(corev1.ResourceCPU, "1"). 1731 Obj(), 1732 ). 1733 Queue("user-queue"). 1734 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1735 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1736 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1737 Admitted(true). 1738 Obj(), 1739 }, 1740 workloadCmpOpts: defaultWorkloadCmpOpts, 1741 }, 1742 "workload is not deleted if one pod role is absent from the cluster": { 1743 pods: []corev1.Pod{ 1744 *basePodWrapper. 1745 Clone(). 1746 Label("kueue.x-k8s.io/managed", "true"). 1747 KueueFinalizer(). 1748 Group("test-group"). 1749 GroupTotalCount("2"). 1750 Delete(). 1751 Obj(), 1752 }, 1753 wantPods: []corev1.Pod{ 1754 *basePodWrapper. 1755 Clone(). 1756 Label("kueue.x-k8s.io/managed", "true"). 1757 KueueFinalizer(). 1758 Group("test-group"). 1759 GroupTotalCount("2"). 1760 Delete(). 1761 Obj(), 1762 }, 1763 workloads: []kueue.Workload{ 1764 *utiltesting.MakeWorkload("test-group", "ns"). 1765 PodSets( 1766 *utiltesting.MakePodSet("absent-pod-role", 1). 1767 Request(corev1.ResourceCPU, "1"). 1768 Obj(), 1769 *utiltesting.MakePodSet("dc85db45", 1). 1770 Request(corev1.ResourceCPU, "1"). 1771 Obj(), 1772 ). 1773 Queue("user-queue"). 1774 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1775 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1776 Admitted(true). 1777 Obj(), 1778 }, 1779 wantWorkloads: []kueue.Workload{ 1780 *utiltesting.MakeWorkload("test-group", "ns"). 1781 PodSets( 1782 *utiltesting.MakePodSet("absent-pod-role", 1). 1783 Request(corev1.ResourceCPU, "1"). 1784 Obj(), 1785 *utiltesting.MakePodSet("dc85db45", 1). 1786 Request(corev1.ResourceCPU, "1"). 1787 Obj(), 1788 ). 1789 Queue("user-queue"). 1790 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 1791 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1792 Admitted(true). 1793 Obj(), 1794 }, 1795 workloadCmpOpts: defaultWorkloadCmpOpts, 1796 }, 1797 "if pod group is finished and wl is deleted, new workload shouldn't be created": { 1798 pods: []corev1.Pod{ 1799 *basePodWrapper. 1800 Clone(). 1801 Label("kueue.x-k8s.io/managed", "true"). 1802 KueueFinalizer(). 1803 Group("test-group"). 1804 GroupTotalCount("2"). 1805 StatusPhase(corev1.PodSucceeded). 1806 Obj(), 1807 *basePodWrapper. 1808 Clone(). 1809 Name("pod2"). 1810 Label("kueue.x-k8s.io/managed", "true"). 1811 KueueFinalizer(). 1812 Group("test-group"). 1813 GroupTotalCount("2"). 1814 StatusPhase(corev1.PodSucceeded). 1815 Obj(), 1816 }, 1817 wantPods: []corev1.Pod{ 1818 *basePodWrapper. 1819 Clone(). 1820 Label("kueue.x-k8s.io/managed", "true"). 1821 Group("test-group"). 1822 GroupTotalCount("2"). 1823 StatusPhase(corev1.PodSucceeded). 1824 Obj(), 1825 *basePodWrapper. 1826 Clone(). 1827 Name("pod2"). 1828 Label("kueue.x-k8s.io/managed", "true"). 1829 Group("test-group"). 1830 GroupTotalCount("2"). 1831 StatusPhase(corev1.PodSucceeded). 1832 Obj(), 1833 }, 1834 workloads: []kueue.Workload{}, 1835 wantWorkloads: []kueue.Workload{}, 1836 workloadCmpOpts: defaultWorkloadCmpOpts, 1837 }, 1838 "if pod in group is scheduling gated and wl is deleted, workload should be recreated": { 1839 pods: []corev1.Pod{ 1840 *basePodWrapper. 1841 Clone(). 1842 Label("kueue.x-k8s.io/managed", "true"). 1843 KueueFinalizer(). 1844 KueueSchedulingGate(). 1845 Group("test-group"). 1846 GroupTotalCount("2"). 1847 Obj(), 1848 *basePodWrapper. 1849 Clone(). 1850 Name("pod2"). 1851 Label("kueue.x-k8s.io/managed", "true"). 1852 KueueFinalizer(). 1853 Group("test-group"). 1854 GroupTotalCount("2"). 1855 StatusPhase(corev1.PodSucceeded). 1856 Obj(), 1857 }, 1858 wantPods: []corev1.Pod{ 1859 *basePodWrapper. 1860 Clone(). 1861 Label("kueue.x-k8s.io/managed", "true"). 1862 KueueFinalizer(). 1863 KueueSchedulingGate(). 1864 Group("test-group"). 1865 GroupTotalCount("2"). 1866 Obj(), 1867 *basePodWrapper. 1868 Clone(). 1869 Name("pod2"). 1870 Label("kueue.x-k8s.io/managed", "true"). 1871 KueueFinalizer(). 1872 Group("test-group"). 1873 GroupTotalCount("2"). 1874 StatusPhase(corev1.PodSucceeded). 1875 Obj(), 1876 }, 1877 workloads: []kueue.Workload{}, 1878 wantWorkloads: []kueue.Workload{ 1879 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 1880 PodSets( 1881 *utiltesting.MakePodSet("dc85db45", 2). 1882 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 1883 Request(corev1.ResourceCPU, "1"). 1884 Obj(), 1885 ). 1886 Queue("user-queue"). 1887 Priority(0). 1888 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 1889 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 1890 Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}). 1891 Obj(), 1892 }, 1893 workloadCmpOpts: defaultWorkloadCmpOpts, 1894 wantEvents: []utiltesting.EventRecord{ 1895 { 1896 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 1897 EventType: "Normal", 1898 Reason: "CreatedWorkload", 1899 Message: "Created Workload: ns/test-group", 1900 }, 1901 }, 1902 }, 1903 "if there's not enough non-failed pods in the group, workload should not be created": { 1904 pods: []corev1.Pod{ 1905 *basePodWrapper. 1906 Clone(). 1907 Label("kueue.x-k8s.io/managed", "true"). 1908 KueueFinalizer(). 1909 KueueSchedulingGate(). 1910 Group("test-group"). 1911 GroupTotalCount("2"). 1912 Obj(), 1913 *basePodWrapper. 1914 Clone(). 1915 Name("pod2"). 1916 Label("kueue.x-k8s.io/managed", "true"). 1917 KueueFinalizer(). 1918 Group("test-group"). 1919 GroupTotalCount("2"). 1920 StatusPhase(corev1.PodFailed). 1921 Obj(), 1922 }, 1923 wantPods: []corev1.Pod{ 1924 *basePodWrapper. 1925 Clone(). 1926 Label("kueue.x-k8s.io/managed", "true"). 1927 KueueFinalizer(). 1928 KueueSchedulingGate(). 1929 Group("test-group"). 1930 GroupTotalCount("2"). 1931 Obj(), 1932 *basePodWrapper. 1933 Clone(). 1934 Name("pod2"). 1935 Label("kueue.x-k8s.io/managed", "true"). 1936 Group("test-group"). 1937 GroupTotalCount("2"). 1938 StatusPhase(corev1.PodFailed). 1939 Obj(), 1940 }, 1941 workloads: []kueue.Workload{}, 1942 wantWorkloads: []kueue.Workload{}, 1943 workloadCmpOpts: defaultWorkloadCmpOpts, 1944 wantEvents: []utiltesting.EventRecord{ 1945 { 1946 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 1947 EventType: "Warning", 1948 Reason: "ErrWorkloadCompose", 1949 Message: "'test-group' group has fewer runnable pods than expected", 1950 }, 1951 }, 1952 }, 1953 "pod group is considered finished if there is an unretriable pod and no running pods": { 1954 pods: []corev1.Pod{ 1955 *basePodWrapper. 1956 Clone(). 1957 Annotation("kueue.x-k8s.io/retriable-in-group", "false"). 1958 Label("kueue.x-k8s.io/managed", "true"). 1959 KueueFinalizer(). 1960 Group("test-group"). 1961 GroupTotalCount("3"). 1962 StatusPhase(corev1.PodFailed). 1963 Obj(), 1964 *basePodWrapper. 1965 Clone(). 1966 Name("pod2"). 1967 Label("kueue.x-k8s.io/managed", "true"). 1968 KueueFinalizer(). 1969 Group("test-group"). 1970 GroupTotalCount("3"). 1971 StatusPhase(corev1.PodSucceeded). 1972 Obj(), 1973 *basePodWrapper. 1974 Clone(). 1975 Name("pod3"). 1976 Label("kueue.x-k8s.io/managed", "true"). 1977 KueueFinalizer(). 1978 Group("test-group"). 1979 Request(corev1.ResourceMemory, "1Gi"). 1980 GroupTotalCount("3"). 1981 StatusPhase(corev1.PodFailed). 1982 Obj(), 1983 }, 1984 wantPods: []corev1.Pod{ 1985 *basePodWrapper. 1986 Clone(). 1987 Annotation("kueue.x-k8s.io/retriable-in-group", "false"). 1988 Label("kueue.x-k8s.io/managed", "true"). 1989 Group("test-group"). 1990 GroupTotalCount("3"). 1991 StatusPhase(corev1.PodFailed). 1992 Obj(), 1993 *basePodWrapper. 1994 Clone(). 1995 Name("pod2"). 1996 Label("kueue.x-k8s.io/managed", "true"). 1997 Group("test-group"). 1998 GroupTotalCount("3"). 1999 StatusPhase(corev1.PodSucceeded). 2000 Obj(), 2001 *basePodWrapper. 2002 Clone(). 2003 Name("pod3"). 2004 Label("kueue.x-k8s.io/managed", "true"). 2005 Group("test-group"). 2006 Request(corev1.ResourceMemory, "1Gi"). 2007 GroupTotalCount("3"). 2008 StatusPhase(corev1.PodFailed). 2009 Obj(), 2010 }, 2011 workloads: []kueue.Workload{ 2012 *utiltesting.MakeWorkload("test-group", "ns"). 2013 PodSets( 2014 *utiltesting.MakePodSet("a119f908", 1). 2015 Request(corev1.ResourceCPU, "1"). 2016 Request(corev1.ResourceMemory, "1Gi"). 2017 Obj(), 2018 *utiltesting.MakePodSet("dc85db45", 2). 2019 Request(corev1.ResourceCPU, "1"). 2020 Obj(), 2021 ). 2022 Queue("user-queue"). 2023 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2024 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2025 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2026 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2027 Admitted(true). 2028 Obj(), 2029 }, 2030 wantWorkloads: []kueue.Workload{ 2031 *utiltesting.MakeWorkload("test-group", "ns"). 2032 PodSets( 2033 *utiltesting.MakePodSet("a119f908", 1). 2034 Request(corev1.ResourceCPU, "1"). 2035 Request(corev1.ResourceMemory, "1Gi"). 2036 Obj(), 2037 *utiltesting.MakePodSet("dc85db45", 2). 2038 Request(corev1.ResourceCPU, "1"). 2039 Obj(), 2040 ). 2041 Queue("user-queue"). 2042 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2043 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2044 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2045 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2046 Admitted(true). 2047 Condition( 2048 metav1.Condition{ 2049 Type: kueue.WorkloadFinished, 2050 Status: metav1.ConditionTrue, 2051 Reason: "JobFinished", 2052 Message: "Pods succeeded: 1/3.", 2053 }, 2054 ). 2055 Obj(), 2056 }, 2057 workloadCmpOpts: defaultWorkloadCmpOpts, 2058 wantEvents: []utiltesting.EventRecord{ 2059 { 2060 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 2061 EventType: "Normal", 2062 Reason: "FinishedWorkload", 2063 Message: "Workload 'ns/test-group' is declared finished", 2064 }, 2065 }, 2066 }, 2067 "reclaimable pods updated for pod group": { 2068 pods: []corev1.Pod{ 2069 *basePodWrapper. 2070 Clone(). 2071 Label("kueue.x-k8s.io/managed", "true"). 2072 KueueFinalizer(). 2073 Group("test-group"). 2074 GroupTotalCount("3"). 2075 StatusPhase(corev1.PodFailed). 2076 Obj(), 2077 *basePodWrapper. 2078 Clone(). 2079 Name("pod2"). 2080 Label("kueue.x-k8s.io/managed", "true"). 2081 KueueFinalizer(). 2082 Group("test-group"). 2083 GroupTotalCount("3"). 2084 StatusPhase(corev1.PodRunning). 2085 Obj(), 2086 *basePodWrapper. 2087 Clone(). 2088 Name("pod3"). 2089 Label("kueue.x-k8s.io/managed", "true"). 2090 KueueFinalizer(). 2091 Group("test-group"). 2092 Request(corev1.ResourceMemory, "1Gi"). 2093 GroupTotalCount("3"). 2094 StatusPhase(corev1.PodSucceeded). 2095 Obj(), 2096 }, 2097 wantPods: []corev1.Pod{ 2098 *basePodWrapper. 2099 Clone(). 2100 Label("kueue.x-k8s.io/managed", "true"). 2101 KueueFinalizer(). 2102 Group("test-group"). 2103 GroupTotalCount("3"). 2104 StatusPhase(corev1.PodFailed). 2105 Obj(), 2106 *basePodWrapper. 2107 Clone(). 2108 Name("pod2"). 2109 Label("kueue.x-k8s.io/managed", "true"). 2110 KueueFinalizer(). 2111 Group("test-group"). 2112 GroupTotalCount("3"). 2113 StatusPhase(corev1.PodRunning). 2114 Obj(), 2115 *basePodWrapper. 2116 Clone(). 2117 Name("pod3"). 2118 Label("kueue.x-k8s.io/managed", "true"). 2119 KueueFinalizer(). 2120 Group("test-group"). 2121 Request(corev1.ResourceMemory, "1Gi"). 2122 GroupTotalCount("3"). 2123 StatusPhase(corev1.PodSucceeded). 2124 Obj(), 2125 }, 2126 workloads: []kueue.Workload{ 2127 *utiltesting.MakeWorkload("test-group", "ns"). 2128 PodSets( 2129 *utiltesting.MakePodSet("4ebdd4a6", 1). 2130 Request(corev1.ResourceCPU, "1"). 2131 Request(corev1.ResourceMemory, "1Gi"). 2132 Obj(), 2133 *utiltesting.MakePodSet("dc85db45", 2). 2134 Request(corev1.ResourceCPU, "1"). 2135 Obj(), 2136 ). 2137 Queue("user-queue"). 2138 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2139 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2140 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2141 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2142 Admitted(true). 2143 Obj(), 2144 }, 2145 wantWorkloads: []kueue.Workload{ 2146 *utiltesting.MakeWorkload("test-group", "ns"). 2147 PodSets( 2148 *utiltesting.MakePodSet("4ebdd4a6", 1). 2149 Request(corev1.ResourceCPU, "1"). 2150 Request(corev1.ResourceMemory, "1Gi"). 2151 Obj(), 2152 *utiltesting.MakePodSet("dc85db45", 2). 2153 Request(corev1.ResourceCPU, "1"). 2154 Obj(), 2155 ). 2156 Queue("user-queue"). 2157 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2158 Admitted(true). 2159 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2160 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2161 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2162 ReclaimablePods(kueue.ReclaimablePod{Name: "4ebdd4a6", Count: 1}). 2163 Obj(), 2164 }, 2165 workloadCmpOpts: defaultWorkloadCmpOpts, 2166 }, 2167 "excess pods before wl creation, youngest pods are deleted": { 2168 pods: []corev1.Pod{ 2169 *basePodWrapper. 2170 Clone(). 2171 Label("kueue.x-k8s.io/managed", "true"). 2172 KueueFinalizer(). 2173 KueueSchedulingGate(). 2174 Group("test-group"). 2175 GroupTotalCount("1"). 2176 CreationTimestamp(now). 2177 Obj(), 2178 *basePodWrapper. 2179 Clone(). 2180 Name("pod2"). 2181 Label("kueue.x-k8s.io/managed", "true"). 2182 KueueFinalizer(). 2183 KueueSchedulingGate(). 2184 Group("test-group"). 2185 GroupTotalCount("1"). 2186 CreationTimestamp(now.Add(time.Minute)). 2187 Obj(), 2188 }, 2189 wantPods: []corev1.Pod{ 2190 *basePodWrapper. 2191 Clone(). 2192 Label("kueue.x-k8s.io/managed", "true"). 2193 KueueFinalizer(). 2194 KueueSchedulingGate(). 2195 Group("test-group"). 2196 GroupTotalCount("1"). 2197 CreationTimestamp(now). 2198 Obj(), 2199 }, 2200 workloads: []kueue.Workload{}, 2201 wantWorkloads: []kueue.Workload{ 2202 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 2203 PodSets( 2204 *utiltesting.MakePodSet("dc85db45", 1). 2205 Request(corev1.ResourceCPU, "1"). 2206 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 2207 Obj(), 2208 ). 2209 Queue("user-queue"). 2210 Priority(0). 2211 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2212 Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}). 2213 Obj(), 2214 }, 2215 workloadCmpOpts: defaultWorkloadCmpOpts, 2216 wantEvents: []utiltesting.EventRecord{ 2217 { 2218 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 2219 EventType: "Normal", 2220 Reason: "CreatedWorkload", 2221 Message: "Created Workload: ns/test-group", 2222 }, 2223 { 2224 Key: types.NamespacedName{Name: "pod2", Namespace: "ns"}, 2225 EventType: "Normal", 2226 Reason: "ExcessPodDeleted", 2227 Message: "Excess pod deleted", 2228 }, 2229 }, 2230 }, 2231 "excess pods before admission, youngest pods are deleted": { 2232 pods: []corev1.Pod{ 2233 *basePodWrapper. 2234 Clone(). 2235 Label("kueue.x-k8s.io/managed", "true"). 2236 KueueFinalizer(). 2237 KueueSchedulingGate(). 2238 Group("test-group"). 2239 GroupTotalCount("2"). 2240 CreationTimestamp(now). 2241 Obj(), 2242 *basePodWrapper. 2243 Clone(). 2244 Name("pod2"). 2245 Label("kueue.x-k8s.io/managed", "true"). 2246 KueueFinalizer(). 2247 KueueSchedulingGate(). 2248 Group("test-group"). 2249 GroupTotalCount("2"). 2250 CreationTimestamp(now.Add(time.Minute)). 2251 Obj(), 2252 *basePodWrapper. 2253 Clone(). 2254 Name("pod3"). 2255 Label("kueue.x-k8s.io/managed", "true"). 2256 KueueFinalizer(). 2257 KueueSchedulingGate(). 2258 Group("test-group"). 2259 CreationTimestamp(now.Add(time.Minute * 2)). 2260 GroupTotalCount("2"). 2261 Obj(), 2262 }, 2263 wantPods: []corev1.Pod{ 2264 *basePodWrapper. 2265 Clone(). 2266 Label("kueue.x-k8s.io/managed", "true"). 2267 KueueFinalizer(). 2268 KueueSchedulingGate(). 2269 Group("test-group"). 2270 GroupTotalCount("2"). 2271 CreationTimestamp(now). 2272 Obj(), 2273 *basePodWrapper. 2274 Clone(). 2275 Name("pod2"). 2276 Label("kueue.x-k8s.io/managed", "true"). 2277 KueueFinalizer(). 2278 KueueSchedulingGate(). 2279 Group("test-group"). 2280 GroupTotalCount("2"). 2281 CreationTimestamp(now.Add(time.Minute)). 2282 Obj(), 2283 }, 2284 workloads: []kueue.Workload{ 2285 *utiltesting.MakeWorkload("test-group", "ns"). 2286 PodSets( 2287 *utiltesting.MakePodSet("dc85db45", 2). 2288 Request(corev1.ResourceCPU, "1"). 2289 Obj(), 2290 ). 2291 Queue("user-queue"). 2292 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2293 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2294 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2295 Obj(), 2296 }, 2297 wantWorkloads: []kueue.Workload{ 2298 *utiltesting.MakeWorkload("test-group", "ns"). 2299 PodSets( 2300 *utiltesting.MakePodSet("dc85db45", 2). 2301 Request(corev1.ResourceCPU, "1"). 2302 Obj(), 2303 ). 2304 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2305 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2306 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2307 Queue("user-queue"). 2308 Obj(), 2309 }, 2310 workloadCmpOpts: defaultWorkloadCmpOpts, 2311 wantEvents: []utiltesting.EventRecord{ 2312 { 2313 Key: types.NamespacedName{Name: "pod3", Namespace: "ns"}, 2314 EventType: "Normal", 2315 Reason: "ExcessPodDeleted", 2316 Message: "Excess pod deleted", 2317 }, 2318 }, 2319 }, 2320 // In this case, group-total-count is equal to the number of pods in the cluster. 2321 // But one of the roles is missing, and another role has an excess pod. 2322 "excess pods in pod set after admission, youngest pods are deleted": { 2323 pods: []corev1.Pod{ 2324 *basePodWrapper. 2325 Clone(). 2326 Label("kueue.x-k8s.io/managed", "true"). 2327 KueueFinalizer(). 2328 Group("test-group"). 2329 GroupTotalCount("2"). 2330 CreationTimestamp(now). 2331 Obj(), 2332 *basePodWrapper. 2333 Clone(). 2334 Name("pod2"). 2335 Label("kueue.x-k8s.io/managed", "true"). 2336 KueueFinalizer(). 2337 KueueSchedulingGate(). 2338 Group("test-group"). 2339 CreationTimestamp(now.Add(time.Minute * 2)). 2340 GroupTotalCount("2"). 2341 Obj(), 2342 }, 2343 wantPods: []corev1.Pod{ 2344 *basePodWrapper. 2345 Clone(). 2346 Label("kueue.x-k8s.io/managed", "true"). 2347 KueueFinalizer(). 2348 Group("test-group"). 2349 GroupTotalCount("2"). 2350 CreationTimestamp(now). 2351 Obj(), 2352 }, 2353 workloads: []kueue.Workload{ 2354 *utiltesting.MakeWorkload("test-group", "ns"). 2355 PodSets( 2356 *utiltesting.MakePodSet("aaf269e6", 1). 2357 Request(corev1.ResourceCPU, "1"). 2358 Obj(), 2359 *utiltesting.MakePodSet("dc85db45", 1). 2360 Request(corev1.ResourceCPU, "1"). 2361 Obj(), 2362 ). 2363 Queue("user-queue"). 2364 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2365 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2366 Admitted(true). 2367 Obj(), 2368 }, 2369 wantWorkloads: []kueue.Workload{ 2370 *utiltesting.MakeWorkload("test-group", "ns"). 2371 PodSets( 2372 *utiltesting.MakePodSet("aaf269e6", 1). 2373 Request(corev1.ResourceCPU, "1"). 2374 Obj(), 2375 *utiltesting.MakePodSet("dc85db45", 1). 2376 Request(corev1.ResourceCPU, "1"). 2377 Obj(), 2378 ). 2379 Queue("user-queue"). 2380 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2381 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2382 Admitted(true). 2383 Obj(), 2384 }, 2385 workloadCmpOpts: defaultWorkloadCmpOpts, 2386 excessPodsExpectations: []keyUIDs{{ 2387 key: types.NamespacedName{Name: "another-group", Namespace: "ns"}, 2388 uids: []types.UID{"pod"}, 2389 }}, 2390 wantEvents: []utiltesting.EventRecord{ 2391 { 2392 Key: types.NamespacedName{Name: "pod2", Namespace: "ns"}, 2393 EventType: "Normal", 2394 Reason: "ExcessPodDeleted", 2395 Message: "Excess pod deleted", 2396 }, 2397 }, 2398 }, 2399 "waiting to observe previous deletion of excess pod, no pods are deleted": { 2400 pods: []corev1.Pod{ 2401 *basePodWrapper. 2402 Clone(). 2403 Label("kueue.x-k8s.io/managed", "true"). 2404 KueueFinalizer(). 2405 Group("test-group"). 2406 GroupTotalCount("1"). 2407 CreationTimestamp(now). 2408 Obj(), 2409 *basePodWrapper. 2410 Clone(). 2411 Name("pod2"). 2412 UID("pod2"). 2413 Label("kueue.x-k8s.io/managed", "true"). 2414 KueueFinalizer(). 2415 KueueSchedulingGate(). 2416 Group("test-group"). 2417 CreationTimestamp(now.Add(time.Minute)). 2418 GroupTotalCount("1"). 2419 Obj(), 2420 *basePodWrapper. 2421 Clone(). 2422 Name("pod3"). 2423 Label("kueue.x-k8s.io/managed", "true"). 2424 KueueFinalizer(). 2425 KueueSchedulingGate(). 2426 Group("test-group"). 2427 CreationTimestamp(now.Add(time.Minute)). 2428 GroupTotalCount("1"). 2429 Obj(), 2430 }, 2431 wantPods: []corev1.Pod{ 2432 *basePodWrapper. 2433 Clone(). 2434 Label("kueue.x-k8s.io/managed", "true"). 2435 KueueFinalizer(). 2436 Group("test-group"). 2437 GroupTotalCount("1"). 2438 CreationTimestamp(now). 2439 Obj(), 2440 *basePodWrapper. 2441 Clone(). 2442 Name("pod2"). 2443 UID("pod2"). 2444 Label("kueue.x-k8s.io/managed", "true"). 2445 KueueFinalizer(). 2446 KueueSchedulingGate(). 2447 Group("test-group"). 2448 CreationTimestamp(now.Add(time.Minute)). 2449 GroupTotalCount("1"). 2450 Obj(), 2451 *basePodWrapper. 2452 Clone(). 2453 Name("pod3"). 2454 Label("kueue.x-k8s.io/managed", "true"). 2455 KueueFinalizer(). 2456 KueueSchedulingGate(). 2457 Group("test-group"). 2458 CreationTimestamp(now.Add(time.Minute)). 2459 GroupTotalCount("1"). 2460 Obj(), 2461 }, 2462 workloads: []kueue.Workload{ 2463 *utiltesting.MakeWorkload("test-group", "ns"). 2464 PodSets( 2465 *utiltesting.MakePodSet("dc85db45", 1). 2466 Request(corev1.ResourceCPU, "1"). 2467 Obj(), 2468 ). 2469 Queue("user-queue"). 2470 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2471 Admitted(true). 2472 Obj(), 2473 }, 2474 wantWorkloads: []kueue.Workload{ 2475 *utiltesting.MakeWorkload("test-group", "ns"). 2476 PodSets( 2477 *utiltesting.MakePodSet("dc85db45", 1). 2478 Request(corev1.ResourceCPU, "1"). 2479 Obj(), 2480 ). 2481 Queue("user-queue"). 2482 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2483 Admitted(true). 2484 Obj(), 2485 }, 2486 workloadCmpOpts: defaultWorkloadCmpOpts, 2487 excessPodsExpectations: []keyUIDs{{ 2488 key: types.NamespacedName{Name: "test-group", Namespace: "ns"}, 2489 uids: []types.UID{"pod2"}, 2490 }}, 2491 }, 2492 "delete excess pod that is gated": { 2493 pods: []corev1.Pod{ 2494 *basePodWrapper. 2495 Clone(). 2496 Label("kueue.x-k8s.io/managed", "true"). 2497 KueueFinalizer(). 2498 Group("test-group"). 2499 GroupTotalCount("2"). 2500 CreationTimestamp(now). 2501 Obj(), 2502 *basePodWrapper. 2503 Clone(). 2504 Name("pod2"). 2505 UID("pod2"). 2506 Label("kueue.x-k8s.io/managed", "true"). 2507 KueueFinalizer(). 2508 Group("test-group"). 2509 CreationTimestamp(now.Add(time.Minute)). 2510 GroupTotalCount("2"). 2511 Obj(), 2512 *basePodWrapper. 2513 Clone(). 2514 Name("pod3"). 2515 Label("kueue.x-k8s.io/managed", "true"). 2516 KueueFinalizer(). 2517 KueueSchedulingGate(). 2518 Group("test-group"). 2519 CreationTimestamp(now.Add(time.Minute)). 2520 GroupTotalCount("2"). 2521 Obj(), 2522 }, 2523 wantPods: []corev1.Pod{ 2524 *basePodWrapper. 2525 Clone(). 2526 Label("kueue.x-k8s.io/managed", "true"). 2527 KueueFinalizer(). 2528 Group("test-group"). 2529 GroupTotalCount("2"). 2530 CreationTimestamp(now). 2531 Obj(), 2532 *basePodWrapper. 2533 Clone(). 2534 Name("pod2"). 2535 UID("pod2"). 2536 Label("kueue.x-k8s.io/managed", "true"). 2537 KueueFinalizer(). 2538 Group("test-group"). 2539 CreationTimestamp(now.Add(time.Minute)). 2540 GroupTotalCount("2"). 2541 Obj(), 2542 }, 2543 workloads: []kueue.Workload{ 2544 *utiltesting.MakeWorkload("test-group", "ns"). 2545 PodSets( 2546 *utiltesting.MakePodSet("dc85db45", 2). 2547 Request(corev1.ResourceCPU, "1"). 2548 Obj(), 2549 ). 2550 Queue("user-queue"). 2551 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2552 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "pod2"). 2553 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2554 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2555 Admitted(true). 2556 Obj(), 2557 }, 2558 wantWorkloads: []kueue.Workload{ 2559 *utiltesting.MakeWorkload("test-group", "ns"). 2560 PodSets( 2561 *utiltesting.MakePodSet("dc85db45", 2). 2562 Request(corev1.ResourceCPU, "1"). 2563 Obj(), 2564 ). 2565 Queue("user-queue"). 2566 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2567 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "pod2"). 2568 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2569 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2570 Admitted(true). 2571 Obj(), 2572 }, 2573 workloadCmpOpts: defaultWorkloadCmpOpts, 2574 wantEvents: []utiltesting.EventRecord{ 2575 { 2576 Key: types.NamespacedName{Name: "pod3", Namespace: "ns"}, 2577 EventType: "Normal", 2578 Reason: "ExcessPodDeleted", 2579 Message: "Excess pod deleted", 2580 }, 2581 }, 2582 }, 2583 // If an excess pod is already deleted and finalized, but an external finalizer blocks 2584 // pod deletion, kueue should ignore such a pod, when creating a workload. 2585 "deletion of excess pod is blocked by another controller": { 2586 pods: []corev1.Pod{ 2587 *basePodWrapper. 2588 Clone(). 2589 Label("kueue.x-k8s.io/managed", "true"). 2590 KueueFinalizer(). 2591 KueueSchedulingGate(). 2592 Group("test-group"). 2593 GroupTotalCount("1"). 2594 CreationTimestamp(now). 2595 Obj(), 2596 *basePodWrapper. 2597 Clone(). 2598 Name("pod2"). 2599 Label("kueue.x-k8s.io/managed", "true"). 2600 KueueSchedulingGate(). 2601 Finalizer("kubernetes"). 2602 Group("test-group"). 2603 GroupTotalCount("1"). 2604 CreationTimestamp(now.Add(time.Minute)). 2605 Delete(). 2606 Obj(), 2607 }, 2608 wantPods: []corev1.Pod{ 2609 *basePodWrapper. 2610 Clone(). 2611 Label("kueue.x-k8s.io/managed", "true"). 2612 KueueFinalizer(). 2613 KueueSchedulingGate(). 2614 Group("test-group"). 2615 GroupTotalCount("1"). 2616 CreationTimestamp(now). 2617 Obj(), 2618 *basePodWrapper. 2619 Clone(). 2620 Name("pod2"). 2621 Label("kueue.x-k8s.io/managed", "true"). 2622 KueueSchedulingGate(). 2623 Finalizer("kubernetes"). 2624 Group("test-group"). 2625 GroupTotalCount("1"). 2626 CreationTimestamp(now.Add(time.Minute)). 2627 Delete(). 2628 Obj(), 2629 }, 2630 workloads: []kueue.Workload{}, 2631 wantWorkloads: []kueue.Workload{ 2632 *utiltesting.MakeWorkload("test-group", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 2633 PodSets( 2634 *utiltesting.MakePodSet("dc85db45", 1). 2635 Request(corev1.ResourceCPU, "1"). 2636 SchedulingGates(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}). 2637 Obj(), 2638 ). 2639 Queue("user-queue"). 2640 Priority(0). 2641 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 2642 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2643 Annotations(map[string]string{"kueue.x-k8s.io/is-group-workload": "true"}). 2644 Obj(), 2645 }, 2646 workloadCmpOpts: defaultWorkloadCmpOpts, 2647 wantEvents: []utiltesting.EventRecord{ 2648 { 2649 Key: types.NamespacedName{Name: "pod", Namespace: "ns"}, 2650 EventType: "Normal", 2651 Reason: "CreatedWorkload", 2652 Message: "Created Workload: ns/test-group", 2653 }, 2654 }, 2655 }, 2656 "deleted pods in incomplete group are finalized": { 2657 pods: []corev1.Pod{ 2658 *basePodWrapper. 2659 Clone(). 2660 Name("p1"). 2661 Label("kueue.x-k8s.io/managed", "true"). 2662 KueueFinalizer(). 2663 KueueSchedulingGate(). 2664 Group("group"). 2665 GroupTotalCount("3"). 2666 StatusPhase(corev1.PodPending). 2667 Delete(). 2668 Obj(), 2669 *basePodWrapper. 2670 Clone(). 2671 Name("p2"). 2672 Label("kueue.x-k8s.io/managed", "true"). 2673 KueueFinalizer(). 2674 KueueSchedulingGate(). 2675 Group("group"). 2676 GroupTotalCount("3"). 2677 StatusPhase(corev1.PodPending). 2678 Delete(). 2679 Obj(), 2680 }, 2681 wantEvents: []utiltesting.EventRecord{ 2682 { 2683 Key: types.NamespacedName{Name: "p1", Namespace: "ns"}, 2684 EventType: "Warning", 2685 Reason: "ErrWorkloadCompose", 2686 Message: "'group' group has fewer runnable pods than expected", 2687 }, 2688 }, 2689 }, 2690 "finalize workload for non existent pod": { 2691 reconcileKey: &types.NamespacedName{Namespace: "ns", Name: "deleted_pod"}, 2692 workloads: []kueue.Workload{ 2693 *utiltesting.MakeWorkload("test-group", "ns"). 2694 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted_pod", ""). 2695 Finalizers(kueue.ResourceInUseFinalizerName). 2696 Obj(), 2697 }, 2698 wantWorkloads: []kueue.Workload{ 2699 *utiltesting.MakeWorkload("test-group", "ns"). 2700 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted_pod", ""). 2701 Obj(), 2702 }, 2703 workloadCmpOpts: defaultWorkloadCmpOpts, 2704 }, 2705 "replacement pods are owning the workload": { 2706 pods: []corev1.Pod{ 2707 *basePodWrapper. 2708 Clone(). 2709 Name("pod1"). 2710 Label("kueue.x-k8s.io/managed", "true"). 2711 Group("test-group"). 2712 GroupTotalCount("2"). 2713 StatusPhase(corev1.PodFailed). 2714 Obj(), 2715 *basePodWrapper. 2716 Clone(). 2717 Name("pod2"). 2718 Label("kueue.x-k8s.io/managed", "true"). 2719 KueueFinalizer(). 2720 Delete(). 2721 Group("test-group"). 2722 GroupTotalCount("2"). 2723 Obj(), 2724 *basePodWrapper. 2725 Clone(). 2726 Name("replacement-for-pod1"). 2727 Label("kueue.x-k8s.io/managed", "true"). 2728 KueueFinalizer(). 2729 Group("test-group"). 2730 GroupTotalCount("2"). 2731 Obj(), 2732 }, 2733 wantPods: []corev1.Pod{ 2734 *basePodWrapper. 2735 Clone(). 2736 Name("pod1"). 2737 Label("kueue.x-k8s.io/managed", "true"). 2738 Group("test-group"). 2739 GroupTotalCount("2"). 2740 StatusPhase(corev1.PodFailed). 2741 Obj(), 2742 *basePodWrapper. 2743 Clone(). 2744 Name("pod2"). 2745 Label("kueue.x-k8s.io/managed", "true"). 2746 KueueFinalizer(). 2747 Delete(). 2748 Group("test-group"). 2749 GroupTotalCount("2"). 2750 Obj(), 2751 *basePodWrapper. 2752 Clone(). 2753 Name("replacement-for-pod1"). 2754 Label("kueue.x-k8s.io/managed", "true"). 2755 KueueFinalizer(). 2756 Group("test-group"). 2757 GroupTotalCount("2"). 2758 Obj(), 2759 }, 2760 workloads: []kueue.Workload{ 2761 *utiltesting.MakeWorkload("test-group", "ns"). 2762 PodSets( 2763 *utiltesting.MakePodSet("dc85db45", 3). 2764 Request(corev1.ResourceCPU, "1"). 2765 Obj(), 2766 ). 2767 Queue("user-queue"). 2768 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid"). 2769 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2770 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2771 Admitted(true). 2772 Obj(), 2773 }, 2774 wantWorkloads: []kueue.Workload{ 2775 *utiltesting.MakeWorkload("test-group", "ns"). 2776 PodSets( 2777 *utiltesting.MakePodSet("dc85db45", 3). 2778 Request(corev1.ResourceCPU, "1"). 2779 Obj(), 2780 ). 2781 Queue("user-queue"). 2782 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid"). 2783 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2784 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement-for-pod1", "test-uid"). 2785 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 2786 Admitted(true). 2787 Obj(), 2788 }, 2789 workloadCmpOpts: defaultWorkloadCmpOpts, 2790 wantEvents: []utiltesting.EventRecord{ 2791 { 2792 Key: types.NamespacedName{Name: "test-group", Namespace: "ns"}, 2793 EventType: "Normal", 2794 Reason: "OwnerReferencesAdded", 2795 Message: "Added 1 owner reference(s)", 2796 }, 2797 }, 2798 }, 2799 "all pods in a group should receive the event about preemption, unless already terminating": { 2800 pods: []corev1.Pod{ 2801 *basePodWrapper. 2802 Clone(). 2803 Name("pod1"). 2804 Label("kueue.x-k8s.io/managed", "true"). 2805 KueueFinalizer(). 2806 Group("test-group"). 2807 GroupTotalCount("3"). 2808 Obj(), 2809 *basePodWrapper. 2810 Clone(). 2811 Name("pod2"). 2812 Label("kueue.x-k8s.io/managed", "true"). 2813 KueueFinalizer(). 2814 Delete(). 2815 Group("test-group"). 2816 GroupTotalCount("3"). 2817 Obj(), 2818 *basePodWrapper. 2819 Clone(). 2820 Name("pod3"). 2821 Label("kueue.x-k8s.io/managed", "true"). 2822 KueueFinalizer(). 2823 Group("test-group"). 2824 GroupTotalCount("3"). 2825 Obj(), 2826 }, 2827 wantPods: []corev1.Pod{ 2828 *basePodWrapper. 2829 Clone(). 2830 Name("pod1"). 2831 Label("kueue.x-k8s.io/managed", "true"). 2832 KueueFinalizer(). 2833 Group("test-group"). 2834 GroupTotalCount("3"). 2835 StatusConditions(corev1.PodCondition{ 2836 Type: "TerminationTarget", 2837 Status: corev1.ConditionTrue, 2838 Reason: "StoppedByKueue", 2839 Message: "Preempted to accommodate a higher priority Workload", 2840 }). 2841 Obj(), 2842 *basePodWrapper. 2843 Clone(). 2844 Name("pod2"). 2845 Label("kueue.x-k8s.io/managed", "true"). 2846 KueueFinalizer(). 2847 Delete(). 2848 Group("test-group"). 2849 GroupTotalCount("3"). 2850 Obj(), 2851 *basePodWrapper. 2852 Clone(). 2853 Name("pod3"). 2854 Label("kueue.x-k8s.io/managed", "true"). 2855 KueueFinalizer(). 2856 Group("test-group"). 2857 GroupTotalCount("3"). 2858 StatusConditions(corev1.PodCondition{ 2859 Type: "TerminationTarget", 2860 Status: corev1.ConditionTrue, 2861 Reason: "StoppedByKueue", 2862 Message: "Preempted to accommodate a higher priority Workload", 2863 }). 2864 Obj(), 2865 }, 2866 workloads: []kueue.Workload{ 2867 *utiltesting.MakeWorkload("test-group", "ns"). 2868 PodSets( 2869 *utiltesting.MakePodSet("dc85db45", 3). 2870 Request(corev1.ResourceCPU, "1"). 2871 Obj(), 2872 ). 2873 Queue("user-queue"). 2874 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid"). 2875 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2876 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2877 Condition(metav1.Condition{ 2878 Type: kueue.WorkloadEvicted, 2879 Status: metav1.ConditionTrue, 2880 LastTransitionTime: metav1.Now(), 2881 Reason: "Preempted", 2882 Message: "Preempted to accommodate a higher priority Workload", 2883 }). 2884 Obj(), 2885 }, 2886 wantWorkloads: []kueue.Workload{ 2887 *utiltesting.MakeWorkload("test-group", "ns"). 2888 PodSets( 2889 *utiltesting.MakePodSet("dc85db45", 3). 2890 Request(corev1.ResourceCPU, "1"). 2891 Obj(), 2892 ). 2893 Queue("user-queue"). 2894 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod1", "test-uid"). 2895 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod2", "test-uid"). 2896 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod3", "test-uid"). 2897 Condition(metav1.Condition{ 2898 Type: kueue.WorkloadEvicted, 2899 Status: metav1.ConditionTrue, 2900 LastTransitionTime: metav1.Now(), 2901 Reason: "Preempted", 2902 Message: "Preempted to accommodate a higher priority Workload", 2903 }). 2904 Obj(), 2905 }, 2906 workloadCmpOpts: defaultWorkloadCmpOpts, 2907 wantEvents: []utiltesting.EventRecord{ 2908 { 2909 Key: types.NamespacedName{Name: "pod1", Namespace: "ns"}, 2910 EventType: "Normal", 2911 Reason: "Stopped", 2912 Message: "Preempted to accommodate a higher priority Workload", 2913 }, 2914 { 2915 Key: types.NamespacedName{Name: "pod3", Namespace: "ns"}, 2916 EventType: "Normal", 2917 Reason: "Stopped", 2918 Message: "Preempted to accommodate a higher priority Workload", 2919 }, 2920 }, 2921 }, 2922 "the failed pods are finalized in order": { 2923 pods: []corev1.Pod{ 2924 *basePodWrapper. 2925 Clone(). 2926 Name("active-pod"). 2927 Label("kueue.x-k8s.io/managed", "true"). 2928 KueueFinalizer(). 2929 Group("test-group"). 2930 GroupTotalCount("4"). 2931 Obj(), 2932 *basePodWrapper. 2933 Clone(). 2934 Name("finished-with-error"). 2935 Label("kueue.x-k8s.io/managed", "true"). 2936 KueueFinalizer(). 2937 Group("test-group"). 2938 GroupTotalCount("4"). 2939 StatusPhase(corev1.PodFailed). 2940 StatusConditions(corev1.PodCondition{ 2941 Type: corev1.ContainersReady, 2942 Status: corev1.ConditionFalse, 2943 Reason: string(corev1.PodFailed), 2944 LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(), 2945 }). 2946 Obj(), 2947 *basePodWrapper. 2948 Clone(). 2949 Name("deleted"). 2950 Label("kueue.x-k8s.io/managed", "true"). 2951 KueueFinalizer(). 2952 Group("test-group"). 2953 GroupTotalCount("4"). 2954 StatusPhase(corev1.PodFailed). 2955 DeletionTimestamp(now.Add(-4 * time.Minute)). 2956 StatusConditions(corev1.PodCondition{ 2957 Type: corev1.ContainersReady, 2958 Status: corev1.ConditionFalse, 2959 Reason: string(corev1.PodFailed), 2960 LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(), 2961 }). 2962 Obj(), 2963 *basePodWrapper. 2964 Clone(). 2965 Name("finished-with-error2"). 2966 Label("kueue.x-k8s.io/managed", "true"). 2967 KueueFinalizer(). 2968 Group("test-group"). 2969 GroupTotalCount("4"). 2970 StatusPhase(corev1.PodFailed). 2971 StatusConditions(corev1.PodCondition{ 2972 Type: corev1.ContainersReady, 2973 Status: corev1.ConditionFalse, 2974 Reason: string(corev1.PodFailed), 2975 LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(), 2976 }). 2977 Obj(), 2978 *basePodWrapper. 2979 Clone(). 2980 Name("replacement1"). 2981 Label("kueue.x-k8s.io/managed", "true"). 2982 KueueFinalizer(). 2983 Group("test-group"). 2984 GroupTotalCount("4"). 2985 Obj(), 2986 *basePodWrapper. 2987 Clone(). 2988 Name("replacement2"). 2989 Label("kueue.x-k8s.io/managed", "true"). 2990 KueueFinalizer(). 2991 Group("test-group"). 2992 GroupTotalCount("4"). 2993 Obj(), 2994 }, 2995 wantPods: []corev1.Pod{ 2996 *basePodWrapper. 2997 Clone(). 2998 Name("active-pod"). 2999 Label("kueue.x-k8s.io/managed", "true"). 3000 KueueFinalizer(). 3001 Group("test-group"). 3002 GroupTotalCount("4"). 3003 Obj(), 3004 *basePodWrapper. 3005 Clone(). 3006 Name("finished-with-error"). 3007 Label("kueue.x-k8s.io/managed", "true"). 3008 Group("test-group"). 3009 GroupTotalCount("4"). 3010 StatusPhase(corev1.PodFailed). 3011 StatusConditions(corev1.PodCondition{ 3012 Type: corev1.ContainersReady, 3013 Status: corev1.ConditionFalse, 3014 Reason: string(corev1.PodFailed), 3015 LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(), 3016 }). 3017 Obj(), 3018 *basePodWrapper. 3019 Clone(). 3020 Name("finished-with-error2"). 3021 Label("kueue.x-k8s.io/managed", "true"). 3022 KueueFinalizer(). 3023 Group("test-group"). 3024 GroupTotalCount("4"). 3025 StatusPhase(corev1.PodFailed). 3026 StatusConditions(corev1.PodCondition{ 3027 Type: corev1.ContainersReady, 3028 Status: corev1.ConditionFalse, 3029 Reason: string(corev1.PodFailed), 3030 LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(), 3031 }). 3032 Obj(), 3033 *basePodWrapper. 3034 Clone(). 3035 Name("replacement1"). 3036 Label("kueue.x-k8s.io/managed", "true"). 3037 KueueFinalizer(). 3038 Group("test-group"). 3039 GroupTotalCount("4"). 3040 Obj(), 3041 *basePodWrapper. 3042 Clone(). 3043 Name("replacement2"). 3044 Label("kueue.x-k8s.io/managed", "true"). 3045 KueueFinalizer(). 3046 Group("test-group"). 3047 GroupTotalCount("4"). 3048 Obj(), 3049 }, 3050 workloads: []kueue.Workload{ 3051 *utiltesting.MakeWorkload("test-group", "ns"). 3052 PodSets( 3053 *utiltesting.MakePodSet("dc85db45", 4). 3054 Request(corev1.ResourceCPU, "1"). 3055 Obj(), 3056 ). 3057 Queue("user-queue"). 3058 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid"). 3059 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid"). 3060 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted", "test-uid"). 3061 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error2", "test-uid"). 3062 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3063 Admitted(true). 3064 Obj(), 3065 }, 3066 wantWorkloads: []kueue.Workload{ 3067 *utiltesting.MakeWorkload("test-group", "ns"). 3068 PodSets( 3069 *utiltesting.MakePodSet("dc85db45", 4). 3070 Request(corev1.ResourceCPU, "1"). 3071 Obj(), 3072 ). 3073 Queue("user-queue"). 3074 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid"). 3075 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid"). 3076 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "deleted", "test-uid"). 3077 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error2", "test-uid"). 3078 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement1", "test-uid"). 3079 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement2", "test-uid"). 3080 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3081 Admitted(true). 3082 Obj(), 3083 }, 3084 workloadCmpOpts: defaultWorkloadCmpOpts, 3085 wantEvents: []utiltesting.EventRecord{ 3086 { 3087 Key: types.NamespacedName{Name: "test-group", Namespace: "ns"}, 3088 EventType: "Normal", 3089 Reason: "OwnerReferencesAdded", 3090 Message: "Added 2 owner reference(s)", 3091 }, 3092 }, 3093 }, 3094 "no failed pods are finalized while waiting for expectations": { 3095 pods: []corev1.Pod{ 3096 *basePodWrapper. 3097 Clone(). 3098 Name("active-pod"). 3099 Label("kueue.x-k8s.io/managed", "true"). 3100 KueueFinalizer(). 3101 Group("test-group"). 3102 GroupTotalCount("2"). 3103 Obj(), 3104 *basePodWrapper. 3105 Clone(). 3106 Name("finished-with-error"). 3107 Label("kueue.x-k8s.io/managed", "true"). 3108 KueueFinalizer(). 3109 Group("test-group"). 3110 GroupTotalCount("2"). 3111 StatusPhase(corev1.PodFailed). 3112 StatusConditions(corev1.PodCondition{ 3113 Type: corev1.ContainersReady, 3114 Status: corev1.ConditionFalse, 3115 Reason: string(corev1.PodFailed), 3116 LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(), 3117 }). 3118 Obj(), 3119 *basePodWrapper. 3120 Clone(). 3121 Name("replacement"). 3122 Label("kueue.x-k8s.io/managed", "true"). 3123 KueueFinalizer(). 3124 Group("test-group"). 3125 GroupTotalCount("2"). 3126 Obj(), 3127 }, 3128 wantPods: []corev1.Pod{ 3129 *basePodWrapper. 3130 Clone(). 3131 Name("active-pod"). 3132 Label("kueue.x-k8s.io/managed", "true"). 3133 KueueFinalizer(). 3134 Group("test-group"). 3135 GroupTotalCount("2"). 3136 Obj(), 3137 *basePodWrapper. 3138 Clone(). 3139 Name("finished-with-error"). 3140 Label("kueue.x-k8s.io/managed", "true"). 3141 KueueFinalizer(). 3142 Group("test-group"). 3143 GroupTotalCount("2"). 3144 StatusPhase(corev1.PodFailed). 3145 StatusConditions(corev1.PodCondition{ 3146 Type: corev1.ContainersReady, 3147 Status: corev1.ConditionFalse, 3148 Reason: string(corev1.PodFailed), 3149 LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(), 3150 }). 3151 Obj(), 3152 *basePodWrapper. 3153 Clone(). 3154 Name("replacement"). 3155 Label("kueue.x-k8s.io/managed", "true"). 3156 KueueFinalizer(). 3157 Group("test-group"). 3158 GroupTotalCount("2"). 3159 Obj(), 3160 }, 3161 workloads: []kueue.Workload{ 3162 *utiltesting.MakeWorkload("test-group", "ns"). 3163 PodSets( 3164 *utiltesting.MakePodSet("dc85db45", 2). 3165 Request(corev1.ResourceCPU, "1"). 3166 Obj(), 3167 ). 3168 Queue("user-queue"). 3169 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid"). 3170 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid"). 3171 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3172 Admitted(true). 3173 Obj(), 3174 }, 3175 wantWorkloads: []kueue.Workload{ 3176 *utiltesting.MakeWorkload("test-group", "ns"). 3177 PodSets( 3178 *utiltesting.MakePodSet("dc85db45", 2). 3179 Request(corev1.ResourceCPU, "1"). 3180 Obj(), 3181 ). 3182 Queue("user-queue"). 3183 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "active-pod", "test-uid"). 3184 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid"). 3185 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3186 Admitted(true). 3187 Obj(), 3188 }, 3189 workloadCmpOpts: defaultWorkloadCmpOpts, 3190 excessPodsExpectations: []keyUIDs{{ 3191 key: types.NamespacedName{Name: "test-group", Namespace: "ns"}, 3192 uids: []types.UID{"some-other-pod"}, 3193 }}, 3194 }, 3195 "no unnecessary additional failed pods are finalized": { 3196 pods: []corev1.Pod{ 3197 *basePodWrapper. 3198 Clone(). 3199 Name("finished-with-error"). 3200 Label("kueue.x-k8s.io/managed", "true"). 3201 KueueFinalizer(). 3202 Group("test-group"). 3203 GroupTotalCount("2"). 3204 StatusPhase(corev1.PodFailed). 3205 StatusConditions(corev1.PodCondition{ 3206 Type: corev1.ContainersReady, 3207 Status: corev1.ConditionFalse, 3208 Reason: string(corev1.PodFailed), 3209 LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(), 3210 }). 3211 Obj(), 3212 *basePodWrapper. 3213 Clone(). 3214 Name("finished-with-error-no-finalizer"). 3215 Label("kueue.x-k8s.io/managed", "true"). 3216 Group("test-group"). 3217 GroupTotalCount("2"). 3218 StatusPhase(corev1.PodFailed). 3219 StatusConditions(corev1.PodCondition{ 3220 Type: corev1.ContainersReady, 3221 Status: corev1.ConditionFalse, 3222 Reason: string(corev1.PodFailed), 3223 LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(), 3224 }). 3225 Obj(), 3226 *basePodWrapper. 3227 Clone(). 3228 Name("replacement"). 3229 Label("kueue.x-k8s.io/managed", "true"). 3230 KueueFinalizer(). 3231 Group("test-group"). 3232 GroupTotalCount("2"). 3233 Obj(), 3234 }, 3235 wantPods: []corev1.Pod{ 3236 *basePodWrapper. 3237 Clone(). 3238 Name("finished-with-error"). 3239 Label("kueue.x-k8s.io/managed", "true"). 3240 KueueFinalizer(). 3241 Group("test-group"). 3242 GroupTotalCount("2"). 3243 StatusPhase(corev1.PodFailed). 3244 StatusConditions(corev1.PodCondition{ 3245 Type: corev1.ContainersReady, 3246 Status: corev1.ConditionFalse, 3247 Reason: string(corev1.PodFailed), 3248 LastTransitionTime: metav1.NewTime(now.Add(-5 * time.Minute)).Rfc3339Copy(), 3249 }). 3250 Obj(), 3251 *basePodWrapper. 3252 Clone(). 3253 Name("finished-with-error-no-finalizer"). 3254 Label("kueue.x-k8s.io/managed", "true"). 3255 Group("test-group"). 3256 GroupTotalCount("2"). 3257 StatusPhase(corev1.PodFailed). 3258 StatusConditions(corev1.PodCondition{ 3259 Type: corev1.ContainersReady, 3260 Status: corev1.ConditionFalse, 3261 Reason: string(corev1.PodFailed), 3262 LastTransitionTime: metav1.NewTime(now.Add(-3 * time.Minute)).Rfc3339Copy(), 3263 }). 3264 Obj(), 3265 *basePodWrapper. 3266 Clone(). 3267 Name("replacement"). 3268 Label("kueue.x-k8s.io/managed", "true"). 3269 KueueFinalizer(). 3270 Group("test-group"). 3271 GroupTotalCount("2"). 3272 Obj(), 3273 }, 3274 workloads: []kueue.Workload{ 3275 *utiltesting.MakeWorkload("test-group", "ns"). 3276 PodSets( 3277 *utiltesting.MakePodSet("dc85db45", 4). 3278 Request(corev1.ResourceCPU, "1"). 3279 Obj(), 3280 ). 3281 Queue("user-queue"). 3282 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid"). 3283 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error-no-finalizer", "test-uid"). 3284 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3285 Admitted(true). 3286 Obj(), 3287 }, 3288 wantWorkloads: []kueue.Workload{ 3289 *utiltesting.MakeWorkload("test-group", "ns"). 3290 PodSets( 3291 *utiltesting.MakePodSet("dc85db45", 4). 3292 Request(corev1.ResourceCPU, "1"). 3293 Obj(), 3294 ). 3295 Queue("user-queue"). 3296 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error", "test-uid"). 3297 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "finished-with-error-no-finalizer", "test-uid"). 3298 OwnerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "replacement", "test-uid"). 3299 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3300 Admitted(true). 3301 Obj(), 3302 }, 3303 workloadCmpOpts: defaultWorkloadCmpOpts, 3304 wantEvents: []utiltesting.EventRecord{ 3305 { 3306 Key: types.NamespacedName{Name: "test-group", Namespace: "ns"}, 3307 EventType: "Normal", 3308 Reason: "OwnerReferencesAdded", 3309 Message: "Added 1 owner reference(s)", 3310 }, 3311 }, 3312 }, 3313 } 3314 3315 for name, tc := range testCases { 3316 t.Run(name, func(t *testing.T) { 3317 ctx, log := utiltesting.ContextWithLog(t) 3318 clientBuilder := utiltesting.NewClientBuilder() 3319 if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil { 3320 t.Fatalf("Could not setup indexes: %v", err) 3321 } 3322 3323 kcBuilder := clientBuilder.WithObjects(tc.initObjects...) 3324 for i := range tc.pods { 3325 kcBuilder = kcBuilder.WithObjects(&tc.pods[i]) 3326 } 3327 3328 for i := range tc.workloads { 3329 kcBuilder = kcBuilder.WithStatusSubresource(&tc.workloads[i]) 3330 } 3331 3332 kClient := kcBuilder.Build() 3333 for i := range tc.workloads { 3334 if err := kClient.Create(ctx, &tc.workloads[i]); err != nil { 3335 t.Fatalf("Could not create workload: %v", err) 3336 } 3337 3338 if tc.deleteWorkloads { 3339 if err := kClient.Delete(ctx, &tc.workloads[i]); err != nil { 3340 t.Fatalf("Could not delete workload: %v", err) 3341 } 3342 } 3343 } 3344 recorder := &utiltesting.EventRecorder{} 3345 reconciler := NewReconciler(kClient, recorder) 3346 pReconciler := reconciler.(*Reconciler) 3347 for _, e := range tc.excessPodsExpectations { 3348 pReconciler.expectationsStore.ExpectUIDs(log, e.key, e.uids) 3349 } 3350 3351 var reconcileRequest reconcile.Request 3352 if tc.reconcileKey != nil { 3353 reconcileRequest.NamespacedName = *tc.reconcileKey 3354 } else { 3355 reconcileRequest = reconcileRequestForPod(&tc.pods[0]) 3356 } 3357 _, err := reconciler.Reconcile(ctx, reconcileRequest) 3358 3359 if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" { 3360 t.Errorf("Reconcile returned error (-want,+got):\n%s", diff) 3361 } 3362 3363 var gotPods corev1.PodList 3364 if err := kClient.List(ctx, &gotPods); err != nil { 3365 if tc.wantPods != nil || !apierrors.IsNotFound(err) { 3366 t.Fatalf("Could not get Pod after reconcile: %v", err) 3367 } 3368 } 3369 if tc.wantPods != nil { 3370 if diff := cmp.Diff(tc.wantPods, gotPods.Items, podCmpOpts...); diff != "" && tc.wantPods != nil { 3371 t.Errorf("Pods after reconcile (-want,+got):\n%s", diff) 3372 } 3373 } 3374 3375 var gotWorkloads kueue.WorkloadList 3376 if err := kClient.List(ctx, &gotWorkloads); err != nil { 3377 t.Fatalf("Could not get Workloads after reconcile: %v", err) 3378 } 3379 3380 if diff := cmp.Diff(tc.wantWorkloads, gotWorkloads.Items, tc.workloadCmpOpts...); diff != "" { 3381 for i, p := range tc.pods { 3382 // Make life easier when changing the hashing function. 3383 hash, _ := getRoleHash(p) 3384 t.Logf("note, the hash for pod[%v] = %s", i, hash) 3385 3386 } 3387 t.Errorf("Workloads after reconcile (-want,+got):\n%s", diff) 3388 } 3389 3390 if diff := cmp.Diff(tc.wantEvents, recorder.RecordedEvents, cmpopts.SortSlices(utiltesting.SortEvents)); diff != "" { 3391 t.Errorf("unexpected events (-want/+got):\n%s", diff) 3392 } 3393 }) 3394 } 3395 } 3396 3397 func TestReconciler_ErrorFinalizingPod(t *testing.T) { 3398 ctx, _ := utiltesting.ContextWithLog(t) 3399 3400 clientBuilder := utiltesting.NewClientBuilder() 3401 if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil { 3402 t.Fatalf("Could not setup indexes: %v", err) 3403 } 3404 3405 basePodWrapper := testingpod.MakePod("pod", "ns"). 3406 UID("test-uid"). 3407 Queue("user-queue"). 3408 Request(corev1.ResourceCPU, "1"). 3409 Image("", nil) 3410 3411 pod := *basePodWrapper. 3412 Clone(). 3413 Label("kueue.x-k8s.io/managed", "true"). 3414 KueueFinalizer(). 3415 StatusPhase(corev1.PodSucceeded). 3416 Obj() 3417 3418 wl := *utiltesting.MakeWorkload("unit-test", "ns").Finalizers(kueue.ResourceInUseFinalizerName). 3419 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 3420 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3421 Admitted(true). 3422 Obj() 3423 3424 reqcount := 0 3425 errMock := fmt.Errorf("connection refused: %w", syscall.ECONNREFUSED) 3426 3427 kcBuilder := clientBuilder. 3428 WithObjects(&pod). 3429 WithStatusSubresource(&wl). 3430 WithInterceptorFuncs(interceptor.Funcs{ 3431 Update: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.UpdateOption) error { 3432 _, isPod := obj.(*corev1.Pod) 3433 if isPod { 3434 defer func() { reqcount++ }() 3435 if reqcount == 0 { 3436 // return a connection refused error for the first update request. 3437 return errMock 3438 } 3439 if reqcount == 1 { 3440 // Exec a regular update operation for the second request 3441 return client.Update(ctx, obj, opts...) 3442 } 3443 } 3444 return client.Update(ctx, obj, opts...) 3445 }, 3446 }) 3447 3448 kClient := kcBuilder.Build() 3449 if err := ctrl.SetControllerReference(&pod, &wl, kClient.Scheme()); err != nil { 3450 t.Fatalf("Could not setup owner reference in Workloads: %v", err) 3451 } 3452 if err := kClient.Create(ctx, &wl); err != nil { 3453 t.Fatalf("Could not create workload: %v", err) 3454 } 3455 recorder := record.NewBroadcaster().NewRecorder(kClient.Scheme(), corev1.EventSource{Component: "test"}) 3456 3457 reconciler := NewReconciler(kClient, recorder) 3458 3459 podKey := client.ObjectKeyFromObject(&pod) 3460 _, err := reconciler.Reconcile(ctx, reconcile.Request{ 3461 NamespacedName: podKey, 3462 }) 3463 3464 if diff := cmp.Diff(errMock, err, cmpopts.EquateErrors()); diff != "" { 3465 t.Errorf("Expected reconcile error (-want,+got):\n%s", diff) 3466 } 3467 3468 // Reconcile for the second time 3469 _, err = reconciler.Reconcile(ctx, reconcile.Request{ 3470 NamespacedName: podKey, 3471 }) 3472 if err != nil { 3473 t.Errorf("Got unexpected error while running reconcile:\n%v", err) 3474 } 3475 3476 var gotPod corev1.Pod 3477 if err := kClient.Get(ctx, podKey, &gotPod); err != nil { 3478 t.Fatalf("Could not get Pod after second reconcile: %v", err) 3479 } 3480 // Validate that pod has no finalizer after the second reconcile 3481 wantPod := *basePodWrapper. 3482 Clone(). 3483 Label("kueue.x-k8s.io/managed", "true"). 3484 StatusPhase(corev1.PodSucceeded). 3485 Obj() 3486 if diff := cmp.Diff(wantPod, gotPod, podCmpOpts...); diff != "" { 3487 t.Errorf("Pod after second reconcile (-want,+got):\n%s", diff) 3488 } 3489 3490 var gotWorkloads kueue.WorkloadList 3491 if err := kClient.List(ctx, &gotWorkloads); err != nil { 3492 t.Fatalf("Could not get Workloads after second reconcile: %v", err) 3493 } 3494 3495 // Workload should be finished after the second reconcile 3496 wantWl := *utiltesting.MakeWorkload("unit-test", "ns"). 3497 PodSets(*utiltesting.MakePodSet(kueue.DefaultPodSetName, 1).Request(corev1.ResourceCPU, "1").Obj()). 3498 ReserveQuota(utiltesting.MakeAdmission("cq").AssignmentPodCount(1).Obj()). 3499 ControllerReference(corev1.SchemeGroupVersion.WithKind("Pod"), "pod", "test-uid"). 3500 Admitted(true). 3501 Condition( 3502 metav1.Condition{ 3503 Type: kueue.WorkloadFinished, 3504 Status: metav1.ConditionTrue, 3505 Reason: "JobFinished", 3506 Message: "Job finished successfully", 3507 }, 3508 ). 3509 Obj() 3510 if diff := cmp.Diff([]kueue.Workload{wantWl}, gotWorkloads.Items, defaultWorkloadCmpOpts...); diff != "" { 3511 t.Errorf("Workloads after second reconcile (-want,+got):\n%s", diff) 3512 } 3513 } 3514 3515 func TestIsPodOwnerManagedByQueue(t *testing.T) { 3516 testCases := map[string]struct { 3517 ownerReference metav1.OwnerReference 3518 wantRes bool 3519 }{ 3520 "batch/v1/Job": { 3521 ownerReference: metav1.OwnerReference{ 3522 APIVersion: "batch/v1", 3523 Controller: ptr.To(true), 3524 Kind: "Job", 3525 }, 3526 wantRes: true, 3527 }, 3528 "apps/v1/ReplicaSet": { 3529 ownerReference: metav1.OwnerReference{ 3530 APIVersion: "apps/v1", 3531 Controller: ptr.To(true), 3532 Kind: "ReplicaSet", 3533 }, 3534 wantRes: false, 3535 }, 3536 "ray.io/v1alpha1/RayCluster": { 3537 ownerReference: metav1.OwnerReference{ 3538 APIVersion: "ray.io/v1alpha1", 3539 Controller: ptr.To(true), 3540 Kind: "RayCluster", 3541 }, 3542 wantRes: true, 3543 }, 3544 } 3545 3546 for name, tc := range testCases { 3547 t.Run(name, func(t *testing.T) { 3548 pod := testingpod.MakePod("pod", "ns"). 3549 UID("test-uid"). 3550 Request(corev1.ResourceCPU, "1"). 3551 Image("", nil). 3552 Obj() 3553 3554 pod.OwnerReferences = append(pod.OwnerReferences, tc.ownerReference) 3555 3556 if tc.wantRes != IsPodOwnerManagedByKueue(fromObject(pod)) { 3557 t.Errorf("Unexpected 'IsPodOwnerManagedByKueue' result\n want: %t\n got: %t)", 3558 tc.wantRes, IsPodOwnerManagedByKueue(fromObject(pod))) 3559 } 3560 }) 3561 } 3562 } 3563 3564 func TestGetWorkloadNameForPod(t *testing.T) { 3565 wantWlName := "pod-unit-test-7bb47" 3566 wlName := GetWorkloadNameForPod("unit-test") 3567 3568 if wantWlName != wlName { 3569 t.Errorf("Expected different workload name\n want: %s\n got: %s", wantWlName, wlName) 3570 } 3571 }