This is an automated email from the ASF dual-hosted git repository.

jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 59ddf5698ab Add workers.celery.serviceAccount & 
workers.kubernetes.serviceAccount (#64730)
59ddf5698ab is described below

commit 59ddf5698ab7ada2edce24f284c827db5242b170
Author: Przemysław Mirowski <[email protected]>
AuthorDate: Tue Apr 7 22:06:05 2026 +0200

    Add workers.celery.serviceAccount & workers.kubernetes.serviceAccount 
(#64730)
    
    * Refactor Service Account workers tests
    
    * Add workers.celery.serviceAccount & workers.kubernetes.serviceAccount
    
    * Fix spellcheck
    
    * Separate ServiceAccount names
    
    * Add newsfragment
    
    * Misc
---
 chart/files/pod-template-file.kubernetes-helm-yaml |   4 +
 chart/newsfragments/64730.significant.rst          |   1 +
 chart/templates/NOTES.txt                          |  32 +++
 chart/templates/_helpers.yaml                      |  25 +-
 .../workers/worker-kubernetes-serviceaccount.yaml  |  41 +++
 chart/values.schema.json                           |  86 +++++-
 chart/values.yaml                                  | 137 +++++++---
 .../helm_tests/airflow_aux/test_annotations.py     |  99 +++++++
 .../airflow_aux/test_pod_template_file.py          |  19 ++
 .../tests/helm_tests/airflow_core/test_worker.py   | 297 ++++++++++++++++++---
 .../helm_tests/airflow_core/test_worker_sets.py    | 113 ++++++--
 11 files changed, 742 insertions(+), 112 deletions(-)

diff --git a/chart/files/pod-template-file.kubernetes-helm-yaml 
b/chart/files/pod-template-file.kubernetes-helm-yaml
index 902391cd1a9..5f067c68077 100644
--- a/chart/files/pod-template-file.kubernetes-helm-yaml
+++ b/chart/files/pod-template-file.kubernetes-helm-yaml
@@ -236,7 +236,11 @@ spec:
   terminationGracePeriodSeconds: {{ 
.Values.workers.kubernetes.terminationGracePeriodSeconds | default 
.Values.workers.terminationGracePeriodSeconds }}
   tolerations: {{- toYaml $tolerations | nindent 4 }}
   topologySpreadConstraints: {{- toYaml $topologySpreadConstraints | nindent 4 
}}
+  {{- if .Values.workers.kubernetes.serviceAccount.create }}
+  serviceAccountName: {{ include "worker.kubernetes.serviceAccountName" . }}
+  {{- else }}
   serviceAccountName: {{ include "worker.serviceAccountName" . }}
+  {{- end }}
   volumes:
   {{- if .Values.dags.persistence.enabled }}
   - name: dags
diff --git a/chart/newsfragments/64730.significant.rst 
b/chart/newsfragments/64730.significant.rst
new file mode 100644
index 00000000000..6213c4e8f92
--- /dev/null
+++ b/chart/newsfragments/64730.significant.rst
@@ -0,0 +1 @@
+``workers.serviceAccount`` section is now deprecated in favor of 
``workers.celery.serviceAccount`` and ``workers.kubernetes.serviceAccount``. 
Please update your configuration accordingly.
diff --git a/chart/templates/NOTES.txt b/chart/templates/NOTES.txt
index 104832aef2c..e8236398227 100644
--- a/chart/templates/NOTES.txt
+++ b/chart/templates/NOTES.txt
@@ -413,6 +413,38 @@ DEPRECATION WARNING:
 
 {{- end }}
 
+{{- if not .Values.workers.serviceAccount.automountServiceAccountToken }}
+
+ DEPRECATION WARNING:
+    `workers.serviceAccount.automountServiceAccountToken` has been renamed to 
`workers.celery.serviceAccount.automountServiceAccountToken`/`workers.kubernetes.serviceAccount.automountServiceAccountToken`.
+    Please change your values as support for the old name will be dropped in a 
future release.
+
+{{- end }}
+
+{{- if not .Values.workers.serviceAccount.create }}
+
+ DEPRECATION WARNING:
+    `workers.serviceAccount.create` has been renamed to 
`workers.celery.serviceAccount.create`/`workers.kubernetes.serviceAccount.create`.
+    Please change your values as support for the old name will be dropped in a 
future release.
+
+{{- end }}
+
+{{- if not (empty .Values.workers.serviceAccount.name) }}
+
+ DEPRECATION WARNING:
+    `workers.serviceAccount.name` has been renamed to 
`workers.celery.serviceAccount.name`/`workers.kubernetes.serviceAccount.name`.
+    Please change your values as support for the old name will be dropped in a 
future release.
+
+{{- end }}
+
+{{- if not (empty .Values.workers.serviceAccount.annotations) }}
+
+ DEPRECATION WARNING:
+    `workers.serviceAccount.annotations` has been renamed to 
`workers.celery.serviceAccount.annotations`/`workers.kubernetes.serviceAccount.annotations`.
+    Please change your values as support for the old name will be dropped in a 
future release.
+
+{{- end }}
+
 {{- if .Values.workers.keda.enabled }}
 
  DEPRECATION WARNING:
diff --git a/chart/templates/_helpers.yaml b/chart/templates/_helpers.yaml
index 5ef1759f604..a435fe6fe65 100644
--- a/chart/templates/_helpers.yaml
+++ b/chart/templates/_helpers.yaml
@@ -641,13 +641,23 @@ server_tls_key_file = /etc/pgbouncer/server.key
   {{- end }}
 {{- end }}
 
-{{/* Helper to generate service account name respecting 
.Values.$section.serviceAccount flags */}}
+{{/* Helper for service account name generation */}}
+{{- define "_serviceAccountNameGen" -}}
+  {{- if .sa.create }}
+    {{- default (printf "%s-%s" (include "airflow.serviceAccountName" .) 
(default .key .nameSuffix)) .sa.name | quote }}
+  {{- else }}
+    {{- default "default" .sa.name | quote }}
+  {{- end }}
+{{- end }}
+
+{{/* Helper to generate service account name respecting 
.Values.$section.serviceAccount or .Values.$section.$subSection.serviceAccount 
flags */}}
 {{- define "_serviceAccountName" -}}
-  {{- $sa := get (get .Values .key) "serviceAccount" }}
-  {{- if $sa.create }}
-    {{- default (printf "%s-%s" (include "airflow.serviceAccountName" .) 
(default .key .nameSuffix )) $sa.name | quote }}
+  {{- if .subKey }}
+    {{- $sa := get (get (get .Values .key) .subKey) "serviceAccount" -}}
+    {{- include "_serviceAccountNameGen" (merge (dict "sa" $sa "key" .key 
"nameSuffix" .nameSuffix) .) }}
   {{- else }}
-    {{- default "default" $sa.name | quote }}
+    {{- $sa := get (get .Values .key) "serviceAccount" }}
+    {{- include "_serviceAccountNameGen" (merge (dict "sa" $sa "key" .key 
"nameSuffix" .nameSuffix) .) }}
   {{- end }}
 {{- end }}
 
@@ -700,6 +710,11 @@ server_tls_key_file = /etc/pgbouncer/server.key
   {{- end }}
 {{- end }}
 
+{{/* Create the name of the worker kubernetes service account to use */}}
+{{- define "worker.kubernetes.serviceAccountName" -}}
+  {{- include "_serviceAccountName" (merge (dict "key" "workers" "subKey" 
"kubernetes" "nameSuffix" "worker-kubernetes") .) -}}
+{{- end }}
+
 {{/* Create the name of the triggerer service account to use */}}
 {{- define "triggerer.serviceAccountName" -}}
   {{- include "_serviceAccountName" (merge (dict "key" "triggerer") .) -}}
diff --git a/chart/templates/workers/worker-kubernetes-serviceaccount.yaml 
b/chart/templates/workers/worker-kubernetes-serviceaccount.yaml
new file mode 100644
index 00000000000..7530f0732d3
--- /dev/null
+++ b/chart/templates/workers/worker-kubernetes-serviceaccount.yaml
@@ -0,0 +1,41 @@
+{{/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+*/}}
+
+###########################################
+## Airflow Worker Kubernetes ServiceAccount
+###########################################
+{{- if and .Values.workers.kubernetes.serviceAccount.create (contains 
"KubernetesExecutor" .Values.executor) }}
+apiVersion: v1
+kind: ServiceAccount
+automountServiceAccountToken: {{ or 
.Values.workers.kubernetes.serviceAccount.automountServiceAccountToken (and 
(not (has 
.Values.workers.kubernetes.serviceAccount.automountServiceAccountToken (list 
true false))) .Values.workers.serviceAccount.automountServiceAccountToken) }}
+metadata:
+  name: {{ include "worker.kubernetes.serviceAccountName" . }}
+  labels:
+    tier: airflow
+    component: worker
+    release: {{ .Release.Name }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+    heritage: {{ .Release.Service }}
+    {{- if or .Values.labels .Values.workers.labels }}
+      {{- mustMerge .Values.workers.labels .Values.labels | toYaml | nindent 4 
}}
+    {{- end }}
+  {{- with (.Values.workers.kubernetes.serviceAccount.annotations | default 
.Values.workers.serviceAccount.annotations) }}
+  annotations: {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
diff --git a/chart/values.schema.json b/chart/values.schema.json
index df088e1bb93..05c3d6de376 100644
--- a/chart/values.schema.json
+++ b/chart/values.schema.json
@@ -1848,21 +1848,21 @@
                     }
                 },
                 "serviceAccount": {
-                    "description": "Create ServiceAccount for Airflow Celery 
workers and pods created with pod-template-file.",
+                    "description": "Create ServiceAccount for Airflow Celery 
workers and pods created with pod-template-file (deprecated, use 
``workers.celery.serviceAccount`` and/or ``workers.kubernetes.serviceAccount`` 
instead).",
                     "type": "object",
                     "properties": {
                         "automountServiceAccountToken": {
-                            "description": "Specifies if ServiceAccount's API 
credentials should be mounted onto Pods",
+                            "description": "Specifies if ServiceAccount's API 
credentials should be mounted onto Pods (deprecated, use 
``workers.celery.serviceAccount.automountServiceAccountToken`` and/or 
``workers.kubernetes.serviceAccount.automountServiceAccountToken`` instead)",
                             "type": "boolean",
                             "default": true
                         },
                         "create": {
-                            "description": "Specifies whether a ServiceAccount 
should be created.",
+                            "description": "Specifies whether a ServiceAccount 
should be created (deprecated, use ``workers.celery.serviceAccount.create`` 
and/or ``workers.kubernetes.serviceAccount.create`` instead).",
                             "type": "boolean",
                             "default": true
                         },
                         "name": {
-                            "description": "The name of the ServiceAccount to 
use. If not set and create is true, a name is generated using the release 
name.",
+                            "description": "The name of the ServiceAccount to 
use (deprecated, use ``workers.celery.serviceAccount.name`` and/or 
``workers.kubernetes.serviceAccount.name`` instead). If not set and create is 
true, a name is generated using the release name.",
                             "type": [
                                 "string",
                                 "null"
@@ -1870,7 +1870,7 @@
                             "default": null
                         },
                         "annotations": {
-                            "description": "Annotations to add to the worker 
Kubernetes ServiceAccount.",
+                            "description": "Annotations to add to the worker 
Kubernetes ServiceAccount (deprecated, use 
``workers.celery.serviceAccount.annotations`` and/or 
``workers.kubernetes.serviceAccount.annotations`` instead).",
                             "type": "object",
                             "default": {},
                             "additionalProperties": {
@@ -2921,6 +2921,44 @@
                                 }
                             }
                         },
+                        "serviceAccount": {
+                            "description": "Create ServiceAccount for Airflow 
Celery workers.",
+                            "type": "object",
+                            "properties": {
+                                "automountServiceAccountToken": {
+                                    "description": "Specifies if 
ServiceAccount's API credentials should be mounted onto Pods.",
+                                    "type": [
+                                        "boolean",
+                                        "null"
+                                    ],
+                                    "default": null
+                                },
+                                "create": {
+                                    "description": "Specifies whether a 
ServiceAccount should be created.",
+                                    "type": [
+                                        "boolean",
+                                        "null"
+                                    ],
+                                    "default": null
+                                },
+                                "name": {
+                                    "description": "The name of the 
ServiceAccount to use. If not set and create is true, a name is generated using 
the release name.",
+                                    "type": [
+                                        "string",
+                                        "null"
+                                    ],
+                                    "default": null
+                                },
+                                "annotations": {
+                                    "description": "Annotations to add to the 
worker Kubernetes ServiceAccount.",
+                                    "type": "object",
+                                    "default": {},
+                                    "additionalProperties": {
+                                        "type": "string"
+                                    }
+                                }
+                            }
+                        },
                         "keda": {
                             "description": "KEDA configuration of Airflow 
Celery workers.",
                             "type": "object",
@@ -3534,6 +3572,44 @@
                                 }
                             ]
                         },
+                        "serviceAccount": {
+                            "description": "Create ServiceAccount for pods 
created with pod-template-file. When this section is specified, the Service 
Account is created from 
``templates/workers/worker-kubernetes-serviceaccount.yaml`` file.",
+                            "type": "object",
+                            "properties": {
+                                "automountServiceAccountToken": {
+                                    "description": "Specifies if 
ServiceAccount's API credentials should be mounted onto Pods. If not specified, 
the ``workers.serviceAccount.automountServiceAccountToken`` value will be 
taken.",
+                                    "type": [
+                                        "boolean",
+                                        "null"
+                                    ],
+                                    "default": null
+                                },
+                                "create": {
+                                    "description": "Specifies whether a 
ServiceAccount should be created. If not specified, the ServiceAccount will be 
generated and used from ``templates/workers/worker-serviceaccount.yaml`` file 
if ``workers.serviceAccount.create`` will be 'true'.",
+                                    "type": [
+                                        "boolean",
+                                        "null"
+                                    ],
+                                    "default": null
+                                },
+                                "name": {
+                                    "description": "The name of the 
ServiceAccount to use. If not set and ``create`` is 'true', a name is generated 
using the release name with kubernetes dedicated name.",
+                                    "type": [
+                                        "string",
+                                        "null"
+                                    ],
+                                    "default": null
+                                },
+                                "annotations": {
+                                    "description": "Annotations to add to the 
worker Kubernetes ServiceAccount. If not specified, the 
``workers.serviceAccount.annotations`` value will be taken.",
+                                    "type": "object",
+                                    "default": {},
+                                    "additionalProperties": {
+                                        "type": "string"
+                                    }
+                                }
+                            }
+                        },
                         "kerberosSidecar": {
                             "description": "Kerberos sidecar for pods created 
with pod-template-file.",
                             "type": "object",
diff --git a/chart/values.yaml b/chart/values.yaml
index e88893aaea0..67dcf229054 100644
--- a/chart/values.yaml
+++ b/chart/values.yaml
@@ -770,19 +770,36 @@ workers:
       # (deprecated, use 
`workers.celery.podDisruptionBudget.config.minAvailable` instead)
       # minAvailable: 1
 
-  # Create ServiceAccount for Airflow Celery workers and pods created with 
pod-template-file
+  # Create Service Account for Airflow Celery workers and pods created with 
pod-template-file
+  # (deprecated, use `workers.celery.serviceAccount` and/or 
`workers.kubernetes.serviceAccount` instead)
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+    # (deprecated, use
+    #   `workers.celery.serviceAccount.automountServiceAccountToken` and/or
+    #   `workers.kubernetes.serviceAccount.automountServiceAccountToken`
+    # instead)
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
+    # (deprecated, use
+    #   `workers.celery.serviceAccount.create` and/or
+    #   `workers.kubernetes.serviceAccount.create`
+    # instead)
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
+    # (deprecated, use
+    #   `workers.celery.serviceAccount.name` and/or
+    #   `workers.kubernetes.serviceAccount.name`
+    # instead)
     name: ~
 
     # Annotations to add to worker Kubernetes Service Account.
+    # (deprecated, use
+    #   `workers.celery.serviceAccount.annotations` and/or
+    #   `workers.kubernetes.serviceAccount.annotations`
+    # instead)
     annotations: {}
 
   # Allow KEDA autoscaling for Airflow Celery workers
@@ -1265,6 +1282,21 @@ workers:
         maxUnavailable: ~
         # minAvailable: ~
 
+    # Create Service Account for Airflow Celery workers
+    serviceAccount:
+      # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+      automountServiceAccountToken: ~
+
+      # Specifies whether a Service Account should be created
+      create: ~
+
+      # The name of the Service Account to use.
+      # If not set and `create` is 'true', a name is generated using the 
release name
+      name: ~
+
+      # Annotations to add to worker Kubernetes Service Account.
+      annotations: {}
+
     # Allow KEDA autoscaling for Airflow Celery workers
     keda:
       enabled: ~
@@ -1459,6 +1491,29 @@ workers:
     # Container level Lifecycle Hooks definition for pods created with 
pod-template-file
     containerLifecycleHooks: {}
 
+    # Create Service Account for pods created with pod-template-file
+    # When this section is specified, the Service Account is created from
+    # 'templates/workers/worker-kubernetes-serviceaccount.yaml' file
+    serviceAccount:
+      # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+      # If not specified, the 
`workers.serviceAccount.automountServiceAccountToken` value will be taken
+      automountServiceAccountToken: ~
+
+      # Specifies whether a Service Account should be created.
+      # If not specified, the Service Account will be generated and used from
+      # 'templates/workers/worker-serviceaccount.yaml' file if 
`workers.serviceAccount.create`
+      # will be 'true'
+      create: ~
+
+      # The name of the Service Account to use.
+      # If not set and `create` is 'true', a name is generated using the 
release name
+      # with Kubernetes dedicated name
+      name: ~
+
+      # Annotations to add to worker Kubernetes Service Account.
+      # If not specified, the `workers.serviceAccount.annotations` value will 
be taken
+      annotations: {}
+
     # Kerberos sidecar configuration for pods created with pod-template-file
     kerberosSidecar:
       # Enable kerberos sidecar
@@ -1601,16 +1656,16 @@ scheduler:
   # Grace period for tasks to finish after SIGTERM is sent from Kubernetes
   terminationGracePeriodSeconds: 10
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # Affects all executors that launch pods
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -1830,15 +1885,15 @@ createUserJob:
   # Container level lifecycle hooks
   containerLifecycleHooks: {}
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -1934,15 +1989,15 @@ migrateDatabaseJob:
   # Container level lifecycle hooks
   containerLifecycleHooks: {}
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -2050,10 +2105,10 @@ apiServer:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -2280,15 +2335,15 @@ webserver:
     # Scaling behavior of the target in both Up and Down directions
     behavior: {}
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -2494,15 +2549,15 @@ triggerer:
     periodSeconds: 60
     command: ~
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -2780,15 +2835,15 @@ dagProcessor:
     periodSeconds: 60
     command: ~
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -3012,15 +3067,15 @@ flower:
   # Container level lifecycle hooks
   containerLifecycleHooks: {}
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -3152,15 +3207,15 @@ statsd:
   # Grace period for StatsD to finish after SIGTERM is sent from Kubernetes
   terminationGracePeriodSeconds: 30
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -3257,15 +3312,15 @@ pgbouncer:
   # Add custom annotations to the PgBouncer certificates secret
   certificatesSecretAnnotations: {}
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -3451,15 +3506,15 @@ redis:
   # Annotations for Redis Statefulset
   annotations: {}
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -3671,15 +3726,15 @@ cleanup:
   #   cpu: 100m
   #   memory: 128Mi
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
@@ -3771,15 +3826,15 @@ databaseCleanup:
   #  cpu: 100m
   #  memory: 128Mi
 
-  # Create ServiceAccount
+  # Create Service Account
   serviceAccount:
     # ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
     automountServiceAccountToken: true
 
-    # Specifies whether a ServiceAccount should be created
+    # Specifies whether a Service Account should be created
     create: true
 
-    # The name of the ServiceAccount to use.
+    # The name of the Service Account to use.
     # If not set and `create` is 'true', a name is generated using the release 
name
     name: ~
 
diff --git a/helm-tests/tests/helm_tests/airflow_aux/test_annotations.py 
b/helm-tests/tests/helm_tests/airflow_aux/test_annotations.py
index 3df818effa7..2641f922fb1 100644
--- a/helm-tests/tests/helm_tests/airflow_aux/test_annotations.py
+++ b/helm-tests/tests/helm_tests/airflow_aux/test_annotations.py
@@ -122,6 +122,105 @@ class TestServiceAccountAnnotations:
                     "example": "worker",
                 },
             ),
