Skip to content

Commit ac5b0ee

Browse files
committed
[SPARK-59519] Add opt-in Kueue RBAC rules to Helm chart
### What changes were proposed in this pull request? This PR adds an opt-in Helm value `operatorRbac.kueue.enabled` (default `false`). When enabled, the operator is granted the RBAC rules that [Kueue](https://kueue.sigs.k8s.io/docs/tasks/dev/integrate_a_custom_job/) requires from an external framework integration: | Group / Resource | Verbs | Granted via | |---|---|---| | `kueue.x-k8s.io` / `workloads` | get, list, watch, create, update, patch, delete | ClusterRole and Role | | `kueue.x-k8s.io` / `workloads/status` | get, update, patch | ClusterRole and Role | | `kueue.x-k8s.io` / `workloads/finalizers` | update | ClusterRole and Role | | `kueue.x-k8s.io` / `resourceflavors`, `workloadpriorityclasses` | get, list, watch | ClusterRole only | | `scheduling.k8s.io` / `priorityclasses` | get, list, watch | ClusterRole only | The namespaced `workloads` rules live in the shared `operatorRbacRules` block under `{{- if }}`, like the existing `leases` rule. The cluster-scoped resources go into a new `operatorClusterRbacRules` wrapper used only by the ClusterRole, since a namespaced Role cannot grant them. `events.k8s.io/events` from the Kueue doc is intentionally left out: the operator only emits core `events`, which are already granted. Also included: `helm test` assertions for the new grants, a `helm-tests` CI group `kueue` that installs Kueue v0.19.4 and runs them, a check that `workloads` create is denied with the default values, and a `docs/operations.md` entry. ### Why are the changes needed? This is the deployment-side preparation for the Kueue integration (SPARK-59486, SPARK-59490, SPARK-59503). Keeping the grant opt-in avoids widening the operator ClusterRole for users who do not run Kueue. The operator runtime changes and the Kueue-side `integrations.externalFrameworks` configuration are out of scope. ### Does this PR introduce _any_ user-facing change? Yes, a new Helm value `operatorRbac.kueue.enabled` (default `false`). With the default, the rendered manifests are identical to the current chart. ### How was this patch tested? - `helm lint --strict` passes. - `helm template` output with the default values is identical to `main`; with `operatorRbac.kueue.enabled=true` the ClusterRole gets all five rules and, when `operatorRbac.role.create=true`, each workload-namespace Role gets only the three `workloads` rules. - `--set operatorRbac.kueue=null` is now rejected by the values schema like every other `operatorRbac` block. - New `helm-tests / kueue` CI job: installs Kueue, runs `helm test` with the value enabled, then upgrades to the default values and asserts the operator service account is denied `create` on `workloads.kueue.x-k8s.io`. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Claude Fable 5.1 Closes #827 from dongjoon-hyun/SPARK-59519. Authored-by: Dongjoon Hyun <dongjoon@apache.org> Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
1 parent df96061 commit ac5b0ee

7 files changed

Lines changed: 142 additions & 2 deletions

File tree

‎.github/workflows/build_and_test.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ jobs:
238238
- "1.37.0"
239239
test-group:
240240
- configmap-metadata
241+
- kueue
241242
- network-policy
242243
- operator-command
243244
steps:
@@ -267,6 +268,13 @@ jobs:
267268
run: |
268269
kubectl get pods -A
269270
kubectl describe node
271+
- name: Install Kueue
272+
if: matrix.test-group == 'kueue'
273+
run: |
274+
kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.19.4/manifests.yaml
275+
# Kueue installs webhooks for pods, deployments and statefulsets with failurePolicy=Fail,
276+
# so wait for the controller (whose readyz covers the webhook server) before helm install.
277+
kubectl wait deploy/kueue-controller-manager -n kueue-system --for=condition=Available --timeout=5m
270278
- name: Run Spark K8s Operator Helm Tests
271279
run: |
272280
eval $(minikube docker-env)
@@ -277,6 +285,15 @@ jobs:
277285
build-tools/helm/spark-kubernetes-operator/
278286
minikube docker-env --unset
279287
helm test spark
288+
- name: Verify Kueue RBAC is denied by default
289+
if: matrix.test-group == 'kueue'
290+
run: |
291+
# The same impersonated check must answer "yes" first, otherwise a wrong subject
292+
# would make the denial below vacuous.
293+
kubectl auth can-i create workloads.kueue.x-k8s.io --as=system:serviceaccount:default:spark-operator
294+
helm upgrade spark -f build-tools/helm/spark-kubernetes-operator/values.yaml \
295+
build-tools/helm/spark-kubernetes-operator/
296+
if kubectl auth can-i create workloads.kueue.x-k8s.io --as=system:serviceaccount:default:spark-operator; then exit 1; fi
280297
lint:
281298
name: "Linter and documentation"
282299
runs-on: ubuntu-26.04

