From eb7604f3573fa89fb369db8ca15f8febcfffd530 Mon Sep 17 00:00:00 2001 From: yansun1996 Date: Tue, 22 Sep 2026 11:04:25 +0000 Subject: [PATCH 1/6] fix: align DRA driver DaemonSet/DeviceClass with AutoPartition The AMD GPU DRA driver added AutoPartition: it advertises every valid compute+memory partition configuration as a synthetic device and dynamically repartitions the GPU via amd-smi when a matching ResourceClaim is prepared, hardware-validated on 8xMI300X. The operator vendors its own copies of the DRA driver DaemonSet spec (internal/plugin/plugin.go) and default DeviceClass (helm-charts-k8s/templates/dra-driver-deviceclass.yaml) rather than consuming the upstream chart directly, and those copies had fallen out of sync: - DeviceClass: split gpu.amd.com into gpu.amd.com (unconstrained) and gpu.amd.com-spx (extendedResourceName, constrained to computePartition == spx) when draDriver.deviceClass.autoPartition is set, so a classic amd.com/gpu request can't resolve to a leftover partition fraction. Default behavior unchanged aside from gaining extendedResourceName support. Ported into both the generated chart and hack/k8s-patch/template-patch/dra-driver-deviceclass.yaml (the true source make helm-k8s copies over it from). - SetDRADriverAsDesired: set KMM_DRIVER_ENABLED=true when utils.ShouldUseKMM(devConfig), mirroring the existing KMM node-selector wiring. The driver reads this via os.Getenv directly, so cmdLineArguments (which only becomes CLI args) could never set it. - SetDRADriverAsDesired: mount /lib/modules (read-only) unconditionally -- both of the driver's amdgpu reload paths shell out to modprobe, which needs it regardless of KMM. Also includes the regenerated helm-docs README table rows for the two new values, and picks up unrelated pre-existing generated-artifact drift exposed by re-running the generators (k8s.io/api Toleration doc-comment wording, an import alias normalization, mockgen method ordering, and stale timestamps in Chart.lock/the bundle CSV). Co-Authored-By: Claude --- api/v1alpha1/zz_generated.deepcopy.go | 2 +- ...md-gpu-operator.clusterserviceversion.yaml | 2 +- bundle/manifests/amd.com_deviceconfigs.yaml | 28 +++-- config/crd/bases/amd.com_deviceconfigs.yaml | 28 +++-- hack/k8s-patch/metadata-patch/values.yaml | 11 ++ .../dra-driver-deviceclass.yaml | 32 +++++ helm-charts-k8s/Chart.lock | 2 +- helm-charts-k8s/README.md | 4 +- helm-charts-k8s/crds/deviceconfig-crd.yaml | 28 +++-- .../templates/dra-driver-deviceclass.yaml | 32 +++++ helm-charts-k8s/values.yaml | 11 ++ internal/client/mock_client.go | 57 ++++++--- internal/plugin/plugin.go | 23 ++++ internal/plugin/plugin_test.go | 115 ++++++++++++++++++ 14 files changed, 319 insertions(+), 56 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index f29fea96d..8e5463b53 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -40,7 +40,7 @@ import ( monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. diff --git a/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml b/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml index 3267e3158..f06088821 100644 --- a/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml +++ b/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml @@ -36,7 +36,7 @@ metadata: capabilities: Seamless Upgrades categories: AI/Machine Learning,Monitoring containerImage: registry.test.pensando.io:5000/amd-gpu-operator:dev - createdAt: "2026-07-09T09:40:15Z" + createdAt: "2026-09-22T10:57:30Z" description: |- Operator responsible for deploying AMD GPU kernel drivers, device plugin, device test runner and device metrics exporter For more information, visit [documentation](https://instinct.docs.amd.com/projects/gpu-operator/en/latest/) diff --git a/bundle/manifests/amd.com_deviceconfigs.yaml b/bundle/manifests/amd.com_deviceconfigs.yaml index cdbf95ccb..99c2a8cd6 100644 --- a/bundle/manifests/amd.com_deviceconfigs.yaml +++ b/bundle/manifests/amd.com_deviceconfigs.yaml @@ -147,9 +147,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -261,9 +262,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -354,9 +356,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -457,9 +460,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -719,9 +723,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -1438,7 +1443,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -1528,9 +1533,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -1672,9 +1678,8 @@ spec: node. type: string timeAdded: - description: |- - TimeAdded represents the time at which the taint was added. - It is only written for NoExecute taints. + description: TimeAdded represents the time at which the + taint was added. format: date-time type: string value: @@ -1819,9 +1824,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- diff --git a/config/crd/bases/amd.com_deviceconfigs.yaml b/config/crd/bases/amd.com_deviceconfigs.yaml index f98254d3f..a53844e71 100644 --- a/config/crd/bases/amd.com_deviceconfigs.yaml +++ b/config/crd/bases/amd.com_deviceconfigs.yaml @@ -143,9 +143,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -257,9 +258,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -350,9 +352,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -453,9 +456,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -715,9 +719,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -1434,7 +1439,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -1524,9 +1529,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -1668,9 +1674,8 @@ spec: node. type: string timeAdded: - description: |- - TimeAdded represents the time at which the taint was added. - It is only written for NoExecute taints. + description: TimeAdded represents the time at which the + taint was added. format: date-time type: string value: @@ -1815,9 +1820,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- diff --git a/hack/k8s-patch/metadata-patch/values.yaml b/hack/k8s-patch/metadata-patch/values.yaml index 1f676fa3e..c6992bed6 100644 --- a/hack/k8s-patch/metadata-patch/values.yaml +++ b/hack/k8s-patch/metadata-patch/values.yaml @@ -365,6 +365,17 @@ draDriver: deviceClass: # -- Create the gpu.amd.com DeviceClass resource. Set to false if managing the DRA driver independently. create: true + # -- Maps classic extended-resource requests (e.g. amd.com/gpu) to a DeviceClass. + # Set "" to omit the field. When autoPartition is true, this is applied to a + # second class, gpu.amd.com-spx, constrained to whole-GPU (spx) devices only, so + # classic requests can't resolve to a leftover partition fraction. When + # autoPartition is false, it stays on the single gpu.amd.com class as before. + extendedResourceName: amd.com/gpu + # -- Set to true when DeviceConfig.spec.draDriver.cmdLineArguments enables the + # DRA driver's AutoPartition feature gate on the matching nodes. Must be kept in + # sync with that feature-gates value; it only controls this chart's DeviceClass + # rendering and cannot detect the DeviceConfig's setting automatically. + autoPartition: false kmmModuleLoader: serviceAccount: annotations: {} diff --git a/hack/k8s-patch/template-patch/dra-driver-deviceclass.yaml b/hack/k8s-patch/template-patch/dra-driver-deviceclass.yaml index d4a7e6094..2ef51677f 100644 --- a/hack/k8s-patch/template-patch/dra-driver-deviceclass.yaml +++ b/hack/k8s-patch/template-patch/dra-driver-deviceclass.yaml @@ -12,4 +12,36 @@ spec: selectors: - cel: expression: "device.driver == 'gpu.amd.com'" +{{- if and .Values.draDriver.deviceClass.extendedResourceName (not .Values.draDriver.deviceClass.autoPartition) }} + extendedResourceName: {{ .Values.draDriver.deviceClass.extendedResourceName }} +{{- end }} +{{- if .Values.draDriver.deviceClass.autoPartition }} +--- +# When AutoPartition is enabled on the DRA driver, gpu.amd.com's device pool +# includes fractional partition devices (cpx/dpx/qpx) alongside whole GPUs (spx), +# all matched by the same selector above. extendedResourceName moves to this +# second, spx-constrained class instead of staying on the general one, so a +# classic amd.com/gpu request (which carries no selector of its own -- it's +# translated by the apiserver from resources.limits, not authored as a +# ResourceClaim) can only ever resolve to a whole GPU, never a partition +# fraction left over from another claim. +apiVersion: {{ $draApi }} +kind: DeviceClass +metadata: + name: gpu.amd.com-spx + labels: + app.kubernetes.io/component: amd-gpu + app.kubernetes.io/part-of: amd-gpu + {{- include "helm-charts-k8s.labels" . | nindent 4 }} +spec: + selectors: + - cel: + expression: >- + device.driver == 'gpu.amd.com' && + (!has(device.attributes["gpu.amd.com"].computePartition) || + device.attributes["gpu.amd.com"].computePartition == "spx") + {{- with .Values.draDriver.deviceClass.extendedResourceName }} + extendedResourceName: {{ . }} + {{- end }} +{{- end }} {{- end }} diff --git a/helm-charts-k8s/Chart.lock b/helm-charts-k8s/Chart.lock index 526228990..93bfb9da2 100644 --- a/helm-charts-k8s/Chart.lock +++ b/helm-charts-k8s/Chart.lock @@ -9,4 +9,4 @@ dependencies: repository: file://./charts/remediation-crds version: v1.0.0 digest: sha256:0806f6b6d7aa21be77bf1c91e720ae3238338a16f107df450a53b02ef940db1b -generated: "2026-07-09T09:40:11.647230235Z" +generated: "2026-09-22T10:57:26.281736805Z" diff --git a/helm-charts-k8s/README.md b/helm-charts-k8s/README.md index 0a1258bee..e476bd4c8 100644 --- a/helm-charts-k8s/README.md +++ b/helm-charts-k8s/README.md @@ -6,7 +6,7 @@ For the most detailed and up-to-date documentation please visit our Instinct Doc ## Introduction -AMD GPU Operator simplifies the deployment and management of AMD Instinct GPU accelerators within Kubernetes clusters. This project enables seamless configuration and operation of GPU-accelerated workloads, including machine learning, Generative AI, and other GPU-intensive applications. +AMD GPU Operator simplifies the deployment and management of AMD Instinct™ and AMD Radeon™ GPU accelerators within Kubernetes clusters. This project enables seamless configuration and operation of GPU-accelerated workloads, including machine learning, Generative AI, and other GPU-intensive applications. ## Components @@ -280,7 +280,9 @@ Kubernetes: `>= 1.29.0-0` | deviceConfig.spec.testRunner.tolerations | list | `[]` | test runner tolerations | | deviceConfig.spec.testRunner.upgradePolicy.maxUnavailable | int | `1` | the maximum number of Pods that can be unavailable during the update process | | deviceConfig.spec.testRunner.upgradePolicy.upgradeStrategy | string | `"RollingUpdate"` | the type of daemonset upgrade, RollingUpdate or OnDelete | +| draDriver.deviceClass.autoPartition | bool | `false` | Set to true when DeviceConfig.spec.draDriver.cmdLineArguments enables the DRA driver's AutoPartition feature gate on the matching nodes. Must be kept in sync with that feature-gates value; it only controls this chart's DeviceClass rendering and cannot detect the DeviceConfig's setting automatically. | | draDriver.deviceClass.create | bool | `true` | Create the gpu.amd.com DeviceClass resource. Set to false if managing the DRA driver independently. | +| draDriver.deviceClass.extendedResourceName | string | `"amd.com/gpu"` | Maps classic extended-resource requests (e.g. amd.com/gpu) to a DeviceClass. Set "" to omit the field. When autoPartition is true, this is applied to a second class, gpu.amd.com-spx, constrained to whole-GPU (spx) devices only, so classic requests can't resolve to a leftover partition fraction. When autoPartition is false, it stays on the single gpu.amd.com class as before. | | installdefaultNFDRule | bool | `true` | Default NFD rule will detect amd gpu based on pci vendor ID | | kmm.enabled | bool | `true` | Set to true/false to enable/disable the installation of kernel module management (KMM) operator subchart | | kmm.watch | bool | `true` | Set to true/false to enable/disable GPU operator watching and using KMM resources | diff --git a/helm-charts-k8s/crds/deviceconfig-crd.yaml b/helm-charts-k8s/crds/deviceconfig-crd.yaml index c54566694..a303d0cc9 100644 --- a/helm-charts-k8s/crds/deviceconfig-crd.yaml +++ b/helm-charts-k8s/crds/deviceconfig-crd.yaml @@ -152,9 +152,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -266,9 +267,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -359,9 +361,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -462,9 +465,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -723,9 +727,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -1440,7 +1445,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -1530,9 +1535,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -1673,9 +1679,8 @@ spec: description: Required. The taint key to be applied to a node. type: string timeAdded: - description: |- - TimeAdded represents the time at which the taint was added. - It is only written for NoExecute taints. + description: TimeAdded represents the time at which the taint + was added. format: date-time type: string value: @@ -1818,9 +1823,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- diff --git a/helm-charts-k8s/templates/dra-driver-deviceclass.yaml b/helm-charts-k8s/templates/dra-driver-deviceclass.yaml index d4a7e6094..2ef51677f 100644 --- a/helm-charts-k8s/templates/dra-driver-deviceclass.yaml +++ b/helm-charts-k8s/templates/dra-driver-deviceclass.yaml @@ -12,4 +12,36 @@ spec: selectors: - cel: expression: "device.driver == 'gpu.amd.com'" +{{- if and .Values.draDriver.deviceClass.extendedResourceName (not .Values.draDriver.deviceClass.autoPartition) }} + extendedResourceName: {{ .Values.draDriver.deviceClass.extendedResourceName }} +{{- end }} +{{- if .Values.draDriver.deviceClass.autoPartition }} +--- +# When AutoPartition is enabled on the DRA driver, gpu.amd.com's device pool +# includes fractional partition devices (cpx/dpx/qpx) alongside whole GPUs (spx), +# all matched by the same selector above. extendedResourceName moves to this +# second, spx-constrained class instead of staying on the general one, so a +# classic amd.com/gpu request (which carries no selector of its own -- it's +# translated by the apiserver from resources.limits, not authored as a +# ResourceClaim) can only ever resolve to a whole GPU, never a partition +# fraction left over from another claim. +apiVersion: {{ $draApi }} +kind: DeviceClass +metadata: + name: gpu.amd.com-spx + labels: + app.kubernetes.io/component: amd-gpu + app.kubernetes.io/part-of: amd-gpu + {{- include "helm-charts-k8s.labels" . | nindent 4 }} +spec: + selectors: + - cel: + expression: >- + device.driver == 'gpu.amd.com' && + (!has(device.attributes["gpu.amd.com"].computePartition) || + device.attributes["gpu.amd.com"].computePartition == "spx") + {{- with .Values.draDriver.deviceClass.extendedResourceName }} + extendedResourceName: {{ . }} + {{- end }} +{{- end }} {{- end }} diff --git a/helm-charts-k8s/values.yaml b/helm-charts-k8s/values.yaml index 1f676fa3e..c6992bed6 100644 --- a/helm-charts-k8s/values.yaml +++ b/helm-charts-k8s/values.yaml @@ -365,6 +365,17 @@ draDriver: deviceClass: # -- Create the gpu.amd.com DeviceClass resource. Set to false if managing the DRA driver independently. create: true + # -- Maps classic extended-resource requests (e.g. amd.com/gpu) to a DeviceClass. + # Set "" to omit the field. When autoPartition is true, this is applied to a + # second class, gpu.amd.com-spx, constrained to whole-GPU (spx) devices only, so + # classic requests can't resolve to a leftover partition fraction. When + # autoPartition is false, it stays on the single gpu.amd.com class as before. + extendedResourceName: amd.com/gpu + # -- Set to true when DeviceConfig.spec.draDriver.cmdLineArguments enables the + # DRA driver's AutoPartition feature gate on the matching nodes. Must be kept in + # sync with that feature-gates value; it only controls this chart's DeviceClass + # rendering and cannot detect the DeviceConfig's setting automatically. + autoPartition: false kmmModuleLoader: serviceAccount: annotations: {} diff --git a/internal/client/mock_client.go b/internal/client/mock_client.go index ee86fdc91..0c8903d5f 100644 --- a/internal/client/mock_client.go +++ b/internal/client/mock_client.go @@ -59,6 +59,25 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } +// Apply mocks base method. +func (m *MockClient) Apply(arg0 context.Context, arg1 runtime.ApplyConfiguration, arg2 ...client.ApplyOption) error { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Apply", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// Apply indicates an expected call of Apply. +func (mr *MockClientMockRecorder) Apply(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Apply", reflect.TypeOf((*MockClient)(nil).Apply), varargs...) +} + // Create mocks base method. func (m *MockClient) Create(arg0 context.Context, arg1 client.Object, arg2 ...client.CreateOption) error { m.ctrl.T.Helper() @@ -259,25 +278,6 @@ func (mr *MockClientMockRecorder) SubResource(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubResource", reflect.TypeOf((*MockClient)(nil).SubResource), arg0) } -// Apply mocks base method. -func (m *MockClient) Apply(arg0 context.Context, arg1 runtime.ApplyConfiguration, arg2 ...client.ApplyOption) error { - m.ctrl.T.Helper() - varargs := []any{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "Apply", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// Apply indicates an expected call of Apply. -func (mr *MockClientMockRecorder) Apply(arg0, arg1 any, arg2 ...any) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]any{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Apply", reflect.TypeOf((*MockClient)(nil).Apply), varargs...) -} - // Update mocks base method. func (m *MockClient) Update(arg0 context.Context, arg1 client.Object, arg2 ...client.UpdateOption) error { m.ctrl.T.Helper() @@ -320,6 +320,25 @@ func (m *MockStatusWriter) EXPECT() *MockStatusWriterMockRecorder { return m.recorder } +// Apply mocks base method. +func (m *MockStatusWriter) Apply(arg0 context.Context, arg1 runtime.ApplyConfiguration, arg2 ...client.SubResourceApplyOption) error { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Apply", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// Apply indicates an expected call of Apply. +func (mr *MockStatusWriterMockRecorder) Apply(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Apply", reflect.TypeOf((*MockStatusWriter)(nil).Apply), varargs...) +} + // Create mocks base method. func (m *MockStatusWriter) Create(arg0 context.Context, arg1, arg2 client.Object, arg3 ...client.SubResourceCreateOption) error { m.ctrl.T.Helper() diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 966bd09f8..73dbdddb1 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -408,6 +408,14 @@ func (dp *devicePlugin) SetDRADriverAsDesired(ds *appsv1.DaemonSet, devConfig *a Name: "sys", MountPath: "/sys", }, + // Required by the AutoPartition feature's driver-reload paths + // (both non-KMM modprobe and KMM-managed) so the amdgpu kernel + // module can be resolved/reloaded from inside the container. + { + Name: "lib-modules", + MountPath: "/lib/modules", + ReadOnly: true, + }, }, }, }, @@ -456,10 +464,25 @@ func (dp *devicePlugin) SetDRADriverAsDesired(ds *appsv1.DaemonSet, devConfig *a }, }, }, + { + Name: "lib-modules", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/lib/modules", + Type: ptr.To(v1.HostPathDirectory), + }, + }, + }, }, }, }, } + if utils.ShouldUseKMM(devConfig) { + ds.Spec.Template.Spec.Containers[0].Env = append(ds.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{ + Name: "KMM_DRIVER_ENABLED", + Value: "true", + }) + } if devConfig.Spec.DRADriver.UpgradePolicy != nil { up := devConfig.Spec.DRADriver.UpgradePolicy upgradeStrategy := appsv1.RollingUpdateDaemonSetStrategyType diff --git a/internal/plugin/plugin_test.go b/internal/plugin/plugin_test.go index cb0c3f2df..4d6fd30dd 100644 --- a/internal/plugin/plugin_test.go +++ b/internal/plugin/plugin_test.go @@ -176,3 +176,118 @@ var _ = Describe("SetDevicePluginAsDesired", func() { Expect(err.Error()).To(ContainSubstring("daemon set is not initialized")) }) }) + +var _ = Describe("SetDRADriverAsDesired", func() { + var dp *devicePlugin + + BeforeEach(func() { + dp = &devicePlugin{ + client: nil, + scheme: scheme, + isOpenShift: false, + } + }) + + newDevConfig := func(driverEnable bool, driverType string) *amdv1alpha1.DeviceConfig { + return &amdv1alpha1.DeviceConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-config", + Namespace: "test-namespace", + }, + Spec: amdv1alpha1.DeviceConfigSpec{ + Driver: amdv1alpha1.DriverSpec{ + Enable: &driverEnable, + DriverType: driverType, + }, + DRADriver: amdv1alpha1.DRADriverSpec{}, + }, + } + } + + // Both auto-partition reload paths (non-KMM modprobe and KMM-managed) shell + // out to modprobe inside the container, which needs /lib/modules regardless + // of whether KMM manages the driver. + It("always mounts /lib/modules for the amdgpu module reload paths", func() { + ds := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{Name: "test-dra-driver", Namespace: "test-namespace"}, + } + devConfig := newDevConfig(false, "") + + err := dp.SetDRADriverAsDesired(ds, devConfig) + Expect(err).To(BeNil()) + + var foundVolumeMount bool + for _, vm := range ds.Spec.Template.Spec.Containers[0].VolumeMounts { + if vm.Name == "lib-modules" { + Expect(vm.MountPath).To(Equal("/lib/modules")) + Expect(vm.ReadOnly).To(BeTrue()) + foundVolumeMount = true + } + } + Expect(foundVolumeMount).To(BeTrue(), "lib-modules volume mount not found") + + var foundVolume bool + for _, vol := range ds.Spec.Template.Spec.Volumes { + if vol.Name == "lib-modules" { + Expect(vol.HostPath.Path).To(Equal("/lib/modules")) + foundVolume = true + } + } + Expect(foundVolume).To(BeTrue(), "lib-modules volume not found") + }) + + It("sets KMM_DRIVER_ENABLED when the driver is KMM-managed", func() { + ds := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{Name: "test-dra-driver", Namespace: "test-namespace"}, + } + devConfig := newDevConfig(true, utils.DriverTypeContainer) + + err := dp.SetDRADriverAsDesired(ds, devConfig) + Expect(err).To(BeNil()) + + var found bool + for _, e := range ds.Spec.Template.Spec.Containers[0].Env { + if e.Name == "KMM_DRIVER_ENABLED" { + Expect(e.Value).To(Equal("true")) + found = true + } + } + Expect(found).To(BeTrue(), "KMM_DRIVER_ENABLED env var not set") + }) + + It("does not set KMM_DRIVER_ENABLED when the driver is not KMM-managed", func() { + ds := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{Name: "test-dra-driver", Namespace: "test-namespace"}, + } + devConfig := newDevConfig(false, "") + + err := dp.SetDRADriverAsDesired(ds, devConfig) + Expect(err).To(BeNil()) + + for _, e := range ds.Spec.Template.Spec.Containers[0].Env { + Expect(e.Name).NotTo(Equal("KMM_DRIVER_ENABLED")) + } + }) + + It("does not set KMM_DRIVER_ENABLED for pf-passthrough driver type", func() { + ds := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{Name: "test-dra-driver", Namespace: "test-namespace"}, + } + devConfig := newDevConfig(true, utils.DriverTypePFPassthrough) + + err := dp.SetDRADriverAsDesired(ds, devConfig) + Expect(err).To(BeNil()) + + for _, e := range ds.Spec.Template.Spec.Containers[0].Env { + Expect(e.Name).NotTo(Equal("KMM_DRIVER_ENABLED")) + } + }) + + It("should return error when daemonset is nil", func() { + devConfig := newDevConfig(false, "") + + err := dp.SetDRADriverAsDesired(nil, devConfig) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(ContainSubstring("daemon set is not initialized")) + }) +}) From 45e40b4cb648b68fb5568aeddf47db3a60964a79 Mon Sep 17 00:00:00 2001 From: yansun1996 Date: Tue, 22 Sep 2026 11:12:07 +0000 Subject: [PATCH 2/6] chore: regenerate all generated artifacts, fix pensando registry leak make all re-run on this repo's own Makefile (DOCKER_REGISTRY defaults to docker.io/rocm here, vs. registry.test.pensando.io upstream). The prior commit's bundle CSV containerImage field had leaked the pensando-internal registry (copied verbatim from the upstream repo's already-regenerated tree); this run corrects it to docker.io/rocm/amd-gpu-operator:dev via this repo's own generators, plus its accompanying createdAt bump. Also commits the other artifacts a full generate/manifests/helm-k8s pass produces on top of the prior commit: mockgen/controller-gen tool-version output (method ordering, copyright header handling), gofmt struct-literal realignment in upgrademgr.go, and the Chart.lock timestamp bump from the redone helm dependency update. Co-Authored-By: Claude --- api/v1alpha1/zz_generated.deepcopy.go | 16 ---------------- .../amd-gpu-operator.clusterserviceversion.yaml | 4 ++-- helm-charts-k8s/Chart.lock | 2 +- internal/client/mock_client.go | 16 ---------------- internal/configmanager/mock_configmanager.go | 16 ---------------- .../controllers/mock_device_config_reconciler.go | 16 ---------------- internal/controllers/mock_remediation_handler.go | 16 ---------------- internal/controllers/mock_upgrademgr.go | 16 ---------------- internal/controllers/upgrademgr.go | 4 ++-- internal/controllers/watchers/mock_daemonset.go | 16 ---------------- internal/controllers/watchers/mock_node.go | 16 ---------------- internal/controllers/watchers/mock_pod.go | 16 ---------------- internal/controllers/workermgr/mock_workermgr.go | 16 ---------------- internal/kmmmodule/mock_kmmmodule.go | 16 ---------------- internal/metricsexporter/mock_metricsexporter.go | 16 ---------------- internal/nodelabeller/mock_nodelabeller.go | 16 ---------------- internal/plugin/mock_plugin.go | 16 ---------------- internal/testrunner/mock_testrunner.go | 16 ---------------- internal/validator/mock_validator.go | 16 ---------------- 19 files changed, 5 insertions(+), 261 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 8e5463b53..02ad7c8b7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -18,22 +18,6 @@ limitations under the License. // Code generated by controller-gen. DO NOT EDIT. -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package v1alpha1 import ( diff --git a/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml b/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml index f06088821..4b9f89d68 100644 --- a/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml +++ b/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml @@ -35,8 +35,8 @@ metadata: ] capabilities: Seamless Upgrades categories: AI/Machine Learning,Monitoring - containerImage: registry.test.pensando.io:5000/amd-gpu-operator:dev - createdAt: "2026-09-22T10:57:30Z" + containerImage: docker.io/rocm/amd-gpu-operator:dev + createdAt: "2026-09-22T11:09:42Z" description: |- Operator responsible for deploying AMD GPU kernel drivers, device plugin, device test runner and device metrics exporter For more information, visit [documentation](https://instinct.docs.amd.com/projects/gpu-operator/en/latest/) diff --git a/helm-charts-k8s/Chart.lock b/helm-charts-k8s/Chart.lock index 93bfb9da2..19a8c9b04 100644 --- a/helm-charts-k8s/Chart.lock +++ b/helm-charts-k8s/Chart.lock @@ -9,4 +9,4 @@ dependencies: repository: file://./charts/remediation-crds version: v1.0.0 digest: sha256:0806f6b6d7aa21be77bf1c91e720ae3238338a16f107df450a53b02ef940db1b -generated: "2026-09-22T10:57:26.281736805Z" +generated: "2026-09-22T11:09:37.666737039Z" diff --git a/internal/client/mock_client.go b/internal/client/mock_client.go index 0c8903d5f..c4ecf1fec 100644 --- a/internal/client/mock_client.go +++ b/internal/client/mock_client.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: sigs.k8s.io/controller-runtime/pkg/client (interfaces: Client,StatusWriter) // diff --git a/internal/configmanager/mock_configmanager.go b/internal/configmanager/mock_configmanager.go index 66fad93d8..d30d04ba1 100644 --- a/internal/configmanager/mock_configmanager.go +++ b/internal/configmanager/mock_configmanager.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: configmanager.go // diff --git a/internal/controllers/mock_device_config_reconciler.go b/internal/controllers/mock_device_config_reconciler.go index 998b6aa89..355e6587a 100644 --- a/internal/controllers/mock_device_config_reconciler.go +++ b/internal/controllers/mock_device_config_reconciler.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: device_config_reconciler.go // diff --git a/internal/controllers/mock_remediation_handler.go b/internal/controllers/mock_remediation_handler.go index 3ec80bcb3..148160377 100644 --- a/internal/controllers/mock_remediation_handler.go +++ b/internal/controllers/mock_remediation_handler.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: remediation_handler.go // diff --git a/internal/controllers/mock_upgrademgr.go b/internal/controllers/mock_upgrademgr.go index b964eda0c..734db3204 100644 --- a/internal/controllers/mock_upgrademgr.go +++ b/internal/controllers/mock_upgrademgr.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: upgrademgr.go // diff --git a/internal/controllers/upgrademgr.go b/internal/controllers/upgrademgr.go index 6a9dfae22..2e85c8645 100644 --- a/internal/controllers/upgrademgr.go +++ b/internal/controllers/upgrademgr.go @@ -1321,8 +1321,8 @@ func (h *upgradeMgrHelper) getRebootPod(nodeName string, dc *amdv1alpha1.DeviceC ImagePullSecrets: imagePullSecrets, Containers: []v1.Container{ { - Name: "reboot-container", - Image: utilsImage, + Name: "reboot-container", + Image: utilsImage, // Flush filesystems before reboot to avoid exec-format errors from unflushed overlay writes. Command: []string{"/nsenter", "--all", "--target=1", "--", "sh", "-c", "sync; sudo reboot"}, Stdin: true, diff --git a/internal/controllers/watchers/mock_daemonset.go b/internal/controllers/watchers/mock_daemonset.go index 661879116..2f0d48657 100644 --- a/internal/controllers/watchers/mock_daemonset.go +++ b/internal/controllers/watchers/mock_daemonset.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: daemonset.go // diff --git a/internal/controllers/watchers/mock_node.go b/internal/controllers/watchers/mock_node.go index 2edb1e2f9..14b8ece5a 100644 --- a/internal/controllers/watchers/mock_node.go +++ b/internal/controllers/watchers/mock_node.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: node.go // diff --git a/internal/controllers/watchers/mock_pod.go b/internal/controllers/watchers/mock_pod.go index 1c3b74fd0..2cdba056c 100644 --- a/internal/controllers/watchers/mock_pod.go +++ b/internal/controllers/watchers/mock_pod.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: pod.go // diff --git a/internal/controllers/workermgr/mock_workermgr.go b/internal/controllers/workermgr/mock_workermgr.go index 1df171ae2..21a919848 100644 --- a/internal/controllers/workermgr/mock_workermgr.go +++ b/internal/controllers/workermgr/mock_workermgr.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: workermgr.go // diff --git a/internal/kmmmodule/mock_kmmmodule.go b/internal/kmmmodule/mock_kmmmodule.go index 39e50f871..bb608fa44 100644 --- a/internal/kmmmodule/mock_kmmmodule.go +++ b/internal/kmmmodule/mock_kmmmodule.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: kmmmodule.go // diff --git a/internal/metricsexporter/mock_metricsexporter.go b/internal/metricsexporter/mock_metricsexporter.go index caaeaacd6..05d44860f 100644 --- a/internal/metricsexporter/mock_metricsexporter.go +++ b/internal/metricsexporter/mock_metricsexporter.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: metricsexporter.go // diff --git a/internal/nodelabeller/mock_nodelabeller.go b/internal/nodelabeller/mock_nodelabeller.go index df2b214a6..334274291 100644 --- a/internal/nodelabeller/mock_nodelabeller.go +++ b/internal/nodelabeller/mock_nodelabeller.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: nodelabeller.go // diff --git a/internal/plugin/mock_plugin.go b/internal/plugin/mock_plugin.go index 64e03fc0f..86bfd2c92 100644 --- a/internal/plugin/mock_plugin.go +++ b/internal/plugin/mock_plugin.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: plugin.go // diff --git a/internal/testrunner/mock_testrunner.go b/internal/testrunner/mock_testrunner.go index d1aa305ba..ab36316ec 100644 --- a/internal/testrunner/mock_testrunner.go +++ b/internal/testrunner/mock_testrunner.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: testrunner.go // diff --git a/internal/validator/mock_validator.go b/internal/validator/mock_validator.go index 7ee15a646..37f817923 100644 --- a/internal/validator/mock_validator.go +++ b/internal/validator/mock_validator.go @@ -1,19 +1,3 @@ -/* -Copyright (c) Advanced Micro Devices, Inc. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the \"License\"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an \"AS IS\" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Code generated by MockGen. DO NOT EDIT. // Source: validator.go // From 942d77e80749098c7938b1fa7be718bd68cfc3ef Mon Sep 17 00:00:00 2001 From: yansun1996 Date: Tue, 22 Sep 2026 11:13:29 +0000 Subject: [PATCH 3/6] chore: restore AMD copyright headers stripped by mockgen/controller-gen regen make copyrights (a required check) failed on the previous commit: the pinned mockgen@v0.3.0/controller-gen@v0.17.0 versions strip the header on regeneration instead of preserving it. Re-run make copyrights && make fmt and commit the restored headers so the check passes. Co-Authored-By: Claude --- api/v1alpha1/zz_generated.deepcopy.go | 16 ++++++++++++++++ internal/client/mock_client.go | 16 ++++++++++++++++ internal/configmanager/mock_configmanager.go | 16 ++++++++++++++++ .../controllers/mock_device_config_reconciler.go | 16 ++++++++++++++++ internal/controllers/mock_remediation_handler.go | 16 ++++++++++++++++ internal/controllers/mock_upgrademgr.go | 16 ++++++++++++++++ internal/controllers/watchers/mock_daemonset.go | 16 ++++++++++++++++ internal/controllers/watchers/mock_node.go | 16 ++++++++++++++++ internal/controllers/watchers/mock_pod.go | 16 ++++++++++++++++ internal/controllers/workermgr/mock_workermgr.go | 16 ++++++++++++++++ internal/kmmmodule/mock_kmmmodule.go | 16 ++++++++++++++++ internal/metricsexporter/mock_metricsexporter.go | 16 ++++++++++++++++ internal/nodelabeller/mock_nodelabeller.go | 16 ++++++++++++++++ internal/plugin/mock_plugin.go | 16 ++++++++++++++++ internal/testrunner/mock_testrunner.go | 16 ++++++++++++++++ internal/validator/mock_validator.go | 16 ++++++++++++++++ 16 files changed, 256 insertions(+) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 02ad7c8b7..8e5463b53 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -18,6 +18,22 @@ limitations under the License. // Code generated by controller-gen. DO NOT EDIT. +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package v1alpha1 import ( diff --git a/internal/client/mock_client.go b/internal/client/mock_client.go index c4ecf1fec..0c8903d5f 100644 --- a/internal/client/mock_client.go +++ b/internal/client/mock_client.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: sigs.k8s.io/controller-runtime/pkg/client (interfaces: Client,StatusWriter) // diff --git a/internal/configmanager/mock_configmanager.go b/internal/configmanager/mock_configmanager.go index d30d04ba1..66fad93d8 100644 --- a/internal/configmanager/mock_configmanager.go +++ b/internal/configmanager/mock_configmanager.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: configmanager.go // diff --git a/internal/controllers/mock_device_config_reconciler.go b/internal/controllers/mock_device_config_reconciler.go index 355e6587a..998b6aa89 100644 --- a/internal/controllers/mock_device_config_reconciler.go +++ b/internal/controllers/mock_device_config_reconciler.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: device_config_reconciler.go // diff --git a/internal/controllers/mock_remediation_handler.go b/internal/controllers/mock_remediation_handler.go index 148160377..3ec80bcb3 100644 --- a/internal/controllers/mock_remediation_handler.go +++ b/internal/controllers/mock_remediation_handler.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: remediation_handler.go // diff --git a/internal/controllers/mock_upgrademgr.go b/internal/controllers/mock_upgrademgr.go index 734db3204..b964eda0c 100644 --- a/internal/controllers/mock_upgrademgr.go +++ b/internal/controllers/mock_upgrademgr.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: upgrademgr.go // diff --git a/internal/controllers/watchers/mock_daemonset.go b/internal/controllers/watchers/mock_daemonset.go index 2f0d48657..661879116 100644 --- a/internal/controllers/watchers/mock_daemonset.go +++ b/internal/controllers/watchers/mock_daemonset.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: daemonset.go // diff --git a/internal/controllers/watchers/mock_node.go b/internal/controllers/watchers/mock_node.go index 14b8ece5a..2edb1e2f9 100644 --- a/internal/controllers/watchers/mock_node.go +++ b/internal/controllers/watchers/mock_node.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: node.go // diff --git a/internal/controllers/watchers/mock_pod.go b/internal/controllers/watchers/mock_pod.go index 2cdba056c..1c3b74fd0 100644 --- a/internal/controllers/watchers/mock_pod.go +++ b/internal/controllers/watchers/mock_pod.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: pod.go // diff --git a/internal/controllers/workermgr/mock_workermgr.go b/internal/controllers/workermgr/mock_workermgr.go index 21a919848..1df171ae2 100644 --- a/internal/controllers/workermgr/mock_workermgr.go +++ b/internal/controllers/workermgr/mock_workermgr.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: workermgr.go // diff --git a/internal/kmmmodule/mock_kmmmodule.go b/internal/kmmmodule/mock_kmmmodule.go index bb608fa44..39e50f871 100644 --- a/internal/kmmmodule/mock_kmmmodule.go +++ b/internal/kmmmodule/mock_kmmmodule.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: kmmmodule.go // diff --git a/internal/metricsexporter/mock_metricsexporter.go b/internal/metricsexporter/mock_metricsexporter.go index 05d44860f..caaeaacd6 100644 --- a/internal/metricsexporter/mock_metricsexporter.go +++ b/internal/metricsexporter/mock_metricsexporter.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: metricsexporter.go // diff --git a/internal/nodelabeller/mock_nodelabeller.go b/internal/nodelabeller/mock_nodelabeller.go index 334274291..df2b214a6 100644 --- a/internal/nodelabeller/mock_nodelabeller.go +++ b/internal/nodelabeller/mock_nodelabeller.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: nodelabeller.go // diff --git a/internal/plugin/mock_plugin.go b/internal/plugin/mock_plugin.go index 86bfd2c92..64e03fc0f 100644 --- a/internal/plugin/mock_plugin.go +++ b/internal/plugin/mock_plugin.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: plugin.go // diff --git a/internal/testrunner/mock_testrunner.go b/internal/testrunner/mock_testrunner.go index ab36316ec..d1aa305ba 100644 --- a/internal/testrunner/mock_testrunner.go +++ b/internal/testrunner/mock_testrunner.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: testrunner.go // diff --git a/internal/validator/mock_validator.go b/internal/validator/mock_validator.go index 37f817923..7ee15a646 100644 --- a/internal/validator/mock_validator.go +++ b/internal/validator/mock_validator.go @@ -1,3 +1,19 @@ +/* +Copyright (c) Advanced Micro Devices, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the \"License\"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an \"AS IS\" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Code generated by MockGen. DO NOT EDIT. // Source: validator.go // From 9079cbe46c1718bea0e7810e34afff7b8e79383f Mon Sep 17 00:00:00 2001 From: yansun1996 Date: Tue, 22 Sep 2026 23:12:27 +0000 Subject: [PATCH 4/6] fix: align OpenShift's handleDeviceClass with the AutoPartition DeviceClass split On OpenShift, the operator creates the gpu.amd.com DeviceClass itself (internal/controllers/device_config_reconciler.go:handleDeviceClass) instead of via the Helm chart's dra-driver-deviceclass.yaml, since OLM-based installs don't go through Helm. This path never set extendedResourceName at all, so classic amd.com/gpu requests couldn't resolve through DRA on OpenShift -- independent of AutoPartition, and unaffected by the earlier Helm-chart fix. Add utils.ShouldUseAutoPartition, parsing AutoPartition out of DeviceConfig.spec.draDriver.cmdLineArguments' feature-gates string (the only place the gate is configured; there's no dedicated field). Mirror the Helm chart split: AutoPartition off -> single gpu.amd.com class with extendedResourceName; AutoPartition on -> unconstrained gpu.amd.com (no extendedResourceName) plus a new gpu.amd.com-spx constrained to computePartition == spx, carrying extendedResourceName, so a classic request can't land on a partition fraction on OpenShift either. Co-Authored-By: Claude --- .../controllers/device_config_reconciler.go | 49 ++++++++++++--- .../device_config_reconciler_test.go | 59 +++++++++++++++++++ internal/utils.go | 20 +++++++ 3 files changed, 120 insertions(+), 8 deletions(-) diff --git a/internal/controllers/device_config_reconciler.go b/internal/controllers/device_config_reconciler.go index 841f7735d..4012146fc 100644 --- a/internal/controllers/device_config_reconciler.go +++ b/internal/controllers/device_config_reconciler.go @@ -83,6 +83,10 @@ const ( deviceConfigFinalizer = "amd.node.kubernetes.io/deviceconfig-finalizer" testRunnerNodeLabelPrefix = "testrunner.amd.com" deviceClassName = "gpu.amd.com" + // deviceClassExtendedResourceName maps classic amd.com/gpu (resources.limits) + // requests onto DRA devices. Mirrors the default of + // helm-charts-k8s' draDriver.deviceClass.extendedResourceName Helm value. + deviceClassExtendedResourceName = "amd.com/gpu" ) var draAPIVersionPriority = []string{"v1", "v1beta2", "v1beta1"} @@ -1271,40 +1275,69 @@ func (dcrh *deviceConfigReconcilerHelper) handleDeviceClass(ctx context.Context, return nil } - logger := log.FromContext(ctx) - apiVersion := discoverDRAAPIVersion() - logger.Info("Discovered DRA API version", "apiVersion", apiVersion) + log.FromContext(ctx).Info("Discovered DRA API version", "apiVersion", apiVersion) + + if !utils.ShouldUseAutoPartition(devConfig) { + return dcrh.applyDeviceClass(ctx, apiVersion, deviceClassName, + "device.driver == '"+deviceClassName+"'", deviceClassExtendedResourceName) + } + + // When AutoPartition is enabled, gpu.amd.com's device pool includes fractional + // partition devices (cpx/dpx/qpx) alongside whole GPUs (spx), all matched by + // the same selector. A classic amd.com/gpu request (no selector of its own -- + // it's translated by the apiserver from resources.limits, not authored as a + // ResourceClaim) must not be able to resolve to a partition fraction left over + // from another claim, so extendedResourceName moves to a second, + // spx-constrained class instead of staying on the general one. Mirrors + // helm-charts-k8s/templates/dra-driver-deviceclass.yaml. + if err := dcrh.applyDeviceClass(ctx, apiVersion, deviceClassName, + "device.driver == '"+deviceClassName+"'", ""); err != nil { + return err + } + spxExpr := "device.driver == '" + deviceClassName + "' && " + + "(!has(device.attributes[\"" + deviceClassName + "\"].computePartition) || " + + "device.attributes[\"" + deviceClassName + "\"].computePartition == \"spx\")" + return dcrh.applyDeviceClass(ctx, apiVersion, deviceClassName+"-spx", spxExpr, deviceClassExtendedResourceName) +} +// applyDeviceClass creates a DeviceClass named name with the given CEL selector +// expression, setting extendedResourceName when non-empty. A no-op if the +// DeviceClass already exists -- this does not reconcile drift on an existing one. +func (dcrh *deviceConfigReconcilerHelper) applyDeviceClass(ctx context.Context, apiVersion, name, selectorExpr, extendedResourceName string) error { dc := &unstructured.Unstructured{} dc.SetGroupVersionKind(schema.GroupVersionKind{ Group: "resource.k8s.io", Version: apiVersion, Kind: "DeviceClass", }) - dc.SetName(deviceClassName) + dc.SetName(name) dc.SetLabels(map[string]string{ "app.kubernetes.io/component": "amd-gpu", "app.kubernetes.io/part-of": "amd-gpu", }) - dc.Object["spec"] = map[string]interface{}{ + spec := map[string]interface{}{ "selectors": []interface{}{ map[string]interface{}{ "cel": map[string]interface{}{ - "expression": "device.driver == '" + deviceClassName + "'", + "expression": selectorExpr, }, }, }, } + if extendedResourceName != "" { + spec["extendedResourceName"] = extendedResourceName + } + dc.Object["spec"] = spec if err := dcrh.client.Create(ctx, dc); err != nil { if k8serrors.IsAlreadyExists(err) { return nil } - return fmt.Errorf("failed to create DeviceClass %s: %v", deviceClassName, err) + return fmt.Errorf("failed to create DeviceClass %s: %v", name, err) } - logger.Info("Created DeviceClass", "name", deviceClassName, "apiVersion", apiVersion) + log.FromContext(ctx).Info("Created DeviceClass", "name", name, "apiVersion", apiVersion) return nil } diff --git a/internal/controllers/device_config_reconciler_test.go b/internal/controllers/device_config_reconciler_test.go index 846b1418d..cfca72f87 100644 --- a/internal/controllers/device_config_reconciler_test.go +++ b/internal/controllers/device_config_reconciler_test.go @@ -55,6 +55,7 @@ import ( v1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -898,4 +899,62 @@ var _ = Describe("handleDeviceClass", func() { err := dcrh.handleDeviceClass(ctx, draEnabledConfig) Expect(err).To(HaveOccurred()) }) + + It("sets extendedResourceName on the single DeviceClass when AutoPartition is disabled", func() { + ctrl := gomock.NewController(GinkgoT()) + kubeClient = mock_client.NewMockClient(ctrl) + dcrh = newDeviceConfigReconcilerHelper(kubeClient, nil, nil, nil, nil, nil, nil, nil, nil, nil, true, true) + + var created *unstructured.Unstructured + kubeClient.EXPECT().Create(ctx, gomock.Any()).DoAndReturn( + func(_ context.Context, obj client.Object, _ ...client.CreateOption) error { + created = obj.(*unstructured.Unstructured) + return nil + }, + ) + + err := dcrh.handleDeviceClass(ctx, draEnabledConfig) + Expect(err).ToNot(HaveOccurred()) + Expect(created.GetName()).To(Equal("gpu.amd.com")) + ern, found, _ := unstructured.NestedString(created.Object, "spec", "extendedResourceName") + Expect(found).To(BeTrue()) + Expect(ern).To(Equal("amd.com/gpu")) + }) + + It("creates both DeviceClasses when AutoPartition is enabled, extendedResourceName only on the spx class", func() { + ctrl := gomock.NewController(GinkgoT()) + kubeClient = mock_client.NewMockClient(ctrl) + dcrh = newDeviceConfigReconcilerHelper(kubeClient, nil, nil, nil, nil, nil, nil, nil, nil, nil, true, true) + + autoPartitionConfig := &amdv1alpha1.DeviceConfig{ + ObjectMeta: metav1.ObjectMeta{Name: devConfigName, Namespace: devConfigNamespace}, + Spec: amdv1alpha1.DeviceConfigSpec{ + DRADriver: amdv1alpha1.DRADriverSpec{ + Enable: &draEnabled, + CmdLineArguments: map[string]string{"feature-gates": "AutoPartition=true"}, + }, + }, + } + + var created []*unstructured.Unstructured + kubeClient.EXPECT().Create(ctx, gomock.Any()).Times(2).DoAndReturn( + func(_ context.Context, obj client.Object, _ ...client.CreateOption) error { + created = append(created, obj.(*unstructured.Unstructured)) + return nil + }, + ) + + err := dcrh.handleDeviceClass(ctx, autoPartitionConfig) + Expect(err).ToNot(HaveOccurred()) + Expect(created).To(HaveLen(2)) + + Expect(created[0].GetName()).To(Equal("gpu.amd.com")) + _, found, _ := unstructured.NestedString(created[0].Object, "spec", "extendedResourceName") + Expect(found).To(BeFalse()) + + Expect(created[1].GetName()).To(Equal("gpu.amd.com-spx")) + ern, found, _ := unstructured.NestedString(created[1].Object, "spec", "extendedResourceName") + Expect(found).To(BeTrue()) + Expect(ern).To(Equal("amd.com/gpu")) + }) }) diff --git a/internal/utils.go b/internal/utils.go index bf66674f3..11374b6bd 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -506,3 +506,23 @@ func ShouldUseKMM(devConfig *v1alpha1.DeviceConfig) bool { } return false } + +// ShouldUseAutoPartition reports whether the DRA driver's AutoPartition feature +// gate is enabled via DeviceConfig.spec.draDriver.cmdLineArguments, e.g. +// cmdLineArguments: {feature-gates: "AutoPartition=true"}. This is the only +// place AutoPartition is configured today -- there is no dedicated DeviceConfig +// field for it -- so this parses the same "key=value,key=value" string the DRA +// driver's own --feature-gates flag accepts. +func ShouldUseAutoPartition(devConfig *v1alpha1.DeviceConfig) bool { + if devConfig == nil { + return false + } + gates := devConfig.Spec.DRADriver.CmdLineArguments["feature-gates"] + for _, pair := range strings.Split(gates, ",") { + kv := strings.SplitN(strings.TrimSpace(pair), "=", 2) + if len(kv) == 2 && kv[0] == "AutoPartition" { + return kv[1] == "true" + } + } + return false +} From 1a5004e3afe6250cb4929d4cc5f68d9a95395522 Mon Sep 17 00:00:00 2001 From: yansun1996 Date: Wed, 23 Sep 2026 02:36:20 +0000 Subject: [PATCH 5/6] fix: grant dra-driver RBAC to delete NodeModulesConfig for KMM-managed reload Live hardware validation of the KMM-managed AutoPartition path (driver.enable via KMM, KMM_DRIVER_ENABLED=true) found the second half of pkg/kmm.Recoverer.TriggerReload never completes: the amdgpu module unloads fine, but the subsequent NodeModulesConfig delete (what makes KMM re-provision and reload the driver) silently fails, because the dra-driver ClusterRole was never granted permission on kmm.sigs.x-k8s.io/nodemodulesconfigs at all. The module stayed unloaded until manually unstuck (kubectl delete nodemodulesconfigs ) -- without this, every KMM-managed partition-mode change on a real cluster would hang the claim indefinitely. Added get+delete on nodemodulesconfigs to config/rbac/dra_driver_cluster_role.yaml (feeds the kustomize/OLM-bundle path) and hack/k8s-patch/template-patch/dra-driver-rbac.yaml (the k8s Helm chart's true source -- make helm-k8s copies over the generated helm-charts-k8s/templates/dra-driver-rbac.yaml from it). Regenerated via make helm-k8s; diffed byte-for-byte identical to hand-editing both files, confirming no other drift. --- config/rbac/dra_driver_cluster_role.yaml | 7 +++++++ hack/k8s-patch/template-patch/dra-driver-rbac.yaml | 7 +++++++ helm-charts-k8s/Chart.lock | 2 +- helm-charts-k8s/templates/dra-driver-rbac.yaml | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/config/rbac/dra_driver_cluster_role.yaml b/config/rbac/dra_driver_cluster_role.yaml index 5f2069856..bd3a230c1 100644 --- a/config/rbac/dra_driver_cluster_role.yaml +++ b/config/rbac/dra_driver_cluster_role.yaml @@ -35,3 +35,10 @@ rules: - nodes verbs: - get +- apiGroups: + - kmm.sigs.x-k8s.io + resources: + - nodemodulesconfigs + verbs: + - get + - delete diff --git a/hack/k8s-patch/template-patch/dra-driver-rbac.yaml b/hack/k8s-patch/template-patch/dra-driver-rbac.yaml index b0da170f2..54eac91b9 100644 --- a/hack/k8s-patch/template-patch/dra-driver-rbac.yaml +++ b/hack/k8s-patch/template-patch/dra-driver-rbac.yaml @@ -31,6 +31,13 @@ rules: - update - patch - delete +- apiGroups: + - kmm.sigs.x-k8s.io + resources: + - nodemodulesconfigs + verbs: + - get + - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/helm-charts-k8s/Chart.lock b/helm-charts-k8s/Chart.lock index 19a8c9b04..91156efbe 100644 --- a/helm-charts-k8s/Chart.lock +++ b/helm-charts-k8s/Chart.lock @@ -9,4 +9,4 @@ dependencies: repository: file://./charts/remediation-crds version: v1.0.0 digest: sha256:0806f6b6d7aa21be77bf1c91e720ae3238338a16f107df450a53b02ef940db1b -generated: "2026-09-22T11:09:37.666737039Z" +generated: "2026-09-23T02:35:29.920413913Z" diff --git a/helm-charts-k8s/templates/dra-driver-rbac.yaml b/helm-charts-k8s/templates/dra-driver-rbac.yaml index b0da170f2..54eac91b9 100644 --- a/helm-charts-k8s/templates/dra-driver-rbac.yaml +++ b/helm-charts-k8s/templates/dra-driver-rbac.yaml @@ -31,6 +31,13 @@ rules: - update - patch - delete +- apiGroups: + - kmm.sigs.x-k8s.io + resources: + - nodemodulesconfigs + verbs: + - get + - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding From 095839dfe63bdc53c0d5a8ebf18ed562a02974ab Mon Sep 17 00:00:00 2001 From: yansun1996 Date: Wed, 23 Sep 2026 02:57:21 +0000 Subject: [PATCH 6/6] chore: propagate dra-driver NodeModulesConfig RBAC into the OLM bundle CSV make bundle-build regenerates the CSV's clusterPermissions from config/rbac/dra_driver_cluster_role.yaml via kustomize. That source already had the get+delete nodemodulesconfigs rule (previous commit), but the CSV itself hadn't been regenerated, so OpenShift/OLM-based installs were still missing the same permission the Helm path was just fixed for. Confirmed via make helm && make bundle-build: only the CSV's clusterPermissions and the expected Chart.lock timestamp changed, nothing else. --- .../amd-gpu-operator.clusterserviceversion.yaml | 9 ++++++++- helm-charts-k8s/Chart.lock | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml b/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml index 4b9f89d68..295d65673 100644 --- a/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml +++ b/bundle/manifests/amd-gpu-operator.clusterserviceversion.yaml @@ -36,7 +36,7 @@ metadata: capabilities: Seamless Upgrades categories: AI/Machine Learning,Monitoring containerImage: docker.io/rocm/amd-gpu-operator:dev - createdAt: "2026-09-22T11:09:42Z" + createdAt: "2026-09-23T02:56:40Z" description: |- Operator responsible for deploying AMD GPU kernel drivers, device plugin, device test runner and device metrics exporter For more information, visit [documentation](https://instinct.docs.amd.com/projects/gpu-operator/en/latest/) @@ -1476,6 +1476,13 @@ spec: - nodes verbs: - get + - apiGroups: + - kmm.sigs.x-k8s.io + resources: + - nodemodulesconfigs + verbs: + - get + - delete serviceAccountName: amd-gpu-operator-dra-driver - rules: - apiGroups: diff --git a/helm-charts-k8s/Chart.lock b/helm-charts-k8s/Chart.lock index 91156efbe..e9b9f562a 100644 --- a/helm-charts-k8s/Chart.lock +++ b/helm-charts-k8s/Chart.lock @@ -9,4 +9,4 @@ dependencies: repository: file://./charts/remediation-crds version: v1.0.0 digest: sha256:0806f6b6d7aa21be77bf1c91e720ae3238338a16f107df450a53b02ef940db1b -generated: "2026-09-23T02:35:29.920413913Z" +generated: "2026-09-23T02:56:24.120766399Z"