@@ -1132,4 +1132,89 @@ var _ = ginkgo.Describe("Preemption", func() {
11321132 util .ExpectWorkloadsToBeAdmitted (ctx , k8sClient , lowWl )
11331133 })
11341134 })
1135+
1136+ // Issue #8320: Adding a priority class to a workload (none -> some) is not reconciled
1137+ // https://github.com/kubernetes-sigs/kueue/issues/8320
1138+ //
1139+ // When a WorkloadPriorityClass is added to a suspended workload, the workload's
1140+ // spec.priority should be reconciled from the WorkloadPriorityClass value, and
1141+ // the workload should be re-queued with the new priority for scheduling.
1142+ ginkgo .Context ("When adding a WorkloadPriorityClass to a suspended workload" , func () {
1143+ var (
1144+ cq * kueue.ClusterQueue
1145+ q * kueue.LocalQueue
1146+ highPrioClass * kueue.WorkloadPriorityClass
1147+ )
1148+
1149+ ginkgo .BeforeEach (func () {
1150+ highPrioClass = utiltestingapi .MakeWorkloadPriorityClass ("high-priority" ).
1151+ PriorityValue (highPriority ).
1152+ Obj ()
1153+ util .MustCreate (ctx , k8sClient , highPrioClass )
1154+
1155+ cq = utiltestingapi .MakeClusterQueue ("cq" ).
1156+ ResourceGroup (* utiltestingapi .MakeFlavorQuotas ("alpha" ).Resource (corev1 .ResourceCPU , "2" ).Obj ()).
1157+ Preemption (kueue.ClusterQueuePreemption {
1158+ WithinClusterQueue : kueue .PreemptionPolicyLowerPriority ,
1159+ }).
1160+ Obj ()
1161+ util .MustCreate (ctx , k8sClient , cq )
1162+
1163+ q = utiltestingapi .MakeLocalQueue ("q" , ns .Name ).ClusterQueue (cq .Name ).Obj ()
1164+ util .MustCreate (ctx , k8sClient , q )
1165+ })
1166+
1167+ ginkgo .AfterEach (func () {
1168+ gomega .Expect (util .DeleteWorkloadsInNamespace (ctx , k8sClient , ns )).To (gomega .Succeed ())
1169+ util .ExpectObjectToBeDeleted (ctx , k8sClient , cq , true )
1170+ util .ExpectObjectToBeDeleted (ctx , k8sClient , highPrioClass , true )
1171+ })
1172+
1173+ ginkgo .It ("Should reconcile the priority when WorkloadPriorityClass is added to suspended workload" , func () {
1174+ ginkgo .By ("Creating a workload with low priority that gets admitted" )
1175+ lowWl := utiltestingapi .MakeWorkload ("low-wl" , ns .Name ).
1176+ Queue (kueue .LocalQueueName (q .Name )).
1177+ Priority (lowPriority ).
1178+ Request (corev1 .ResourceCPU , "2" ).
1179+ Obj ()
1180+ util .MustCreate (ctx , k8sClient , lowWl )
1181+ util .ExpectWorkloadsToHaveQuotaReservation (ctx , k8sClient , cq .Name , lowWl )
1182+
1183+ ginkgo .By ("Creating a workload WITHOUT a priority class (stays pending)" )
1184+ noPrioWl := utiltestingapi .MakeWorkload ("no-prio-wl" , ns .Name ).
1185+ Queue (kueue .LocalQueueName (q .Name )).
1186+ Request (corev1 .ResourceCPU , "2" ).
1187+ Obj ()
1188+ util .MustCreate (ctx , k8sClient , noPrioWl )
1189+ util .ExpectWorkloadsToBePending (ctx , k8sClient , noPrioWl )
1190+
1191+ ginkgo .By ("Adding a WorkloadPriorityClass to the pending workload" )
1192+ // Note: Due to CEL validation, we must set both priorityClassRef AND priority together.
1193+ // In real usage, the job controller sets both when creating/updating the workload.
1194+ // The bug in #8320 is that the workload controller's change detection
1195+ // (workloadPriorityClassChanged) fails to detect when priority class is ADDED
1196+ // (oldPriorityClassName == "" -> newPriorityClassName != "").
1197+ // However, when adding a priority class, we set the priority to a WRONG value (0)
1198+ // to simulate that the job controller created the workload but the reconciler
1199+ // needs to update the priority from the WorkloadPriorityClass.
1200+ gomega .Eventually (func (g gomega.Gomega ) {
1201+ wl := & kueue.Workload {}
1202+ g .Expect (k8sClient .Get (ctx , client .ObjectKeyFromObject (noPrioWl ), wl )).To (gomega .Succeed ())
1203+ // Set priorityClassRef to reference the high-priority WorkloadPriorityClass
1204+ wl .Spec .PriorityClassRef = kueue .NewWorkloadPriorityClassRef ("high-priority" )
1205+ // Set priority to 0 (wrong value) - the controller should reconcile this to highPriority
1206+ wl .Spec .Priority = ptr.To [int32 ](0 )
1207+ g .Expect (k8sClient .Update (ctx , wl )).To (gomega .Succeed ())
1208+ }, util .Timeout , util .Interval ).Should (gomega .Succeed ())
1209+
1210+ ginkgo .By ("Verifying the workload priority is reconciled to the correct value from the WorkloadPriorityClass" )
1211+ util .ExpectWorkloadsWithWorkloadPriority (ctx , k8sClient , "high-priority" , highPriority , client .ObjectKeyFromObject (noPrioWl ))
1212+
1213+ ginkgo .By ("Verifying preemption occurs and the high-priority workload gets admitted" )
1214+ util .ExpectWorkloadsToBePreempted (ctx , k8sClient , lowWl )
1215+ util .FinishEvictionForWorkloads (ctx , k8sClient , lowWl )
1216+ util .ExpectWorkloadsToHaveQuotaReservation (ctx , k8sClient , cq .Name , noPrioWl )
1217+ util .ExpectWorkloadsToBePending (ctx , k8sClient , lowWl )
1218+ })
1219+ })
11351220})
0 commit comments