From 04e01247748bd9031ec78d3030212aac958c7f3f Mon Sep 17 00:00:00 2001 From: hussein-awala Date: Wed, 15 Nov 2023 01:13:27 +0200 Subject: [PATCH] Support configuring multiple namespace for multiNamespaceMode --- chart/templates/configmaps/configmap.yaml | 51 +++++++++++------- .../rbac/pod-launcher-rolebinding.yaml | 15 +++++- ...curity-context-constraint-rolebinding.yaml | 8 ++- .../secrets/elasticsearch-secret.yaml | 29 +++++++--- chart/templates/secrets/fernetkey-secret.yaml | 25 ++++++--- .../secrets/metadata-connection-secret.yaml | 32 +++++++---- chart/templates/secrets/registry-secret.yaml | 25 ++++++--- .../result-backend-connection-secret.yaml | 24 ++++++--- .../secrets/webserver-secret-key-secret.yaml | 27 +++++++--- .../workers/worker-serviceaccount.yaml | 29 +++++++--- chart/values.schema.json | 9 ++++ chart/values.yaml | 4 ++ helm_tests/airflow_aux/test_configmap.py | 26 +++++++++ helm_tests/airflow_core/test_worker.py | 54 +++++++++++++++++++ 14 files changed, 284 insertions(+), 74 deletions(-) diff --git a/chart/templates/configmaps/configmap.yaml b/chart/templates/configmaps/configmap.yaml index b93c1cbe1e51d..528b77ad83609 100644 --- a/chart/templates/configmaps/configmap.yaml +++ b/chart/templates/configmaps/configmap.yaml @@ -20,55 +20,68 @@ ################################ ## Airflow ConfigMap ################################# +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: ConfigMap metadata: - name: {{ template "airflow_config" . }} + name: {{ template "airflow_config" $ }} + namespace: {{ $namespace }} labels: tier: airflow component: config - release: {{ .Release.Name }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - heritage: {{ .Release.Service }} - {{- with .Values.labels }} + release: {{ $.Release.Name }} + chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} {{- toYaml . | nindent 4 }} {{- end -}} - {{- if .Values.airflowConfigAnnotations }} - annotations: {{- toYaml .Values.airflowConfigAnnotations | nindent 4 }} + {{- if $.Values.airflowConfigAnnotations }} + annotations: {{- toYaml $.Values.airflowConfigAnnotations | nindent 4 }} {{- end }} -{{- $Global := . }} +{{- $Global := $ }} data: # These are system-specified config overrides. airflow.cfg: |- - {{- range $section, $settings := .Values.config }} + {{- range $section, $settings := $.Values.config }} [{{ $section }}] {{- range $key, $val := $settings }} {{ $key }} = {{ tpl ($val | toString) $Global }} {{- end }} {{ end }} - {{- if .Values.airflowLocalSettings }} + {{- if $.Values.airflowLocalSettings }} airflow_local_settings.py: |- - {{- tpl .Values.airflowLocalSettings . | nindent 4 }} + {{- tpl $.Values.airflowLocalSettings $ | nindent 4 }} {{- end }} - {{- if and .Values.dags.gitSync.enabled .Values.dags.gitSync.knownHosts }} + {{- if and $.Values.dags.gitSync.enabled $.Values.dags.gitSync.knownHosts }} known_hosts: |- - {{- .Values.dags.gitSync.knownHosts | nindent 4 }} + {{- $.Values.dags.gitSync.knownHosts | nindent 4 }} {{- end }} {{- if or (eq $.Values.executor "LocalKubernetesExecutor") (eq $.Values.executor "KubernetesExecutor") (eq $.Values.executor "CeleryKubernetesExecutor") }} -{{- if semverCompare ">=1.10.12" .Values.airflowVersion }} +{{- if semverCompare ">=1.10.12" $.Values.airflowVersion }} pod_template_file.yaml: |- - {{- if .Values.podTemplate }} - {{- tpl .Values.podTemplate . | nindent 4 }} + {{- if $.Values.podTemplate }} + {{- tpl $.Values.podTemplate $ | nindent 4 }} {{- else }} - {{- tpl (.Files.Get "files/pod-template-file.kubernetes-helm-yaml") . | nindent 4 }} + {{- tpl ($.Files.Get "files/pod-template-file.kubernetes-helm-yaml") $ | nindent 4 }} {{- end }} {{- end }} {{- end }} - {{- if .Values.kerberos.enabled }} + {{- if $.Values.kerberos.enabled }} krb5.conf: |- - {{- tpl .Values.kerberos.config . | nindent 4 }} + {{- tpl $.Values.kerberos.config $ | nindent 4 }} {{- end }} +{{- end }} diff --git a/chart/templates/rbac/pod-launcher-rolebinding.yaml b/chart/templates/rbac/pod-launcher-rolebinding.yaml index 60705c8993a77..637c9eee7463e 100644 --- a/chart/templates/rbac/pod-launcher-rolebinding.yaml +++ b/chart/templates/rbac/pod-launcher-rolebinding.yaml @@ -23,6 +23,15 @@ {{- if and .Values.rbac.create .Values.allowPodLaunching }} {{- $schedulerLaunchExecutors := list "LocalExecutor" "LocalKubernetesExecutor" "KubernetesExecutor" "CeleryKubernetesExecutor" }} {{- $workerLaunchExecutors := list "CeleryExecutor" "LocalKubernetesExecutor" "KubernetesExecutor" "CeleryKubernetesExecutor" }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} apiVersion: rbac.authorization.k8s.io/v1 {{- if .Values.multiNamespaceMode }} kind: ClusterRoleBinding @@ -57,8 +66,10 @@ subjects: namespace: "{{ .Release.Namespace }}" {{- end }} {{- if has .Values.executor $workerLaunchExecutors }} + {{- range $namespace := $workersNamespaces }} - kind: ServiceAccount - name: {{ include "worker.serviceAccountName" . }} - namespace: "{{ .Release.Namespace }}" + name: {{ include "worker.serviceAccountName" $ }} + namespace: {{ $namespace }} + {{- end }} {{- end }} {{- end }} diff --git a/chart/templates/rbac/security-context-constraint-rolebinding.yaml b/chart/templates/rbac/security-context-constraint-rolebinding.yaml index 070a8e8169ae8..98184e6f232b4 100644 --- a/chart/templates/rbac/security-context-constraint-rolebinding.yaml +++ b/chart/templates/rbac/security-context-constraint-rolebinding.yaml @@ -21,6 +21,8 @@ ## Airflow SCC Role Binding ################################# {{- if and .Values.rbac.create .Values.rbac.createSCCRoleBinding }} +{{- $defaultWorkersNamespaces := list (.Release.Namespace | quote)}} +{{- $workerNamespaces := (.Values.multiNamespaceMode | ternary (concat $defaultWorkersNamespaces .Values.airflowNamespaces | uniq) $defaultWorkersNamespaces) }} {{- $hasWorkers := has .Values.executor (list "CeleryExecutor" "LocalKubernetesExecutor" "KubernetesExecutor" "CeleryKubernetesExecutor") }} apiVersion: rbac.authorization.k8s.io/v1 {{- if .Values.multiNamespaceMode }} @@ -50,9 +52,11 @@ subjects: name: {{ include "webserver.serviceAccountName" . }} namespace: "{{ .Release.Namespace }}" {{- if $hasWorkers }} + {{- range $namespace := $workerNamespaces }} - kind: ServiceAccount - name: {{ include "worker.serviceAccountName" . }} - namespace: "{{ .Release.Namespace }}" + name: {{ include "worker.serviceAccountName" $ }} + namespace: {{ $namespace }} + {{- end }} {{- end }} - kind: ServiceAccount name: {{ include "scheduler.serviceAccountName" . }} diff --git a/chart/templates/secrets/elasticsearch-secret.yaml b/chart/templates/secrets/elasticsearch-secret.yaml index aea70f7af91c8..a2dc89387cadd 100644 --- a/chart/templates/secrets/elasticsearch-secret.yaml +++ b/chart/templates/secrets/elasticsearch-secret.yaml @@ -21,24 +21,37 @@ ## Elasticsearch Secret ################################# {{- if (and .Values.elasticsearch.enabled (not .Values.elasticsearch.secretName)) }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: Secret metadata: - name: {{ include "airflow.fullname" . }}-elasticsearch + name: {{ include "airflow.fullname" $ }}-elasticsearch + namespace: {{ $namespace }} labels: - release: {{ .Release.Name }} - chart: {{ .Chart.Name }} - heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + release: {{ $.Release.Name }} + chart: {{ $.Chart.Name }} + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} + {{- toYaml $ | nindent 4 }} {{- end }} type: Opaque data: - {{- with .Values.elasticsearch.connection }} - {{- if and .user .pass }} + {{- with $.Values.elasticsearch.connection }} + {{- if and $.user $.pass }} connection: {{ urlJoin (dict "scheme" (default "http" .scheme) "userinfo" (printf "%s:%s" (.user | urlquery) (.pass | urlquery)) "host" (printf "%s:%s" .host ((default 9200 .port) | toString) ) ) | b64enc | quote }} {{- else }} connection: {{ urlJoin (dict "scheme" (default "http" .scheme) "host" (printf "%s:%s" .host ((default 9200 .port) | toString))) | b64enc | quote }} {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/chart/templates/secrets/fernetkey-secret.yaml b/chart/templates/secrets/fernetkey-secret.yaml index a917aab2d33b9..ad83beaa17e05 100644 --- a/chart/templates/secrets/fernetkey-secret.yaml +++ b/chart/templates/secrets/fernetkey-secret.yaml @@ -22,16 +22,28 @@ ################################# {{- if not .Values.fernetKeySecretName }} {{- $generated_fernet_key := (randAlphaNum 32 | b64enc) }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: Secret metadata: - name: {{ .Release.Name }}-fernet-key + name: {{ $.Release.Name }}-fernet-key + namespace: {{ $namespace }} labels: tier: airflow - release: {{ .Release.Name }} - chart: {{ .Chart.Name }} - heritage: {{ .Release.Service }} - {{- with .Values.labels }} + release: {{ $.Release.Name }} + chart: {{ $.Chart.Name }} + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} {{- toYaml . | nindent 4 }} {{- end }} annotations: @@ -40,5 +52,6 @@ metadata: "helm.sh/hook-weight": "0" type: Opaque data: - fernet-key: {{ (default $generated_fernet_key .Values.fernetKey) | b64enc | quote }} + fernet-key: {{ (default $generated_fernet_key $.Values.fernetKey) | b64enc | quote }} +{{- end }} {{- end }} diff --git a/chart/templates/secrets/metadata-connection-secret.yaml b/chart/templates/secrets/metadata-connection-secret.yaml index c25156d118e78..5e669f2978018 100644 --- a/chart/templates/secrets/metadata-connection-secret.yaml +++ b/chart/templates/secrets/metadata-connection-secret.yaml @@ -30,26 +30,38 @@ {{- $metadataDatabase := .Values.data.metadataConnection.db }} {{- $database := (ternary (printf "%s-%s" .Release.Name "metadata") $metadataDatabase .Values.pgbouncer.enabled) }} {{- $query := ternary (printf "sslmode=%s" .Values.data.metadataConnection.sslmode) "" (eq .Values.data.metadataConnection.protocol "postgresql") }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: Secret metadata: - name: {{ include "airflow.fullname" . }}-metadata + name: {{ include "airflow.fullname" $ }}-metadata + namespace: {{ $namespace }} labels: tier: airflow - release: {{ .Release.Name }} - chart: {{ .Chart.Name }} - heritage: {{ .Release.Service }} - {{- with .Values.labels }} + release: {{ $.Release.Name }} + chart: {{ $.Chart.Name }} + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} {{- toYaml . | nindent 4 }} {{- end }} type: Opaque data: - {{- with .Values.data.metadataConnection }} + {{- with $.Values.data.metadataConnection }} connection: {{ urlJoin (dict "scheme" .protocol "userinfo" (printf "%s:%s" (.user | urlquery) (.pass | urlquery) ) "host" (printf "%s:%s" $host $port) "path" (printf "/%s" $database) "query" $query) | b64enc | quote }} {{- end }} - {{- if and .Values.workers.keda.enabled .Values.pgbouncer.enabled (not .Values.workers.keda.usePgbouncer) }} - {{- with .Values.data.metadataConnection }} - kedaConnection: {{ urlJoin (dict "scheme" .protocol "userinfo" (printf "%s:%s" (.user | urlquery) (.pass | urlquery) ) "host" (printf "%s:%s" $metadataHost $metadataPort) "path" (printf "/%s" $metadataDatabase) "query" $query) | b64enc | quote }} - {{- end }} + {{- if and $.Values.workers.keda.enabled $.Values.pgbouncer.enabled (not $.Values.workers.keda.usePgbouncer) }} + {{- with $.Values.data.metadataConnection }} + kedaConnection: {{ urlJoin (dict "scheme" .protocol "userinfo" (printf "%s:%s" (.user | urlquery) (.pass | urlquery) ) "host" (printf "%s:%s" $metadataHost $metadataPort) "path" (printf "/%s" $metadataDatabase) "query" $query) | b64enc | quote }} {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/chart/templates/secrets/registry-secret.yaml b/chart/templates/secrets/registry-secret.yaml index 19add845ac5c9..f7ae180c4901c 100644 --- a/chart/templates/secrets/registry-secret.yaml +++ b/chart/templates/secrets/registry-secret.yaml @@ -21,18 +21,31 @@ ## Registry Secret ################################# {{- if (and .Values.registry.connection (not .Values.registry.secretName)) }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: Secret metadata: - name: {{ include "airflow.fullname" . }}-registry + name: {{ include "airflow.fullname" $ }}-registry + namespace: {{ $namespace }} labels: - release: {{ .Release.Name }} - chart: {{ .Chart.Name }} - heritage: {{ .Release.Service }} - {{- with .Values.labels }} + release: {{ $.Release.Name }} + chart: {{ $.Chart.Name }} + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/dockerconfigjson data: - .dockerconfigjson: {{ include "registry_docker_config" . | b64enc }} + .dockerconfigjson: {{ include "registry_docker_config" $ | b64enc }} +{{- end }} {{- end }} diff --git a/chart/templates/secrets/result-backend-connection-secret.yaml b/chart/templates/secrets/result-backend-connection-secret.yaml index e89046d3dde35..fdb110228b351 100644 --- a/chart/templates/secrets/result-backend-connection-secret.yaml +++ b/chart/templates/secrets/result-backend-connection-secret.yaml @@ -30,17 +30,28 @@ {{- $port := (ternary .Values.ports.pgbouncer $connection.port .Values.pgbouncer.enabled) | toString }} {{- $database := ternary (printf "%s-%s" .Release.Name "result-backend") $connection.db .Values.pgbouncer.enabled }} {{- $query := ternary (printf "sslmode=%s" $connection.sslmode) "" (eq $connection.protocol "postgresql") }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: Secret metadata: - name: {{ include "airflow.fullname" . }}-result-backend + name: {{ include "airflow.fullname" $ }}-result-backend labels: tier: airflow - release: {{ .Release.Name }} - chart: {{ .Chart.Name }} - heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + release: {{ $.Release.Name }} + chart: {{ $.Chart.Name }} + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} + {{- toYaml $ | nindent 4 }} {{- end }} type: Opaque data: @@ -48,3 +59,4 @@ data: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/chart/templates/secrets/webserver-secret-key-secret.yaml b/chart/templates/secrets/webserver-secret-key-secret.yaml index d7b1d5236f39e..56e8bf06f5502 100644 --- a/chart/templates/secrets/webserver-secret-key-secret.yaml +++ b/chart/templates/secrets/webserver-secret-key-secret.yaml @@ -22,20 +22,33 @@ ############################################ {{- if not .Values.webserverSecretKeySecretName }} {{ $generated_secret_key := (randAlphaNum 32 | b64enc) }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: Secret metadata: - name: {{ include "airflow.fullname" . }}-webserver-secret-key + name: {{ include "airflow.fullname" $ }}-webserver-secret-key + namespace: {{ $namespace }} labels: tier: airflow component: webserver - release: {{ .Release.Name }} - chart: {{ .Chart.Name }} - heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + release: {{ $.Release.Name }} + chart: {{ $.Chart.Name }} + heritage: {{ $.Release.Service }} + {{- with $.Values.labels }} + {{- toYaml $ | nindent 4 }} {{- end }} type: Opaque data: - webserver-secret-key: {{ (default $generated_secret_key .Values.webserverSecretKey) | b64enc | quote }} + webserver-secret-key: {{ (default $generated_secret_key $.Values.webserverSecretKey) | b64enc | quote }} +{{- end }} {{- end }} diff --git a/chart/templates/workers/worker-serviceaccount.yaml b/chart/templates/workers/worker-serviceaccount.yaml index 87dbb9728478c..168a20888151f 100644 --- a/chart/templates/workers/worker-serviceaccount.yaml +++ b/chart/templates/workers/worker-serviceaccount.yaml @@ -21,21 +21,34 @@ ## Airflow Worker ServiceAccount ################################# {{- if and .Values.workers.serviceAccount.create (or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor") (eq .Values.executor "KubernetesExecutor") (eq .Values.executor "LocalKubernetesExecutor")) }} +{{- $workersNamespaces := list }} +{{- if .Values.multiNamespaceMode }} + {{- range $namespace := .Values.airflowNamespaces }} + {{- $workersNamespaces = mustAppend $workersNamespaces ($namespace | quote) }} + {{- end }} +{{- end }} +{{- if not (has (.Release.Namespace | quote) $workersNamespaces) }} + {{ $workersNamespaces = mustPrepend $workersNamespaces (.Release.Namespace | quote) }} +{{- end }} +{{- range $namespace := $workersNamespaces }} +--- apiVersion: v1 kind: ServiceAccount -automountServiceAccountToken: {{ .Values.workers.serviceAccount.automountServiceAccountToken }} +automountServiceAccountToken: {{ $.Values.workers.serviceAccount.automountServiceAccountToken }} metadata: - name: {{ include "worker.serviceAccountName" . }} + name: {{ include "worker.serviceAccountName" $ }} + namespace: {{ $namespace }} 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 }} + 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.serviceAccount.annotations}} + {{- with $.Values.workers.serviceAccount.annotations}} annotations: {{- toYaml . | nindent 4 }} {{- end }} {{- end }} +{{- end }} diff --git a/chart/values.schema.json b/chart/values.schema.json index e031376b8145d..544f9c50d0d3e 100644 --- a/chart/values.schema.json +++ b/chart/values.schema.json @@ -7038,6 +7038,15 @@ "type": "boolean", "default": false }, + "airflowNamespaces": { + "description": "The list of the namespaces that will be used to create workers in multi namespace mode. A service account will be created in each namespace, and the cluster role will be bound to it.", + "x-docsSection": "Airflow", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, "podTemplate": { "description": "The contents of ``pod_template_file.yaml`` used for KubernetesExecutor workers (templated). The default (see ``files/pod-template-file.kubernetes-helm-yaml``) already takes into account normal ``workers`` configuration parameters (e.g. ``workers.resources``), so you normally won't need to override this directly.", "type": [ diff --git a/chart/values.yaml b/chart/values.yaml index 5e14e4029c058..bb322a0fc18b3 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -2366,6 +2366,10 @@ config: # If true, it creates ClusterRole/ClusterRolebinding (with access to entire cluster) multiNamespaceMode: false +# The list of the namespaces that will be used to create workers in multi namespace mode. +# A service account will be created in each namespace, and the cluster role will be bound to it. +airflowNamespaces: [] + # `podTemplate` is a templated string containing the contents of `pod_template_file.yaml` used for # KubernetesExecutor workers. The default `podTemplate` will use normal `workers` configuration parameters # (e.g. `workers.resources`). As such, you normally won't need to override this directly, however, diff --git a/helm_tests/airflow_aux/test_configmap.py b/helm_tests/airflow_aux/test_configmap.py index 623f3f1067e10..c1a29289b9bb2 100644 --- a/helm_tests/airflow_aux/test_configmap.py +++ b/helm_tests/airflow_aux/test_configmap.py @@ -199,3 +199,29 @@ def test_expected_default_dag_folder(self, dag_values, expected_default_dag_fold cfg = jmespath.search('data."airflow.cfg"', docs[0]) expected_folder_config = f"dags_folder = {expected_default_dag_folder}" assert expected_folder_config in cfg.splitlines() + + @pytest.mark.parametrize( + "namespaces", [["airflow-1", "airflow-2"], ["default", "airflow-1", "airflow-2"]] + ) + def test_multi_namespace_mode(self, namespaces): + docs = render_chart( + values={ + "executor": "KubernetesExecutor", + "multiNamespaceMode": True, + "airflowNamespaces": namespaces, + "workers": { + "serviceAccount": {"create": True}, + }, + }, + show_only=["templates/configmaps/configmap.yaml"], + ) + assert len(docs) == 3 + assert ( + jmespath.search("metadata.name", docs[0]) + == jmespath.search("metadata.name", docs[1]) + == jmespath.search("metadata.name", docs[2]) + == "release-name-config" + ) + assert jmespath.search("metadata.namespace", docs[0]) == "default" + assert jmespath.search("metadata.namespace", docs[1]) == "airflow-1" + assert jmespath.search("metadata.namespace", docs[2]) == "airflow-2" diff --git a/helm_tests/airflow_core/test_worker.py b/helm_tests/airflow_core/test_worker.py index a65db04a5dbcf..05644172432e0 100644 --- a/helm_tests/airflow_core/test_worker.py +++ b/helm_tests/airflow_core/test_worker.py @@ -1062,6 +1062,60 @@ def test_should_create_worker_service_account_for_specific_executors( else: assert docs == [] + @pytest.mark.parametrize( + "namespaces", [["airflow-1", "airflow-2"], ["default", "airflow-1", "airflow-2"]] + ) + def test_multi_namespace_configuration_service_account(self, namespaces): + docs = render_chart( + values={ + "executor": "KubernetesExecutor", + "multiNamespaceMode": True, + "airflowNamespaces": namespaces, + "workers": { + "serviceAccount": {"create": True}, + }, + }, + show_only=["templates/workers/worker-serviceaccount.yaml"], + ) + assert len(docs) == 3 + assert ( + jmespath.search("metadata.name", docs[0]) + == jmespath.search("metadata.name", docs[1]) + == jmespath.search("metadata.name", docs[2]) + == "release-name-airflow-worker" + ) + assert jmespath.search("metadata.namespace", docs[0]) == "default" + assert jmespath.search("metadata.namespace", docs[1]) == "airflow-1" + assert jmespath.search("metadata.namespace", docs[2]) == "airflow-2" + + @pytest.mark.parametrize( + "namespaces", [["airflow-1", "airflow-2"], ["default", "airflow-1", "airflow-2"]] + ) + def test_multi_namespace_configuration_role_bindings(self, namespaces): + docs = render_chart( + values={ + "executor": "KubernetesExecutor", + "multiNamespaceMode": True, + "airflowNamespaces": namespaces, + "workers": { + "serviceAccount": {"create": True}, + }, + }, + show_only=["templates/rbac/pod-launcher-rolebinding.yaml"], + ) + assert jmespath.search("subjects[*].name", docs[0]) == [ + "release-name-airflow-scheduler", + "release-name-airflow-worker", + "release-name-airflow-worker", + "release-name-airflow-worker", + ] + assert jmespath.search("subjects[*].namespace", docs[0]) == [ + "default", + "default", + "airflow-1", + "airflow-2", + ] + def test_default_automount_service_account_token(self): docs = render_chart( values={