+            (
+                {
+                    "workers": {
+                        "celery": {
+                            "serviceAccount": {
+                                "annotations": {
+                                    "example": "worker",
+                                },
+                            }
+                        },
+                    },
+                },
+                "templates/workers/worker-serviceaccount.yaml",
+                {
+                    "example": "worker",
+                },
+            ),
+            (
+                {
+                    "workers": {
+                        "serviceAccount": {
+                            "annotations": {
+                                "worker": "example",
+                            },
+                        },
+                        "celery": {
+                            "serviceAccount": {
+                                "annotations": {
+                                    "example": "worker",
+                                },
+                            }
+                        },
+                    },
+                },
+                "templates/workers/worker-serviceaccount.yaml",
+                {
+                    "example": "worker",
+                },
+            ),
+            (
+                {
+                    "executor": "KubernetesExecutor",
+                    "workers": {
+                        "serviceAccount": {
+                            "annotations": {
+                                "example": "worker",
+                            },
+                        },
+                        "kubernetes": {"serviceAccount": {"create": True}},
+                    },
+                },
+                "templates/workers/worker-kubernetes-serviceaccount.yaml",
+                {
+                    "example": "worker",
+                },
+            ),
+            (
+                {
+                    "executor": "KubernetesExecutor",
+                    "workers": {
+                        "kubernetes": {
+                            "serviceAccount": {
+                                "create": True,
+                                "annotations": {
+                                    "example": "worker",
+                                },
+                            }
+                        },
+                    },
+                },
+                "templates/workers/worker-kubernetes-serviceaccount.yaml",
+                {
+                    "example": "worker",
+                },
+            ),
+            (
+                {
+                    "executor": "KubernetesExecutor",
+                    "workers": {
+                        "serviceAccount": {
+                            "annotations": {
+                                "worker": "example",
+                            },
+                        },
+                        "kubernetes": {
+                            "serviceAccount": {
+                                "create": True,
+                                "annotations": {
+                                    "example": "worker",
+                                },
+                            }
+                        },
+                    },
+                },
+                "templates/workers/worker-kubernetes-serviceaccount.yaml",
+                {
+                    "example": "worker",
+                },
+            ),
             (
                 {
                     "flower": {
diff --git a/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py 
b/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py
index a963638459c..d206f61c085 100644
--- a/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py
+++ b/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py
@@ -1810,3 +1810,22 @@ class TestPodTemplateFile:
         assert jmespath.search("spec.initContainers[?name=='kerberos-init'] | 
[0].lifecycle", docs[0]) == {
             "postStart": {"exec": {"command": ["echo", "test-release"]}}
         }
+
+    def test_service_account_name_default(self):
+        docs = render_chart(
+            name="test-release",
+            show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
+        )
+
+        assert jmespath.search("spec.serviceAccountName", docs[0]) == 
"test-release-airflow-worker"
+
+    def test_dedicated_service_account_name_default(self):
+        docs = render_chart(
+            name="test-release",
+            values={"workers": {"kubernetes": {"serviceAccount": {"create": 
True}}}},
+            show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
+        )
+
+        assert jmespath.search("spec.serviceAccountName", docs[0]) == 
"test-release-airflow-worker-kubernetes"
diff --git a/helm-tests/tests/helm_tests/airflow_core/test_worker.py 
b/helm-tests/tests/helm_tests/airflow_core/test_worker.py
index 0032e50e06c..a247f15ca47 100644
--- a/helm-tests/tests/helm_tests/airflow_core/test_worker.py
+++ b/helm-tests/tests/helm_tests/airflow_core/test_worker.py
@@ -2327,15 +2327,141 @@ class TestWorkerService:
         assert jmespath.search("metadata.labels", docs[0])["test_label"] == 
"test_label_value"
 
 
-class TestWorkerServiceAccount:
-    """Tests worker service account."""
+class TestWorkerCeleryServiceAccount:
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"serviceAccount": {"create": False}},
+            {"celery": {"serviceAccount": {"create": False}}},
+            {"serviceAccount": {"create": True}, "celery": {"serviceAccount": 
{"create": False}}},
+        ],
+    )
+    def test_should_not_create_service_account_when_disabled(self, 
workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 0
+
+    def test_should_create_service_account_by_default(self):
+        docs = render_chart(
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 1
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"serviceAccount": {"create": True}},
+            {"celery": {"serviceAccount": {"create": True}}},
+            {"serviceAccount": {"create": False}, "celery": {"serviceAccount": 
{"create": True}}},
+        ],
+    )
+    def test_should_not_create_service_account_for_local_executor(self, 
workers_values):
+        docs = render_chart(
+            values={
+                "executor": "LocalExecutor",
+                "workers": workers_values,
+            },
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 0
+
+    @pytest.mark.parametrize(
+        "executor",
+        [
+            "CeleryExecutor",
+            "CeleryKubernetesExecutor",
+            "CeleryExecutor,KubernetesExecutor",
+            "KubernetesExecutor",
+            "LocalKubernetesExecutor",
+        ],
+    )
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"serviceAccount": {"create": True}},
+            {"celery": {"serviceAccount": {"create": True}}},
+            {"serviceAccount": {"create": False}, "celery": {"serviceAccount": 
{"create": True}}},
+        ],
+    )
+    def test_should_create_service_account_for_specific_executors(self, 
executor, workers_values):
+        docs = render_chart(
+            values={
+                "executor": executor,
+                "workers": workers_values,
+            },
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 1
+        assert jmespath.search("kind", docs[0]) == "ServiceAccount"
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"serviceAccount": {"create": True}},
+            {"celery": {"serviceAccount": {"create": True}}},
+            {
+                "serviceAccount": {"automountServiceAccountToken": False},
+                "celery": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": True}},
+            },
+        ],
+    )
+    def test_automount_service_account_token_true(self, workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+        assert jmespath.search("automountServiceAccountToken", docs[0]) is True
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"serviceAccount": {"create": True, 
"automountServiceAccountToken": False}},
+            {"celery": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": False}}},
+            {
+                "serviceAccount": {"automountServiceAccountToken": True},
+                "celery": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": False}},
+            },
+        ],
+    )
+    def test_automount_service_account_token_false(self, workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+
+        assert jmespath.search("automountServiceAccountToken", docs[0]) is 
False
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"serviceAccount": {"create": True, "name": "test"}},
+            {"celery": {"serviceAccount": {"create": True, "name": "test"}}},
+            {
+                "serviceAccount": {"name": "none"},
+                "celery": {"serviceAccount": {"create": True, "name": "test"}},
+            },
+        ],
+    )
+    def test_overwrite_name(self, workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
+            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        )
+
+        assert jmespath.search("metadata.name", docs[0]) == "test"
 
     def test_should_add_component_specific_labels(self):
         docs = render_chart(
             values={
                 "executor": "CeleryExecutor",
                 "workers": {
-                    "serviceAccount": {"create": True},
+                    "celery": {"serviceAccount": {"create": True}},
                     "labels": {"test_label": "test_label_value"},
                 },
             },
@@ -2345,55 +2471,156 @@ class TestWorkerServiceAccount:
         assert "test_label" in jmespath.search("metadata.labels", docs[0])
         assert jmespath.search("metadata.labels", docs[0])["test_label"] == 
"test_label_value"
 
+
+class TestWorkerKubernetesServiceAccount:
+    def test_should_not_create_service_account_by_default(self):
+        docs = render_chart(
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 0
+
     @pytest.mark.parametrize(
-        ("executor", "creates_service_account"),
+        "workers_values",
         [
-            ("LocalExecutor", False),
-            ("CeleryExecutor", True),
-            ("CeleryKubernetesExecutor", True),
-            ("CeleryExecutor,KubernetesExecutor", True),
-            ("KubernetesExecutor", True),
-            ("LocalKubernetesExecutor", True),
+            {"serviceAccount": {"create": True}},  # Should not have effect
+            {"kubernetes": {"serviceAccount": {"create": False}}},
+            {"serviceAccount": {"create": True}, "kubernetes": 
{"serviceAccount": {"create": False}}},
         ],
     )
-    def test_should_create_worker_service_account_for_specific_executors(
-        self, executor, creates_service_account
-    ):
+    def test_should_not_create_service_account_when_disabled(self, 
workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 0
+
+    def test_should_create_service_account_when_enabled(self):
         docs = render_chart(
             values={
-                "executor": executor,
-                "workers": {
-                    "serviceAccount": {"create": True},
-                    "labels": {"test_label": "test_label_value"},
-                },
+                "executor": "KubernetesExecutor",
+                "workers": {"kubernetes": {"serviceAccount": {"create": 
True}}},
             },
-            show_only=["templates/workers/worker-serviceaccount.yaml"],
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 1
+
+    @pytest.mark.parametrize(
+        "executor",
+        [
+            "CeleryExecutor",
+            "LocalExecutor",
+            "LocalExecutor,CeleryExecutor",
+        ],
+    )
+    def test_should_not_create_service_account_non_k8s_executors(self, 
executor):
+        docs = render_chart(
+            values={"executor": executor, "workers": {"kubernetes": 
{"serviceAccount": {"create": True}}}},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
         )
-        if creates_service_account:
-            assert jmespath.search("kind", docs[0]) == "ServiceAccount"
-            assert "test_label" in jmespath.search("metadata.labels", docs[0])
-            assert jmespath.search("metadata.labels", docs[0])["test_label"] 
== "test_label_value"
-        else:
-            assert docs == []
 
-    def test_default_automount_service_account_token(self):
+        assert len(docs) == 0
+
+    @pytest.mark.parametrize(
+        "executor",
+        [
+            "CeleryKubernetesExecutor",
+            "CeleryExecutor,KubernetesExecutor",
+            "KubernetesExecutor",
+            "LocalKubernetesExecutor",
+        ],
+    )
+    def test_should_create_service_account_when_k8s_executors(self, executor):
         docs = render_chart(
-            values={
-                "workers": {
-                    "serviceAccount": {"create": True},
-                },
+            values={"executor": executor, "workers": {"kubernetes": 
{"serviceAccount": {"create": True}}}},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert len(docs) == 1
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"kubernetes": {"serviceAccount": {"create": True}}},
+            {"kubernetes": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": True}}},
+            {
+                "serviceAccount": {"automountServiceAccountToken": False},
+                "kubernetes": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": True}},
             },
-            show_only=["templates/workers/worker-serviceaccount.yaml"],
+        ],
+    )
+    def test_automount_service_account_token_true(self, workers_values):
+        docs = render_chart(
+            values={"executor": "KubernetesExecutor", "workers": 
workers_values},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
         )
         assert jmespath.search("automountServiceAccountToken", docs[0]) is True
 
-    def test_overridden_automount_service_account_token(self):
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"kubernetes": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": False}}},
+            {
+                "serviceAccount": {"automountServiceAccountToken": True},
+                "kubernetes": {"serviceAccount": {"create": True, 
"automountServiceAccountToken": False}},
+            },
+        ],
+    )
+    def test_automount_service_account_token_false(self, workers_values):
+        docs = render_chart(
+            values={"executor": "KubernetesExecutor", "workers": 
workers_values},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert jmespath.search("automountServiceAccountToken", docs[0]) is 
False
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"kubernetes": {"serviceAccount": {"create": True}}},
+            {"serviceAccount": {"name": "test"}, "kubernetes": 
{"serviceAccount": {"create": True}}},
+        ],
+    )
+    def test_default_name(self, workers_values):
+        docs = render_chart(
+            name="test",
+            values={"executor": "KubernetesExecutor", "workers": 
workers_values},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert jmespath.search("metadata.name", docs[0]) == 
"test-airflow-worker-kubernetes"
+
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {"kubernetes": {"serviceAccount": {"create": True, "name": 
"test"}}},
+            {
+                "serviceAccount": {"name": "none"},
+                "kubernetes": {"serviceAccount": {"create": True, "name": 
"test"}},
+            },
+        ],
+    )
+    def test_overwrite_name(self, workers_values):
+        docs = render_chart(
+            values={"executor": "KubernetesExecutor", "workers": 
workers_values},
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
+        )
+
+        assert jmespath.search("metadata.name", docs[0]) == "test"
+
+    def test_should_add_component_specific_labels(self):
         docs = render_chart(
             values={
+                "executor": "KubernetesExecutor",
                 "workers": {
-                    "serviceAccount": {"create": True, 
"automountServiceAccountToken": False},
+                    "kubernetes": {"serviceAccount": {"create": True}},
+                    "labels": {"test_label": "test_label_value"},
                 },
             },
-            show_only=["templates/workers/worker-serviceaccount.yaml"],
+            
show_only=["templates/workers/worker-kubernetes-serviceaccount.yaml"],
         )
