Describe the bug
How this was found: by auditing every DaemonSet-bearing component the GPU Operator ships (checked at tag v26.3.3, commit b0a49c0e7b2e061dcd83f2bb2fe4fe960c5d0338) for priorityClassName, then confirming the result by deploying the actual, unmodified manifest to a live cluster — not a static-analysis-only claim.
Of the 13 DaemonSet templates under assets/, 12 hardcode priorityClassName: system-node-critical:
state-driver, state-device-plugin, state-container-toolkit, gpu-feature-discovery, state-dcgm-exporter, state-mig-manager, state-vgpu-manager, state-cc-manager, state-kata-device-plugin, state-kata-manager, state-mps-control-daemon, state-node-status-exporter, state-operator-validation, state-sandbox-device-plugin, state-sandbox-validation, state-vfio-manager
nvidia-vgpu-device-manager is the sole exception — assets/state-vgpu-device-manager/0600_daemonset.yaml has no priorityClassName field anywhere.
This isn't compensated for elsewhere: controllers/object_controls.go#L819-L822 (applyCommonDaemonsetConfig, applied to every DaemonSet) only overrides PriorityClassName when an operator explicitly sets a cluster-wide ClusterPolicy.spec.daemonsets.priorityClassName — it never injects a default for a DaemonSet whose own template omits the field:
// update PriorityClass
if config.Daemonsets.PriorityClassName != "" {
obj.Spec.Template.Spec.PriorityClassName = config.Daemonsets.PriorityClassName
}
Confirmed live, deploying the two real manifests (namespace/image placeholders substituted, no other changes) to a kind cluster:
$ kubectl get pods -o jsonpath='{.spec.priority}{" "}{.spec.priorityClassName}{"\n"}'
nvidia-device-plugin-daemonset-... 2000001000 system-node-critical
nvidia-vgpu-device-manager-... 0
nvidia-vgpu-device-manager admits at priority 0 — identical to any ordinary, unprivileged workload pod.
Why this matters: kube-scheduler's default preemption plugin only allows a pod to preempt a strictly lower-priority victim (isPreemptionAllowed, a strict <, not <=). This is the exact mechanism behind kubernetes/kubernetes#140984: a node-pinned pod at default priority can be permanently locked out if its one eligible node fills up with other equal-priority pods first, with no self-heal, because preemption can never reclaim the slot. nvidia-vgpu-device-manager is a DaemonSet — hard-pinned to whichever node it targets — running at that same default priority. During a mass node remediation event (health-triggered cordon/drain/reboot across a fleet), if the node comes back and fills with equal-priority workload pods before this DaemonSet's replacement pod is considered, it can be stuck Pending indefinitely. Since this DaemonSet applies vGPU device/profile configuration on the node, that node's vGPU-sliced GPU capacity may never get (re)configured after the remediation event — with nothing to signal that a stuck DaemonSet pod, rather than a hardware issue, is the cause.
To Reproduce
No real GPU hardware or vGPU license is required — this is a manifest/admission-level check, not a functional GPU test.
# 1. Any Kubernetes cluster (a plain `kind` cluster is sufficient)
kind create cluster --name vgpu-dm-repro
# 2. Fetch the actual, unmodified DaemonSet manifest from the operator's assets at the pinned tag
curl -sSL -o vgpu-dm.yaml \
https://raw.githubusercontent.com/NVIDIA/gpu-operator/v26.3.3/assets/state-vgpu-device-manager/0600_daemonset.yaml
# 3. Substitute the operator-templated placeholders (namespace, image) with real values —
# this is the ONLY change needed; priorityClassName is absent in the source file itself
sed -i 's#"FILLED BY THE OPERATOR"#default#; s#image: default#image: "registry.k8s.io/pause:3.10"#g' vgpu-dm.yaml
# 4. Provide the ServiceAccount the manifest references, and label a node to match its nodeSelector
kubectl create serviceaccount nvidia-vgpu-device-manager
kubectl label node <a-node> nvidia.com/gpu.deploy.vgpu-device-manager=true
# 5. Apply and check the admitted priority
kubectl apply -f vgpu-dm.yaml
kubectl get pods -l app=nvidia-vgpu-device-manager \
-o jsonpath='{.items[0].spec.priority}{" "}{.items[0].spec.priorityClassName}{"\n"}'
# -> 0 (empty priorityClassName)
For contrast, repeating the same steps with assets/state-device-plugin/0500_daemonset.yaml (which does set priorityClassName: system-node-critical in its source) shows 2000001000 system-node-critical instead.
Expected behavior
nvidia-vgpu-device-manager should run at priorityClassName: system-node-critical, consistent with every other DaemonSet the GPU Operator ships, so it has the same protection against being permanently starved of scheduling by equal-priority workload pods during node remediation events.
Environment (please provide the following information):
- GPU Operator Version:
v26.3.3 (commit b0a49c0e7b2e061dcd83f2bb2fe4fe960c5d0338) — root cause is a static manifest omission, not version-specific behavior; not yet checked against main/unreleased commits for whether it has already been fixed.
- Reproduction environment: vanilla
kind cluster, no cloud provider, no real GPU/vGPU hardware — the bug is at the pod-admission/priority level, independent of the driver or vGPU functionality itself.
Information to attach (optional if deemed irrelevant)
Not applicable — this is a manifest-completeness finding confirmed via kubectl get pod -o jsonpath on the priority/priorityClassName fields, not a runtime error requiring pod logs or a nvidia-smi capture. Happy to provide the full kubectl describe/get -o yaml output for both DaemonSets used in the reproduction if useful for triage.
Describe the bug
How this was found: by auditing every DaemonSet-bearing component the GPU Operator ships (checked at tag
v26.3.3, commitb0a49c0e7b2e061dcd83f2bb2fe4fe960c5d0338) forpriorityClassName, then confirming the result by deploying the actual, unmodified manifest to a live cluster — not a static-analysis-only claim.Of the 13 DaemonSet templates under
assets/, 12 hardcodepriorityClassName: system-node-critical:state-driver,state-device-plugin,state-container-toolkit,gpu-feature-discovery,state-dcgm-exporter,state-mig-manager,state-vgpu-manager,state-cc-manager,state-kata-device-plugin,state-kata-manager,state-mps-control-daemon,state-node-status-exporter,state-operator-validation,state-sandbox-device-plugin,state-sandbox-validation,state-vfio-managernvidia-vgpu-device-manageris the sole exception —assets/state-vgpu-device-manager/0600_daemonset.yamlhas nopriorityClassNamefield anywhere.This isn't compensated for elsewhere:
controllers/object_controls.go#L819-L822(applyCommonDaemonsetConfig, applied to every DaemonSet) only overridesPriorityClassNamewhen an operator explicitly sets a cluster-wideClusterPolicy.spec.daemonsets.priorityClassName— it never injects a default for a DaemonSet whose own template omits the field:Confirmed live, deploying the two real manifests (namespace/image placeholders substituted, no other changes) to a
kindcluster:nvidia-vgpu-device-manageradmits at priority 0 — identical to any ordinary, unprivileged workload pod.Why this matters: kube-scheduler's default preemption plugin only allows a pod to preempt a strictly lower-priority victim (
isPreemptionAllowed, a strict<, not<=). This is the exact mechanism behind kubernetes/kubernetes#140984: a node-pinned pod at default priority can be permanently locked out if its one eligible node fills up with other equal-priority pods first, with no self-heal, because preemption can never reclaim the slot.nvidia-vgpu-device-manageris a DaemonSet — hard-pinned to whichever node it targets — running at that same default priority. During a mass node remediation event (health-triggered cordon/drain/reboot across a fleet), if the node comes back and fills with equal-priority workload pods before this DaemonSet's replacement pod is considered, it can be stuckPendingindefinitely. Since this DaemonSet applies vGPU device/profile configuration on the node, that node's vGPU-sliced GPU capacity may never get (re)configured after the remediation event — with nothing to signal that a stuck DaemonSet pod, rather than a hardware issue, is the cause.To Reproduce
No real GPU hardware or vGPU license is required — this is a manifest/admission-level check, not a functional GPU test.
For contrast, repeating the same steps with
assets/state-device-plugin/0500_daemonset.yaml(which does setpriorityClassName: system-node-criticalin its source) shows2000001000 system-node-criticalinstead.Expected behavior
nvidia-vgpu-device-managershould run atpriorityClassName: system-node-critical, consistent with every other DaemonSet the GPU Operator ships, so it has the same protection against being permanently starved of scheduling by equal-priority workload pods during node remediation events.Environment (please provide the following information):
v26.3.3(commitb0a49c0e7b2e061dcd83f2bb2fe4fe960c5d0338) — root cause is a static manifest omission, not version-specific behavior; not yet checked againstmain/unreleased commits for whether it has already been fixed.kindcluster, no cloud provider, no real GPU/vGPU hardware — the bug is at the pod-admission/priority level, independent of the driver or vGPU functionality itself.Information to attach (optional if deemed irrelevant)
Not applicable — this is a manifest-completeness finding confirmed via
kubectl get pod -o jsonpathon the priority/priorityClassName fields, not a runtime error requiring pod logs or anvidia-smicapture. Happy to provide the fullkubectl describe/get -o yamloutput for both DaemonSets used in the reproduction if useful for triage.