Pre-existing LeaderWorkerSets permanently Gated after v0.18.4 upgrade
kind/bug
**What happened**:
After upgrading v0.17.6 → v0.18.4, pods belonging to **pre-existing** LeaderWorkerSets become permanently `SchedulingGated` whenever they are recreated.
`5252f419e` ("Allow mutating queue-name label in LeaderWorkerSet", #4932) **moved** the `queue-name` write:
- **Removed** from the LWS pod reconciler's `setDefault` — previously `pod.Labels[QueueLabel] = QueueNameForObject(lws)`, applied per pod at reconcile time.
- **Added** to the LWS webhook's `podTemplateSpecDefault` — now writes into `spec.leaderWorkerTemplate.{leader,worker}Template.metadata.labels`.
That webhook is `verbs=create;update`, so it only runs when an LWS is admitted. Existing LWS objects are never re-admitted, so their stored templates are never stamped, and there is no backfill. The reconciler
that used to patch pods individually no longer does.
A pod created from an unstamped template is invisible to the pod integration:
1. Pod controller skips it — `"queue-name label is not set, ignoring the job"`
2. No `kueue.x-k8s.io/workload` annotation is written
3. `IndexPodWorkloadSliceName` derives the index solely from that annotation → pod absent from `WorkloadSliceNameKey`
4. `ListPodsForWorkloadSlice` returns nothing → topology ungater logs `domainIDToUngatedCount={}`, zero candidates
5. Gates never drop; the pod never starts
6. `waitForPodsReady` expires → `Evicted/PodsReadyTimeout` → pods deleted → StatefulSet controller recreates them from the **same** template, still unlabelled → back to 1
Each cycle increments `requeueState.count`. At `backoffLimitCount` the Workload is deactivated (`DeactivatedDueToRequeuingLimitExceeded`) and only resubmission recovers it. Affected Workloads reported
`Admitted=True` with a valid TAS assignment throughout, so quota looked healthy while nothing ran.
**What you expected to happen**:
An LWS admitted under an earlier version should not become permanently unschedulable because its pod templates predate the change. Either the reconciler should still fall back to copying `queue-name` onto pods
when the template lacks it, or the LWS controller should backfill templates on reconcile — not only via the admission webhook.
**How to reproduce it (as minimally and precisely as possible)**:
1. On v0.17.x, create an LWS with `queue-name` on `metadata.labels` only (not on the pod templates). Confirm pods are labelled by the reconciler and run.
2. Upgrade to v0.18.4 without modifying the LWS.
3. Force pod recreation — delete a pod, or let a PodsReady timeout fire.
4. Replacement pods have no `queue-name`, stay `SchedulingGated`, and loop until the Workload is deactivated.
**Anything else we need to know?**:
Workaround: any update to the LWS re-runs the webhook and stamps both templates; the label then propagates LWS → StatefulSet → every recreated pod.
```
kubectl annotate lws <name> example.com/backfill=1 --overwrite
```
This bumps the template revision and triggers a full rolling update of all groups, so it is disruptive for serving workloads.
**Environment**:
- Kubernetes version: `v1.34`
- Kueue version: `v0.18.4` (upgraded from `v0.17.6`)
- Cloud provider or hardware configuration: GKE, GPU node pools
- OS: <fill in>
- Kernel: <fill in>
- Install tools: <fill in>
- Others: `waitForPodsReady` enabled (45m timeout, `backoffLimitCount: 75`, `blockAdmission: false`); TAS and fair sharing enabled; `pod` and `leaderworkerset` integrations enabled. Feature gates:
`TASReplaceNodeOnNodeTaints=true`, `ElasticJobsViaWorkloadSlices=true`, `LocalQueueMetrics=true`, `VisibilityOnDemand=false`, `KueueDRAIntegration=false`, `KueueDRARejectWorkloadsWhenDRADisabled=false`
Scrubbed: cluster/namespace/queue names, job IDs, GPU counts and node names, company and internal service names, our log-volume figures, and the internal generator's file paths. Everything left is upstream-public
— Kueue code paths, log strings, commit 5252f419e.
2 条评论