‎build-tools/helm/spark-kubernetes-operator/templates/operator-rbac.yaml‎

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,61 @@ rules:
122122
- patch
123123
- delete
124124
{{- end }}
125+
{{- if .Values.operatorRbac.kueue.enabled }}
126+
- apiGroups:
127+
- "kueue.x-k8s.io"
128+
resources:
129+
- workloads
130+
verbs:
131+
- get
132+
- list
133+
- watch
134+
- create
135+
- update
136+
- patch
137+
- delete
138+
- apiGroups:
139+
- "kueue.x-k8s.io"
140+
resources:
141+
- workloads/status
142+
verbs:
143+
- get
144+
- update
145+
- patch
146+
- apiGroups:
147+
- "kueue.x-k8s.io"
148+
resources:
149+
- workloads/finalizers
150+
verbs:
151+
- update
152+
{{- end }}
153+
{{- end }}
154+
155+
{{/*
156+
RBAC rules used to create the operator clusterrole: the shared rules above plus
157+
the rules for cluster-scoped resources, which a namespaced role cannot grant
158+
*/}}
159+
{{- define "spark-operator.operatorClusterRbacRules" }}
160+
{{- include "spark-operator.operatorRbacRules" . }}
161+
{{- if .Values.operatorRbac.kueue.enabled }}
162+
- apiGroups:
163+
- "kueue.x-k8s.io"
164+
resources:
165+
- resourceflavors
166+
- workloadpriorityclasses
167+
verbs:
168+
- get
169+
- list
170+
- watch
171+
- apiGroups:
172+
- "scheduling.k8s.io"
173+
resources:
174+
- priorityclasses
175+
verbs:
176+
- get
177+
- list
178+
- watch
179+
{{- end }}
125180
{{- end }}
126181