-        assert jmespath.search("automountServiceAccountToken", docs[0]) is 
False
+
+        assert "test_label" in jmespath.search("metadata.labels", docs[0])
+        assert jmespath.search("metadata.labels", docs[0])["test_label"] == 
"test_label_value"
diff --git a/helm-tests/tests/helm_tests/airflow_core/test_worker_sets.py 
b/helm-tests/tests/helm_tests/airflow_core/test_worker_sets.py
index 1d71fe813ca..d15554ab0f8 100644
--- a/helm-tests/tests/helm_tests/airflow_core/test_worker_sets.py
+++ b/helm-tests/tests/helm_tests/airflow_core/test_worker_sets.py
@@ -1205,46 +1205,100 @@ class TestWorkerSets:
 
         assert jmespath.search("[*].metadata.name", docs) == expected
 
-    def 
test_overwrite_service_account_automount_service_account_token_disable(self):
-        docs = render_chart(
-            values={
-                "workers": {
-                    "celery": {
-                        "enableDefault": False,
-                        "sets": [{"name": "test", "serviceAccount": 
{"automountServiceAccountToken": False}}],
-                    },
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "sets": [{"name": "test", "serviceAccount": {"create": 
False}}],
+                }
+            },
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "serviceAccount": {"create": True},
+                    "sets": [{"name": "test", "serviceAccount": {"create": 
False}}],
                 }
             },
