Skip to content

Commit aff2736

Browse files
Add GPUClusterConfig Helm install with ClusterPolicy mutual exclusion
Signed-off-by: Karthik Vetrivel <kvetrivel@nvidia.com>
1 parent 87fa6c0 commit aff2736

14 files changed

Lines changed: 263 additions & 6 deletions

config/rbac/role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ rules:
142142
- patch
143143
- update
144144
- watch
145+
- apiGroups:
146+
- nvidia.com
147+
resources:
148+
- clusterpolicies
149+
verbs:
150+
- get
151+
- list
152+
- watch
145153
- apiGroups:
146154
- nvidia.com
147155
resources:

config/samples/nvidia_v1alpha1_gpuclusterconfig.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ metadata:
44
name: gpuclusterconfig-sample
55
spec:
66
draDriver:
7-
repository: nvcr.io/nvidia
8-
image: k8s-dra-driver-gpu
9-
version: v0.1.0
7+
repository: registry.k8s.io/dra-driver-nvidia
8+
image: dra-driver-nvidia-gpu
9+
version: v0.4.0
1010
imagePullPolicy: IfNotPresent
1111
imagePullSecrets: []
1212
# NOTE: a driver-validation init container config block (e.g. `validator:`) is

controllers/gpuclusterconfig_controller.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3535
"sigs.k8s.io/controller-runtime/pkg/source"
3636