127182
{{/*
@@ -170,7 +225,7 @@ kind: ClusterRole
170225
metadata:
171226
name: {{ .Values.operatorRbac.clusterRole.name }}
172227
{{- template "spark-operator.rbacLabelsAnnotations" $ }}
173-
{{- template "spark-operator.operatorRbacRules" $ }}
228+
{{- template "spark-operator.operatorClusterRbacRules" $ }}
174229
---
175230
{{- end }}
176231
{{- if and (eq (include "spark-operator.dynamicConfig.enabled" .) "true") (eq .Values.operatorConfiguration.dynamicConfig.source "configMap") }}

‎build-tools/helm/spark-kubernetes-operator/templates/tests/test-rbac.yaml‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,22 @@ spec:
7777
kubectl auth can-i watch grpcroutes.gateway.networking.k8s.io --all-namespaces
7878
kubectl auth can-i create grpcroutes.gateway.networking.k8s.io --all-namespaces
7979
fi
80+
{{- if .Values.operatorRbac.kueue.enabled }}
81+
82+
# The Kueue grant is opt-in and, like Gateway API, can only be asserted
83+
# where the Kueue CRDs are installed.
84+
if kubectl api-resources --api-group=kueue.x-k8s.io --no-headers -o name | grep -q workloads; then
85+
kubectl auth can-i watch workloads.kueue.x-k8s.io --all-namespaces
86+
kubectl auth can-i create workloads.kueue.x-k8s.io --all-namespaces
87+
kubectl auth can-i patch workloads.kueue.x-k8s.io --subresource=status --all-namespaces
88+
kubectl auth can-i update workloads.kueue.x-k8s.io --subresource=finalizers --all-namespaces
89+
kubectl auth can-i watch resourceflavors.kueue.x-k8s.io
90+
kubectl auth can-i watch workloadpriorityclasses.kueue.x-k8s.io
91+
fi
92+
93+
# PriorityClass is built in, so this one needs no CRD-presence guard.
94+
kubectl auth can-i watch priorityclasses.scheduling.k8s.io
95+
{{- end }}
8096
8197
# The operator must not be cluster-admin. These also prove the suite is
8298
# able to observe a denial at all. `set -e` ignores a failing `!`

‎build-tools/helm/spark-kubernetes-operator/values.schema.json‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,8 @@
428428
"clusterRoleBinding",
429429
"role",
430430
"roleBinding",
431-
"configManagement"
431+
"configManagement",
432+
"kueue"
432433
],
433434
"properties": {
434435
"serviceAccount": {
@@ -567,6 +568,19 @@
567568
}
568569
}
569570
},
571+
"kueue": {
572+
"type": "object",
573+
"description": "Kueue integration RBAC",
574+
"required": [
575+
"enabled"
576+
],
577+
"properties": {
578+
"enabled": {
579+
"type": "boolean",
580+
"description": "Whether to grant the operator access to Kueue resources"
581+
}
582+
}
583+
},
570584
"labels": {
571585
"type": "object",
572586
"description": "Labels for RBAC resources",

‎build-tools/helm/spark-kubernetes-operator/values.yaml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ operatorRbac:
137137
create: true
138138
roleName: "spark-operator-config-monitor"
139139
roleBindingName: "spark-operator-config-monitor-role-binding"
140+
kueue:
141+
# If enabled, the operator (cluster)role would be granted access to Kueue workloads.
142+
# The cluster-scoped resourceflavors, workloadpriorityclasses and priorityclasses are
143+
# granted through the ClusterRole only, so {operatorRbac.clusterRole.create} is required
144+
# for the operator to read them. Kueue itself must be installed separately.
145+
enabled: false
140146
labels:
141147
"app.kubernetes.io/component": "operator-rbac"
142148

‎docs/operations.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ under the License.
3737
implementation such as Istio) before submitting SparkApplications that request Gateway API
3838
routing. If the CRDs are missing, reconciliation of such SparkApplications will fail with a
3939
`no matches for kind "HTTPRoute"` error from the Kubernetes API.
40+
- **Kueue** (`workloads.kueue.x-k8s.io`, `resourceflavors.kueue.x-k8s.io`,
41+
`workloadpriorityclasses.kueue.x-k8s.io`) — required only when `operatorRbac.kueue.enabled` is
42+
set. Kueue is not bundled with the operator; install it from
43+
[kueue.sigs.k8s.io](https://kueue.sigs.k8s.io/docs/installation/), and register
44+
`SparkApplication.v1.spark.apache.org` and `SparkCluster.v1.spark.apache.org` in Kueue's
45+
`integrations.externalFrameworks`.
4046

4147
## Spark Application Namespaces
4248

@@ -108,6 +114,7 @@ following table:
108114
| operatorRbac.configManagement.create | Enable this to create a Role for operator configuration management (hot property loading and leader election). | true |
109115
| operatorRbac.configManagement.roleName | Role name for operator configuration management. | `spark-operator-config-role` |
110116
| operatorRbac.configManagement.roleBinding | RoleBinding name for operator configuration management. | `"spark-operator-config-monitor-role-binding"` |
117+
| operatorRbac.kueue.enabled | Grant the operator access to Kueue `workloads`, `resourceflavors`, `workloadpriorityclasses` and to `priorityclasses`. The cluster-scoped ones need `clusterRole.create`. See [Optional Prerequisites](#optional-prerequisites). | false |
111118
| operatorRbac.labels | Labels to be applied on all created `operatorRbac` resources. | `"app.kubernetes.io/component": "operator-rbac"` |
112119
| workloadResources.namespaces.create | Whether to create dedicated namespaces for Spark workload. | true |
113120
| workloadResources.namespaces.overrideWatchedNamespaces | When enabled, operator would by default only watch namespace(s) provided in data field. | true |
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# Test values for validating the opt-in Kueue RBAC rules. The Kueue CRDs must be installed
17+
# on the cluster for the `helm test` assertions to run.
18+
#
19+
# Usage:
20+
# helm install spark-operator . -f tests/e2e/helm/helm-test-values/kueue/values.yaml
21+
# helm test spark-operator
22+
23+
operatorRbac:
24+
kueue:
25+
enabled: true

0 commit comments

Comments
 (0)