+            {
+                "serviceAccount": {"create": True},
+                "celery": {
+                    "enableDefault": False,
+                    "sets": [{"name": "test", "serviceAccount": {"create": 
False}}],
+                },
+            },
+        ],
+    )
+    def test_overwrite_service_account_create_disable(self, workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
             show_only=["templates/workers/worker-serviceaccount.yaml"],
         )
 
-        assert jmespath.search("automountServiceAccountToken", docs[0]) is 
False
+        assert len(docs) == 0
 
-    def test_overwrite_service_account_create_disable(self):
-        docs = render_chart(
-            values={
-                "workers": {
-                    "celery": {
-                        "enableDefault": False,
-                        "sets": [{"name": "test", "serviceAccount": {"create": 
False}}],
-                    },
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "sets": [{"name": "test", "serviceAccount": 
{"automountServiceAccountToken": False}}],
+                }
+            },
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "serviceAccount": {"automountServiceAccountToken": True},
+                    "sets": [{"name": "test", "serviceAccount": 
{"automountServiceAccountToken": False}}],
                 }
             },
+            {
+                "serviceAccount": {"automountServiceAccountToken": True},
+                "celery": {
+                    "enableDefault": False,
+                    "sets": [{"name": "test", "serviceAccount": 
{"automountServiceAccountToken": False}}],
+                },
+            },
+        ],
+    )
+    def 
test_overwrite_service_account_automount_service_account_token_disable(self, 
workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
             show_only=["templates/workers/worker-serviceaccount.yaml"],
         )
 