37+
gpuv1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1"
3738
nvidiav1alpha1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1alpha1"
3839
"github.com/NVIDIA/gpu-operator/controllers/clusterinfo"
3940
"github.com/NVIDIA/gpu-operator/internal/conditions"
@@ -59,6 +60,7 @@ type GPUClusterConfigReconciler struct {
5960
//+kubebuilder:rbac:groups=nvidia.com,resources=gpuclusterconfigs,verbs=get;list;watch;create;update;patch;delete
6061
//+kubebuilder:rbac:groups=nvidia.com,resources=gpuclusterconfigs/status,verbs=get;update;patch
6162
//+kubebuilder:rbac:groups=nvidia.com,resources=gpuclusterconfigs/finalizers,verbs=update
63+
//+kubebuilder:rbac:groups=nvidia.com,resources=clusterpolicies,verbs=get;list;watch
6264

6365
func (r *GPUClusterConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
6466
logger := log.FromContext(ctx)
@@ -79,6 +81,24 @@ func (r *GPUClusterConfigReconciler) Reconcile(ctx context.Context, req ctrl.Req
7981
return ctrl.Result{}, wrappedErr
8082
}
8183

84+
// GPUClusterConfig (DRA path) is mutually exclusive with ClusterPolicy: if one
85+
// exists, yield to it rather than deploying the DRA stack alongside it.
86+
clusterPolicies := &gpuv1.ClusterPolicyList{}
87+
if err := r.List(ctx, clusterPolicies); err != nil {
88+
return ctrl.Result{}, fmt.Errorf("error listing ClusterPolicies: %w", err)
89+
}
90+
if len(clusterPolicies.Items) > 0 {
91+
logger.V(consts.LogLevelWarning).Info("ClusterPolicy present, skipping mutually exclusive GPUClusterConfig")
92+
if err := r.updateCrStatus(ctx, instance, nvidiav1alpha1.Disabled); err != nil {
93+
return ctrl.Result{}, err
94+
}
95+
msg := "GPUClusterConfig is mutually exclusive with ClusterPolicy; remove the ClusterPolicy or disable GPUClusterConfig"
96+
if condErr := r.conditionUpdater.SetConditionsError(ctx, instance, conditions.ReconcileFailed, msg); condErr != nil {
97+
logger.Error(condErr, "failed to set condition")
98+
}
99+
return ctrl.Result{}, nil
100+
}
101+
82102
// Singleton, first-wins (mirroring ClusterPolicy): the first instance to reconcile
83103
// claims ownership; any other instance is marked Ignored and skipped. The owner is
84104
// held in memory, so the choice resets on operator restart.

controllers/gpuclusterconfig_controller_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"sigs.k8s.io/controller-runtime/pkg/client"
3131
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3232

33+
gpuv1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1"
3334
nvidiav1alpha1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1alpha1"
3435
"github.com/NVIDIA/gpu-operator/internal/conditions"
3536
"github.com/NVIDIA/gpu-operator/internal/state"
@@ -42,6 +43,7 @@ func newGPUClusterConfigReconciler(t *testing.T, objs ...client.Object) (*GPUClu
4243

4344
scheme := runtime.NewScheme()
4445
require.NoError(t, nvidiav1alpha1.AddToScheme(scheme))
46+
require.NoError(t, gpuv1.AddToScheme(scheme))
4547

4648
c := fake.NewClientBuilder().
4749
WithScheme(scheme).
@@ -110,6 +112,18 @@ func TestGPUClusterConfigReconcileNotFound(t *testing.T) {
110112
require.Zero(t, res)
111113
}
112114

115+
// A ClusterPolicy in the cluster disables the GPUClusterConfig: the two paths are
116+
// mutually exclusive, so the DRA stack is not deployed alongside ClusterPolicy.
117+
func TestGPUClusterConfigDisabledByClusterPolicy(t *testing.T) {
118+
cfg := &nvidiav1alpha1.GPUClusterConfig{ObjectMeta: metav1.ObjectMeta{Name: "config"}}
119+
cp := &gpuv1.ClusterPolicy{ObjectMeta: metav1.ObjectMeta{Name: "cluster-policy"}}
120+
r, c := newGPUClusterConfigReconciler(t, cfg, cp)
121+
122+
gccReconcile(t, r, cfg.Name)
123+
124+
require.Equal(t, nvidiav1alpha1.Disabled, gccState(t, c, cfg.Name))
125+
}
126+
113127
// First-reconciled wins (mirroring ClusterPolicy): whichever instance reconciles first
114128
// claims ownership, regardless of name or creationTimestamp.
115129
func TestGPUClusterConfigSingleton(t *testing.T) {

deployments/gpu-operator/templates/cleanup_crd.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ spec:
4040
- delete
4141
- --filepath=/opt/gpu-operator/nvidia.com_clusterpolicies.yaml
4242
- --filepath=/opt/gpu-operator/nvidia.com_nvidiadrivers.yaml
43+
- --filepath=/opt/gpu-operator/nvidia.com_gpuclusterconfigs.yaml
4344
{{- if .Values.nfd.enabled }}
4445
- --filepath=/opt/gpu-operator/nfd-api-crds.yaml
4546
{{- end }}

deployments/gpu-operator/templates/clusterpolicy.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{{- /* ClusterPolicy is mutually exclusive with the DRA path; skip it when gpuClusterConfig is enabled. */ -}}
2+
{{- if not .Values.gpuClusterConfig.enabled }}
13
apiVersion: nvidia.com/v1
24
kind: ClusterPolicy
35
metadata:
@@ -815,3 +817,4 @@ spec:
815817
{{- if .Values.kataSandboxDevicePlugin.hostNetwork }}
816818
hostNetwork: {{ .Values.kataSandboxDevicePlugin.hostNetwork }}
817819
{{- end }}
820+
{{- end }}

deployments/gpu-operator/templates/clusterrole.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,16 @@ rules:
263263
- list
264264
- watch
265265
- patch
266+
- apiGroups:
267+
- admissionregistration.k8s.io
268+
resources:
269+
- validatingadmissionpolicies
270+
- validatingadmissionpolicybindings
271+
verbs:
272+
- get
273+
- list
274+
- watch
275+
- create
276+
- update
277+
- patch
278+
- delete
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{{- if .Values.gpuClusterConfig.enabled }}
2+
{{- $dra := .Values.gpuClusterConfig.draDriver }}
3+
apiVersion: nvidia.com/v1alpha1
4+
kind: GPUClusterConfig
5+
metadata:
6+
name: gpu-cluster-config
7+
labels:
8+
{{- include "gpu-operator.labels" . | nindent 4 }}
9+
app.kubernetes.io/component: "gpu-operator"
10+
{{- if .Values.operator.cleanupCRD }}
11+
# CR cleanup is handled during pre-delete hook
12+
# Add below annotation so that helm doesn't attempt to cleanup CR twice
13+
annotations:
14+
"helm.sh/resource-policy": keep
15+
{{- end }}
16+
spec:
17+
draDriver:
18+
repository: {{ $dra.repository }}
19+
image: {{ $dra.image }}
20+
version: {{ $dra.version }}
21+
{{- if $dra.imagePullPolicy }}
22+
imagePullPolicy: {{ $dra.imagePullPolicy }}
23+
{{- end }}
24+
{{- with $dra.imagePullSecrets }}
25+
imagePullSecrets:
26+
{{- toYaml . | nindent 6 }}
27+
{{- end }}
28+
{{- with $dra.featureGates }}
29+
featureGates:
30+
{{- toYaml . | nindent 6 }}
31+
{{- end }}
32+
gpus:
33+
enabled: {{ $dra.gpus.enabled }}
34+
{{- with $dra.gpus.kubeletPlugin }}
35+
kubeletPlugin:
36+
{{- toYaml . | nindent 8 }}
37+
{{- end }}
38+
computeDomains:
39+
enabled: {{ $dra.computeDomains.enabled }}
40+
{{- with $dra.computeDomains.controller }}
41+
controller:
42+
{{- toYaml . | nindent 8 }}
43+
{{- end }}
44+
{{- with $dra.computeDomains.kubeletPlugin }}
45+
kubeletPlugin:
46+
{{- toYaml . | nindent 8 }}
47+
{{- end }}
48+
hostPaths:
49+
rootFS: {{ .Values.hostPaths.rootFS }}
50+
driverInstallDir: {{ .Values.hostPaths.driverInstallDir }}
51+
{{- if .Values.hostPaths.kubeletRootDir }}
52+
kubeletRootDir: {{ .Values.hostPaths.kubeletRootDir }}
53+
{{- end }}
54+
daemonsets:
55+
{{- toYaml .Values.daemonsets | nindent 4 }}
56+
{{- end }}

deployments/gpu-operator/values.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,59 @@ ccManager:
557557
resources: {}
558558
hostNetwork: false
559559

560+
# gpuClusterConfig deploys the DRA-based GPU enablement stack (the NVIDIA DRA
561+
# driver for GPUs) via a GPUClusterConfig CR, as an alternative to the classic
562+
# device-plugin path. This is an alpha feature (nvidia.com/v1alpha1) and is
563+
# disabled by default.
564+
#
565+
# NOTE: when enabling this, the classic NVIDIA device plugin should be disabled
566+
# (devicePlugin.enabled=false) to avoid conflicts, and an NVIDIA driver (>= 580)
567+
# with CDI must be available (host-installed or via driver.enabled / an
568+
# NVIDIADriver CR). GPUClusterConfig does not manage the driver or device plugin
569+
# itself; it waits for driver readiness before deploying the DRA driver.
570+
gpuClusterConfig:
571+
enabled: false
572+
draDriver:
573+
repository: registry.k8s.io/dra-driver-nvidia
574+
image: dra-driver-nvidia-gpu
575+
version: v0.4.0
576+
imagePullPolicy: IfNotPresent
577+
imagePullSecrets: []
578+
# featureGates toggles DRA driver feature gates; rendered as FEATURE_GATES.
579+
# e.g. featureGates: {MPSSupport: true, NVMLDeviceHealthCheck: true}
580+
featureGates: {}
581+
# gpus configures the gpu.nvidia.com / mig.nvidia.com / vfio.gpu.nvidia.com
582+
# capability (the gpus container of the kubelet-plugin DaemonSet).
583+
gpus:
584+
enabled: true
585+
# kubeletPlugin overrides scheduling/resources for the gpus container.
586+
# All fields are optional:
587+
kubeletPlugin: {}
588+
# env: [] # list of {name, value}
589+
# resources: {} # requests/limits
590+
# healthcheckPort: 51000 # negative value disables the health probe
591+
# priorityClassName: system-node-critical
592+
# nodeSelector: {}
593+
# tolerations: []
594+
# affinity: {}
595+
# computeDomains configures the Multi-Node NVLink (MNNVL) compute-domain
596+
# capability: a controller Deployment plus the compute-domains kubelet-plugin
597+
# container.
598+
computeDomains:
599+
enabled: true
600+
# controller overrides scheduling/resources for the compute-domain
601+
# controller Deployment. All fields are optional:
602+
controller: {}
603+
# env: []
604+
# resources: {}
605+
# priorityClassName: system-node-critical
606+
# nodeSelector: {}
607+
# tolerations: []
608+
# affinity: {}
609+
# kubeletPlugin overrides the compute-domains container (same fields as
610+
# gpus.kubeletPlugin above).
611+
kubeletPlugin: {}
612+
560613
# Array of extra K8s manifests to deploy
561614
# Supports use of custom Helm templates
562615
extraObjects: []

docker/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ COPY validator/manifests /opt/validator/manifests
121121
# Add CRD resource into the image for helm upgrades
122122
COPY deployments/gpu-operator/crds/nvidia.com_clusterpolicies.yaml /opt/gpu-operator/nvidia.com_clusterpolicies.yaml
123123
COPY deployments/gpu-operator/crds/nvidia.com_nvidiadrivers.yaml /opt/gpu-operator/nvidia.com_nvidiadrivers.yaml
124+
COPY deployments/gpu-operator/crds/nvidia.com_gpuclusterconfigs.yaml /opt/gpu-operator/nvidia.com_gpuclusterconfigs.yaml
124125
COPY deployments/gpu-operator/charts/node-feature-discovery/crds/nfd-api-crds.yaml /opt/gpu-operator/nfd-api-crds.yaml
125126

126127
USER 65532:65532

0 commit comments

Comments
 (0)