From 7201bb2b8ea13e7db7d0ce1d863fd0ac0905d1f8 Mon Sep 17 00:00:00 2001 From: ghkdwlgns612 Date: Wed, 22 Jul 2026 22:06:25 +0900 Subject: [PATCH 1/2] feat(helm): allow specifying existing serviceAccountName for router and lora-controller to skip SA/Role/RoleBinding creation Signed-off-by: ghkdwlgns612 --- .../templates/deployment-lora-controller.yaml | 2 +- helm/templates/deployment-router.yaml | 2 +- helm/templates/role.yaml | 4 +- helm/templates/rolebinding.yaml | 10 +- helm/templates/serviceaccount.yaml | 4 +- .../deployment-lora-controller_test.yaml | 23 ++++ helm/tests/deployment-router_test.yaml | 23 ++++ helm/tests/serviceaccount_rbac_test.yaml | 76 +++++++++++ helm/tests/serviceaccount_test.yaml | 121 ++++++++++++++++++ helm/values.yaml | 8 ++ 10 files changed, 262 insertions(+), 11 deletions(-) create mode 100644 helm/tests/serviceaccount_rbac_test.yaml create mode 100644 helm/tests/serviceaccount_test.yaml diff --git a/helm/templates/deployment-lora-controller.yaml b/helm/templates/deployment-lora-controller.yaml index b1bfb4fae..2f0557568 100644 --- a/helm/templates/deployment-lora-controller.yaml +++ b/helm/templates/deployment-lora-controller.yaml @@ -38,7 +38,7 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ .Release.Name }}-lora-controller + serviceAccountName: {{ .Values.loraController.serviceAccountName | default (printf "%s-lora-controller" .Release.Name) }} securityContext: {{- toYaml .Values.loraController.podSecurityContext | nindent 8 }} {{- if $.Values.sharedPvcStorage.enabled }} diff --git a/helm/templates/deployment-router.yaml b/helm/templates/deployment-router.yaml index 47c065bc0..ab979dfbf 100644 --- a/helm/templates/deployment-router.yaml +++ b/helm/templates/deployment-router.yaml @@ -26,7 +26,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} spec: - serviceAccountName: {{ .Release.Name }}-router-service-account + serviceAccountName: {{ .Values.routerSpec.serviceAccountName | default (printf "%s-router-service-account" .Release.Name) }} {{- if .Values.routerSpec.priorityClassName }} priorityClassName: {{ .Values.routerSpec.priorityClassName | quote }} {{- end }} diff --git a/helm/templates/role.yaml b/helm/templates/role.yaml index 8f479cc19..1bd14b6a4 100644 --- a/helm/templates/role.yaml +++ b/helm/templates/role.yaml @@ -1,4 +1,4 @@ -{{- if .Values.routerSpec.enableRouter -}} +{{- if and .Values.routerSpec.enableRouter (not .Values.routerSpec.serviceAccountName) -}} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -14,7 +14,7 @@ rules: verbs: ["get", "watch", "list", "patch"] {{- end }} -{{- if .Values.loraController.enableLoraController }} +{{- if and .Values.loraController.enableLoraController (not .Values.loraController.serviceAccountName) }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/helm/templates/rolebinding.yaml b/helm/templates/rolebinding.yaml index 771ed51e2..89cf6a899 100644 --- a/helm/templates/rolebinding.yaml +++ b/helm/templates/rolebinding.yaml @@ -1,4 +1,4 @@ -{{- if .Values.routerSpec.enableRouter -}} +{{- if and .Values.routerSpec.enableRouter (not .Values.routerSpec.serviceAccountName) -}} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: @@ -6,7 +6,7 @@ metadata: namespace: {{ .Release.Namespace }} subjects: - kind: ServiceAccount - name: {{ .Release.Name }}-router-service-account + name: {{ printf "%s-router-service-account" .Release.Name }} namespace: {{ .Release.Namespace }} roleRef: kind: Role @@ -14,7 +14,7 @@ roleRef: apiGroup: rbac.authorization.k8s.io {{- end }} -{{- if .Values.loraController.enableLoraController }} +{{- if and .Values.loraController.enableLoraController (not .Values.loraController.serviceAccountName) }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -29,7 +29,7 @@ roleRef: name: {{ .Release.Name }}-lora-controller subjects: - kind: ServiceAccount - name: {{ .Release.Name }}-lora-controller + name: {{ printf "%s-lora-controller" .Release.Name }} namespace: {{ .Release.Namespace }} --- @@ -46,6 +46,6 @@ roleRef: name: {{ .Release.Name }}-leader-election-role subjects: - kind: ServiceAccount - name: {{ .Release.Name }}-lora-controller + name: {{ printf "%s-lora-controller" .Release.Name }} namespace: {{ .Release.Namespace }} {{- end }} diff --git a/helm/templates/serviceaccount.yaml b/helm/templates/serviceaccount.yaml index 5acd072f5..5ee0f4caa 100644 --- a/helm/templates/serviceaccount.yaml +++ b/helm/templates/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if .Values.routerSpec.enableRouter -}} +{{- if and .Values.routerSpec.enableRouter (not .Values.routerSpec.serviceAccountName) -}} apiVersion: v1 kind: ServiceAccount metadata: @@ -6,7 +6,7 @@ metadata: namespace: {{ .Release.Namespace }} {{- end }} -{{- if .Values.loraController.enableLoraController }} +{{- if and .Values.loraController.enableLoraController (not .Values.loraController.serviceAccountName) }} --- apiVersion: v1 kind: ServiceAccount diff --git a/helm/tests/deployment-lora-controller_test.yaml b/helm/tests/deployment-lora-controller_test.yaml index 1d6e98c58..eab4b5e40 100644 --- a/helm/tests/deployment-lora-controller_test.yaml +++ b/helm/tests/deployment-lora-controller_test.yaml @@ -217,3 +217,26 @@ tests: - name: vllm-shared-pvc-storage persistentVolumeClaim: claimName: "vllm-shared-pvc-storage-claim" + + - it: should use generated service account name by default + release: + name: vllm + set: + loraController: + enableLoraController: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: vllm-lora-controller + + - it: should use custom serviceAccountName when specified + release: + name: vllm + set: + loraController: + enableLoraController: true + serviceAccountName: my-existing-sa + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: my-existing-sa diff --git a/helm/tests/deployment-router_test.yaml b/helm/tests/deployment-router_test.yaml index 6a29df6b1..88dc57d6b 100644 --- a/helm/tests/deployment-router_test.yaml +++ b/helm/tests/deployment-router_test.yaml @@ -233,3 +233,26 @@ tests: secretKeyRef: name: custom-secret key: custom-apikey + + - it: should use generated service account name by default + release: + name: vllm + set: + routerSpec: + enableRouter: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: vllm-router-service-account + + - it: should use custom serviceAccountName when specified + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: my-existing-sa + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: my-existing-sa diff --git a/helm/tests/serviceaccount_rbac_test.yaml b/helm/tests/serviceaccount_rbac_test.yaml new file mode 100644 index 000000000..615a70fcc --- /dev/null +++ b/helm/tests/serviceaccount_rbac_test.yaml @@ -0,0 +1,76 @@ +suite: test Role and RoleBinding creation with serviceAccountName +templates: + - role.yaml + - rolebinding.yaml +tests: + - it: should create Role and RoleBinding when serviceAccountName is not set + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: "" + asserts: + - containsDocument: + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + name: vllm-reader + template: role.yaml + - containsDocument: + kind: RoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + name: vllm-deployment-access-binding + template: rolebinding.yaml + + - it: should NOT create Role and RoleBinding when custom serviceAccountName is set + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: my-existing-sa + asserts: + - hasDocuments: + count: 0 + + - it: should NOT create Role and RoleBinding when router is disabled + set: + routerSpec: + enableRouter: false + asserts: + - hasDocuments: + count: 0 + + - it: should create ClusterRole and ClusterRoleBinding when lora serviceAccountName is not set + release: + name: vllm + set: + routerSpec: + enableRouter: false + loraController: + enableLoraController: true + serviceAccountName: "" + asserts: + - equal: + path: metadata.name + value: vllm-lora-controller + documentIndex: 0 + template: role.yaml + - equal: + path: metadata.name + value: vllm-lora-controller + documentIndex: 0 + template: rolebinding.yaml + + - it: should NOT create ClusterRole and ClusterRoleBinding when lora serviceAccountName is set + release: + name: vllm + set: + routerSpec: + enableRouter: false + loraController: + enableLoraController: true + serviceAccountName: my-existing-lora-sa + asserts: + - hasDocuments: + count: 0 diff --git a/helm/tests/serviceaccount_test.yaml b/helm/tests/serviceaccount_test.yaml new file mode 100644 index 000000000..43aa99f0b --- /dev/null +++ b/helm/tests/serviceaccount_test.yaml @@ -0,0 +1,121 @@ +suite: test ServiceAccount creation +templates: + - serviceaccount.yaml +tests: + # Router ServiceAccount tests + - it: should create router ServiceAccount when serviceAccountName is not set + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: "" + loraController: + enableLoraController: false + asserts: + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: vllm-router-service-account + + - it: should NOT create router ServiceAccount when serviceAccountName is specified + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: my-existing-sa + loraController: + enableLoraController: false + asserts: + - hasDocuments: + count: 0 + + - it: should NOT create router ServiceAccount when router is disabled + set: + routerSpec: + enableRouter: false + loraController: + enableLoraController: false + asserts: + - hasDocuments: + count: 0 + + # Lora Controller ServiceAccount tests + - it: should create lora-controller ServiceAccount when serviceAccountName is not set + release: + name: vllm + set: + routerSpec: + enableRouter: false + loraController: + enableLoraController: true + serviceAccountName: "" + asserts: + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: vllm-lora-controller + + - it: should NOT create lora-controller ServiceAccount when serviceAccountName is specified + release: + name: vllm + set: + routerSpec: + enableRouter: false + loraController: + enableLoraController: true + serviceAccountName: my-existing-lora-sa + asserts: + - hasDocuments: + count: 0 + + - it: should create both ServiceAccounts when both are enabled and no custom names set + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: "" + loraController: + enableLoraController: true + serviceAccountName: "" + asserts: + - hasDocuments: + count: 2 + + - it: should create only lora-controller ServiceAccount when router uses custom name + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: my-existing-router-sa + loraController: + enableLoraController: true + serviceAccountName: "" + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: vllm-lora-controller + + - it: should create only router ServiceAccount when lora-controller uses custom name + release: + name: vllm + set: + routerSpec: + enableRouter: true + serviceAccountName: "" + loraController: + enableLoraController: true + serviceAccountName: my-existing-lora-sa + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: vllm-router-service-account diff --git a/helm/values.yaml b/helm/values.yaml index 3cc8a3125..8e2475065 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -434,6 +434,10 @@ routerSpec: # -- image pull policy for the router pod imagePullPolicy: "Always" # @schema enum:[Always,IfNotPresent,Never] + # -- The name of an existing service account to use for the router deployment. + # -- If set, no ServiceAccount will be created and this name will be used directly. + serviceAccountName: "" + # -- Hugging Face token configuration hf_token: "" @@ -874,6 +878,10 @@ loraController: # -- kubernetes cluster domain kubernetesClusterDomain: "cluster.local" + # -- The name of an existing service account to use for the lora controller deployment. + # -- If set, no ServiceAccount will be created and this name will be used directly. + serviceAccountName: "" + # -- Number of lora controller replicas replicaCount: 1 From 2a9b320f8c3d47fabd9464966b8ed87b2c1da486 Mon Sep 17 00:00:00 2001 From: ghkdwlgns612 Date: Thu, 23 Jul 2026 09:42:43 +0900 Subject: [PATCH 2/2] fix(helm): values.schema.json Signed-off-by: ghkdwlgns612 --- helm/values.schema.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/helm/values.schema.json b/helm/values.schema.json index 432b72019..15b0dbb33 100644 --- a/helm/values.schema.json +++ b/helm/values.schema.json @@ -427,6 +427,10 @@ "description": "lora controller resources", "type": "object" }, + "serviceAccountName": { + "description": "The name of an existing service account to use for the lora controller deployment.", + "type": "string" + }, "tolerations": { "description": "Tolerations", "type": "array" @@ -884,6 +888,10 @@ "description": "Pod-level security context configuration. https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#podsecuritycontext-v1-core", "type": "object" }, + "serviceAccountName": { + "description": "The name of an existing service account to use for the router deployment.", + "type": "string" + }, "serviceAnnotations": { "description": "Service annotations if you use a LoadBalancer or NodePort service type", "type": "object"