-        assert len(docs) == 0
+        assert jmespath.search("automountServiceAccountToken", docs[0]) is 
False
 
-    def test_overwrite_service_account_name(self):
-        docs = render_chart(
-            values={
-                "workers": {
-                    "celery": {
-                        "enableDefault": False,
-                        "sets": [{"name": "test", "serviceAccount": {"name": 
"test"}}],
-                    },
+    @pytest.mark.parametrize(
+        "workers_values",
+        [
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "sets": [{"name": "test", "serviceAccount": {"name": 
"test"}}],
                 }
             },
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "serviceAccount": {"name": "nontest"},
+                    "sets": [{"name": "test", "serviceAccount": {"name": 
"test"}}],
+                }
+            },
+            {
+                "serviceAccount": {"name": "nontest"},
+                "celery": {
+                    "enableDefault": False,
+                    "sets": [{"name": "test", "serviceAccount": {"name": 
"test"}}],
+                },
+            },
+        ],
+    )
+    def test_overwrite_service_account_name(self, workers_values):
+        docs = render_chart(
+            values={"workers": workers_values},
             show_only=["templates/workers/worker-serviceaccount.yaml"],
         )
 
@@ -1264,6 +1318,13 @@ class TestWorkerSets:
                     "sets": [{"name": "test", "serviceAccount": 
{"annotations": {"test": "echo"}}}],
                 },
             },
+            {
+                "celery": {
+                    "enableDefault": False,
+                    "serviceAccount": {"annotations": {"echo": "test"}},
+                    "sets": [{"name": "test", "serviceAccount": 
{"annotations": {"test": "echo"}}}],
+                },
+            },
         ],
     )
     def test_overwrite_service_account_annotations(self, workers_values):

Reply via email to