diff --git a/.vib/airflow/cypress/cypress.config.js b/.vib/airflow/cypress/cypress.config.js
index c735ac508c48a6..c520f589a1640a 100644
--- a/.vib/airflow/cypress/cypress.config.js
+++ b/.vib/airflow/cypress/cypress.config.js
@@ -1,12 +1,18 @@
module.exports = {
+ viewportWidth: 1920,
+ viewportHeight: 1080,
+ chromeWebSecurity: false,
pageLoadTimeout: 240000,
defaultCommandTimeout: 80000,
env: {
username: 'user',
password: 'ComplicatedPassword123!4',
+ baseUrl: 'http://vmware-airflow.my',
},
e2e: {
setupNodeEvents(on, config) {},
- baseUrl: 'http://localhost',
+ },
+ hosts: {
+ 'vmware-airflow.my': '{{ TARGET_IP }}',
},
}
diff --git a/.vib/airflow/cypress/cypress/e2e/airflow.cy.js b/.vib/airflow/cypress/cypress/e2e/airflow.cy.js
index be8e448e21d72a..7569233681c9f6 100644
--- a/.vib/airflow/cypress/cypress/e2e/airflow.cy.js
+++ b/.vib/airflow/cypress/cypress/e2e/airflow.cy.js
@@ -9,18 +9,22 @@ import { random } from '../support/utils';
it('allows triggering execution of a sample DAG', () => {
cy.login();
cy.fixture('DAGs').then((dags) => {
- cy.visit(`dags/${dags.triggered.id}/grid`);
- cy.get('[aria-label="Trigger DAG"]').click({force: true});
+ cy.visit(`/dags/${dags.triggered.id}`);
+ cy.get('[aria-label="Trigger Dag"]').click({force: true});
+ // Trigger button text is prefixed by a white space
+ cy.get('button').contains(' Trigger').click({force: true});
- // Verify the DAG appears in the list of active jobs
- cy.visit('home?status=active');
- cy.get(`[href='/dags/${dags.triggered.id}/grid']`);
+ // Verify the DAG was scheduled
+ cy.wait(3000);
+ cy.visit('/dags');
+ cy.get(`[href='/dags/${dags.triggered.id}']`);
+ cy.get('div').contains(new Date().toISOString().split('T')[0]);
});
});
it('allows to create a user', () => {
cy.login();
- cy.visit('users/add');
+ cy.visit('/auth/users/add');
cy.fixture('users').then((users) => {
cy.get('#first_name').type(users.newUser.firstName);
cy.get('#last_name').type(users.newUser.lastName);
@@ -30,8 +34,8 @@ it('allows to create a user', () => {
cy.get('#password').type(users.newUser.password);
cy.get('#conf_password').type(users.newUser.password);
cy.contains('Save').click();
-
- // Verify the user was created successfully
- cy.contains('div', 'Added Row');
});
+ // Verify the user was created successfully
+ cy.visit('/auth/users/add');
+ cy.contains('div', 'Added Row');
});
diff --git a/.vib/airflow/cypress/cypress/support/commands.js b/.vib/airflow/cypress/cypress/support/commands.js
index b98bbdac1c733a..76185f667ab5c9 100644
--- a/.vib/airflow/cypress/cypress/support/commands.js
+++ b/.vib/airflow/cypress/cypress/support/commands.js
@@ -17,10 +17,22 @@ for (const command of ['click']) {
});
}
+// Due to a bug when using "hosts" in Cypress, we cannot set a "baseUrl" in the
+// cypress.json file. Workaround this by modifying the "visit" command to preprend
+// the base URL.
+//
+// Further details: https://github.com/cypress-io/cypress/issues/20647
+Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
+ // Only replace relative URLs
+ const targetUrl = url.includes('://') ? url : `${Cypress.env('baseUrl')}${url}`;
+ return originalFn(targetUrl, options);
+});
+
+
Cypress.Commands.add(
'login',
(username = Cypress.env('username'), password = Cypress.env('password')) => {
- cy.visit('/login');
+ cy.visit('/');
// Wait for DOM content to load
cy.wait(5000);
cy.get('form[name="login"]').should('exist').and('be.visible'); // Needed to ensure stability of the test
@@ -31,9 +43,6 @@ Cypress.Commands.add(
);
Cypress.on('uncaught:exception', (err, runnable) => {
- if (
- err.message.includes('Cannot set properties of undefined')
- ) {
- return false;
- }
-});
\ No newline at end of file
+ // Skip all exceptions
+ return false;
+});
diff --git a/.vib/airflow/runtime-parameters.yaml b/.vib/airflow/runtime-parameters.yaml
index df4dd3d41331c6..48f90b88c22346 100644
--- a/.vib/airflow/runtime-parameters.yaml
+++ b/.vib/airflow/runtime-parameters.yaml
@@ -30,6 +30,7 @@ scheduler:
periodSeconds: 30
timeoutSeconds: 20
web:
+ baseUrl: 'http://vmware-airflow.my'
extraConfiguration: |
# Theme CONFIG
APP_THEME = "amelia.css"
@@ -39,6 +40,11 @@ web:
fsGroup: 1002
containerSecurityContext:
runAsUser: 1002
+ # Give some extra time for the service to start
+ startupProbe:
+ enabled: true
+ failureThreshold: 30
+ periodSeconds: 10
worker:
podSecurityContext:
fsGroup: 1002
diff --git a/.vib/airflow/vib-verify.json b/.vib/airflow/vib-verify.json
index 07e0bdc45a147c..318bd13d0e85a8 100644
--- a/.vib/airflow/vib-verify.json
+++ b/.vib/airflow/vib-verify.json
@@ -60,8 +60,9 @@
"resources": {
"path": "/.vib/airflow/cypress"
},
- "endpoint": "lb-airflow-http",
+ "endpoint": "lb-airflow-web-http",
"app_protocol": "HTTP",
+ "port": 80,
"env": {
"username": "user",
"password": "ComplicatedPassword123!4"
diff --git a/bitnami/airflow/CHANGELOG.md b/bitnami/airflow/CHANGELOG.md
index 68d52c9cb3fea3..6decf3291530d2 100644
--- a/bitnami/airflow/CHANGELOG.md
+++ b/bitnami/airflow/CHANGELOG.md
@@ -1,8 +1,12 @@
# Changelog
-## 22.7.3 (2025-04-21)
+## 23.0.0 (2025-04-29)
-* [bitnami/airflow] Release 22.7.3 ([#33087](https://github.com/bitnami/charts/pull/33087))
+* [bitnami/airflow] Release 23.0.0 ([#33141](https://github.com/bitnami/charts/pull/33141))
+
+## 22.7.3 (2025-04-21)
+
+* [bitnami/airflow] Release 22.7.3 (#33087) ([c62ad9b](https://github.com/bitnami/charts/commit/c62ad9b97dad33d09d2888d21066d9d25cafeed5)), closes [#33087](https://github.com/bitnami/charts/issues/33087)
## 22.7.2 (2025-03-25)
diff --git a/bitnami/airflow/Chart.lock b/bitnami/airflow/Chart.lock
index 2fbb7891b138f0..670ab5d6392892 100644
--- a/bitnami/airflow/Chart.lock
+++ b/bitnami/airflow/Chart.lock
@@ -1,12 +1,12 @@
dependencies:
- name: redis
repository: oci://registry-1.docker.io/bitnamicharts
- version: 20.12.1
+ version: 20.13.1
- name: postgresql
repository: oci://registry-1.docker.io/bitnamicharts
version: 16.6.3
- name: common
repository: oci://registry-1.docker.io/bitnamicharts
version: 2.30.0
-digest: sha256:8cd79ef253d7a517de839fd46e82e8b482a5c790cd4adc0b901f5fd878f42a02
-generated: "2025-04-21T01:13:19.809190595Z"
+digest: sha256:9da8ff790e57d014ce6015b9dddb7de1dfddf14e592cdd148dd07fb760b1340b
+generated: "2025-04-23T14:37:53.595077325Z"
diff --git a/bitnami/airflow/Chart.yaml b/bitnami/airflow/Chart.yaml
index 012083660f9e6b..d3c8e1a17494d8 100644
--- a/bitnami/airflow/Chart.yaml
+++ b/bitnami/airflow/Chart.yaml
@@ -7,11 +7,11 @@ annotations:
licenses: Apache-2.0
images: |
- name: airflow
- image: docker.io/bitnami/airflow:2.10.5-debian-12-r11
+ image: docker.io/bitnami/airflow:3.0.0-debian-12-r2
- name: statsd-exporter
image: docker.io/bitnami/statsd-exporter:0.28.0-debian-12-r15
apiVersion: v2
-appVersion: 2.10.5
+appVersion: 3.0.0
dependencies:
- condition: redis.enabled
name: redis
@@ -40,4 +40,4 @@ maintainers:
name: airflow
sources:
- https://github.com/bitnami/charts/tree/main/bitnami/airflow
-version: 22.7.3
+version: 23.0.0
diff --git a/bitnami/airflow/README.md b/bitnami/airflow/README.md
index 4d297e27d35174..5adcbd1cb19274 100644
--- a/bitnami/airflow/README.md
+++ b/bitnami/airflow/README.md
@@ -99,7 +99,7 @@ Bitnami charts configure credentials at first boot. Any further change in the se
- Update the password secret with the new values (replace the SECRET_NAME, PASSWORD, FERNET_KEY and SECRET_KEY placeholders)
```shell
-kubectl create secret generic SECRET_NAME --from-literal=airflow-password=PASSWORD --from-literal=airflow-fernet-key=FERNET_KEY --from-literal=airflow-secret-key=SECRET_KEY --dry-run -o yaml | kubectl apply -f -
+kubectl create secret generic SECRET_NAME --from-literal=airflow-password=PASSWORD --from-literal=airflow-fernet-key=FERNET_KEY --from-literal=airflow-secret-key=SECRET_KEY --from-literal=airflow-jwt-secret-key=JWT_SECRET_KEY --dry-run -o yaml | kubectl apply -f -
```
### Airflow configuration file
@@ -410,6 +410,7 @@ The Bitnami Airflow chart relies on the PostgreSQL chart persistence. This means
| `auth.password` | Password to access web UI | `""` |
| `auth.fernetKey` | Fernet key to secure connections | `""` |
| `auth.secretKey` | Secret key to run your flask app | `""` |
+| `auth.jwtSecretKey` | JWT secret key to run your flask app | `""` |
| `auth.existingSecret` | Name of an existing secret to use for Airflow credentials | `""` |
| `executor` | Airflow executor. Allowed values: `SequentialExecutor`, `LocalExecutor`, `CeleryExecutor`, `KubernetesExecutor`, `CeleryKubernetesExecutor` and `LocalKubernetesExecutor` | `CeleryExecutor` |
| `loadExamples` | Switch to load some Airflow examples | `false` |
@@ -712,7 +713,7 @@ The Bitnami Airflow chart relies on the PostgreSQL chart persistence. This means
| Name | Description | Value |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
-| `dagProcessor.enabled` | Run Airflow Dag Processor Manager as a standalone component | `false` |
+| `dagProcessor.enabled` | Run Airflow Dag Processor Manager as a standalone component | `true` |
| `dagProcessor.replicaCount` | Number of Airflow Dag Processor replicas | `1` |
| `dagProcessor.command` | Override default Airflow Dag Processor cmd | `[]` |
| `dagProcessor.args` | Override default Airflow Dag Processor args | `[]` |
@@ -806,7 +807,7 @@ The Bitnami Airflow chart relies on the PostgreSQL chart persistence. This means
| Name | Description | Value |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
-| `triggerer.enabled` | Run Airflow Triggerer as a standalone component | `false` |
+| `triggerer.enabled` | Run Airflow Triggerer as a standalone component | `true` |
| `triggerer.defaultCapacity` | How many triggers a single Triggerer can run at once | `1000` |
| `triggerer.replicaCount` | Number of Airflow Triggerer replicas | `1` |
| `triggerer.command` | Override default Airflow Triggerer cmd | `[]` |
@@ -1287,6 +1288,26 @@ Find more information about how to deal with common errors related to Bitnami's
## Upgrading
+### To 23.0.0
+
+This major release adds support for Airflow `3.x.y` series. Additionally, previous Airflow `2.x.y` series can be deployed by setting the corresponding image parameters. The chart logic will detect which image version you are using, and it will generate the required Airflow configuration and Kubernetes objects.
+
+We recommend following the next procedure in order to upgrade from `22.x.y` chart version to the `23.x.y` series, and also upgrade to Airflow `3.y.z` series:
+
+- Upgrade your release (maintaining Airflow `2.x.y` series):
+
+```console
+helm upgrade airflow oci://REGISTRY_NAME/REPOSITORY_NAME/airflow --set image.tag=2
+```
+
+- Follow the recommended steps for the database backup and the DAGs files verification available at the [official "upgrading to Airflow 3" guide](https://airflow.apache.org/docs/apache-airflow/stable/installation/upgrading_to_airflow3.html).
+
+- Upgrade your release now using the default Airflow `3.x.y` series:
+
+```console
+helm upgrade airflow oci://REGISTRY_NAME/REPOSITORY_NAME/airflow
+```
+
### To 22.4.0
This version introduces image verification for security purposes. To disable it, set `global.security.allowInsecureImages` to `true`. More details at [GitHub issue](https://github.com/bitnami/charts/issues/30850).
@@ -1526,4 +1547,4 @@ 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.
\ No newline at end of file
+limitations under the License.
diff --git a/bitnami/airflow/templates/_helpers.tpl b/bitnami/airflow/templates/_helpers.tpl
index c1fe887de5125b..7b33fdf5f786d3 100644
--- a/bitnami/airflow/templates/_helpers.tpl
+++ b/bitnami/airflow/templates/_helpers.tpl
@@ -352,6 +352,10 @@ Add environment variables to configure airflow common values
value: "cat /opt/bitnami/airflow/secrets/airflow-fernet-key"
- name: AIRFLOW__WEBSERVER__SECRET_KEY_CMD
value: "cat /opt/bitnami/airflow/secrets/airflow-secret-key"
+{{- if (include "airflow.isImageMajorVersion3" .) }}
+- name: AIRFLOW__API_AUTH__JWT_SECRET_CMD
+ value: "cat /opt/bitnami/airflow/secrets/airflow-jwt-secret-key"
+{{- end }}
{{- else }}
- name: AIRFLOW__CORE__FERNET_KEY
valueFrom:
@@ -363,6 +367,13 @@ Add environment variables to configure airflow common values
secretKeyRef:
name: {{ include "airflow.secretName" . }}
key: airflow-secret-key
+{{- if (include "airflow.isImageMajorVersion3" .) }}
+- name: AIRFLOW__API_AUTH__JWT_SECRET_CMD
+ valueFrom:
+ secretKeyRef:
+ name: {{ include "airflow.secretName" . }}
+ key: airflow-jwt-secret-key
+{{- end -}}
{{- end -}}
{{- end -}}
@@ -516,3 +527,36 @@ Ref: https://github.com/bitnami/charts/pull/6096#issuecomment-856499047
{{- define "airflow.worker.executor" -}}
{{- print (ternary "CeleryExecutor" .Values.executor (eq .Values.executor "CeleryKubernetesExecutor")) -}}
{{- end -}}
+
+{{/*
+Validates a semver constraint
+*/}}
+{{- define "airflow.semverCondition" -}}
+{{- $constraint := .constraint -}}
+{{- $imageVersion := (.imageVersion | toString) -}}
+
+{{/* tag 'latest' is an special case, where we fall to .Chart.AppVersion value */}}
+{{- if eq "latest" $imageVersion -}}
+{{- $imageVersion = .context.Chart.AppVersion -}}
+{{- else -}}
+{{- $imageVersion = (index (splitList "-" $imageVersion) 0 ) -}}
+{{- end -}}
+
+{{- if semverCompare $constraint $imageVersion -}}
+true
+{{- end -}}
+{{- end -}}
+
+{{/*
+Validates the image tag version is equal or higher than 3.0.0
+*/}}
+{{- define "airflow.isImageMajorVersion3" -}}
+{{- include "airflow.semverCondition" (dict "constraint" "^3" "imageVersion" .Values.image.tag "context" $) -}}
+{{- end -}}
+
+{{/*
+Validates the image tag version is equal or higher than 2.0.0
+*/}}
+{{- define "airflow.isImageMajorVersion2" -}}
+{{- include "airflow.semverCondition" (dict "constraint" "^2" "imageVersion" .Values.image.tag "context" $) -}}
+{{- end -}}
diff --git a/bitnami/airflow/templates/_init_containers_sidecars.tpl b/bitnami/airflow/templates/_init_containers_sidecars.tpl
index 7b8431f9d7ebd9..1e714dd9117378 100644
--- a/bitnami/airflow/templates/_init_containers_sidecars.tpl
+++ b/bitnami/airflow/templates/_init_containers_sidecars.tpl
@@ -60,6 +60,8 @@ Returns an init-container that prepares the Airflow configuration files for main
{{- end }}
airflow_conf_set "celery" "broker_url" "redis://${redis_credentials}@${REDIS_HOST}:${REDIS_PORT_NUMBER}/${REDIS_DATABASE}"
{{- end }}
+ # Configure authentication backend
+ airflow_conf_set "core" "auth_manager" "airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager"
info "Airflow configuration ready"
if [[ -f "/opt/bitnami/airflow/config/airflow_local_settings.py" ]]; then
@@ -125,6 +127,9 @@ Returns an init-container that prepares the Airflow configuration files for main
key: redis-password
{{- end }}
{{- end }}
+ {{- if .Values.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 4 }}
+ {{- end }}
volumeMounts:
- name: empty-dir
mountPath: /emptydir
@@ -187,6 +192,9 @@ Returns an init-container that prepares the Airflow Webserver configuration file
key: bind-password
{{- end }}
{{- end }}
+ {{- if .Values.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 4 }}
+ {{- end }}
volumeMounts:
- name: empty-dir
mountPath: /emptydir
@@ -222,11 +230,20 @@ Returns an init-container that waits for db migrations to be ready
. /opt/bitnami/scripts/airflow-env.sh
. /opt/bitnami/scripts/libairflow.sh
+ info "Trying to connect to the database server"
+ airflow_wait_for_db_connection
info "Waiting for db migrations to be completed"
airflow_wait_for_db_migrations
+ {{- if (include "airflow.isImageMajorVersion3" .) }}
+ info "Waiting for the admin user to exist"
+ airflow_wait_for_admin_user
+ {{- end }}
env:
- name: BITNAMI_DEBUG
value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }}
+ {{- if .Values.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 4 }}
+ {{- end }}
volumeMounts:
- name: empty-dir
mountPath: /tmp
@@ -276,9 +293,15 @@ Returns shared structure between load-dags and load-plugins init containers
{{- else }}
command: ["/bin/bash"]
{{- end }}
- {{- if .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVars }}
- env: {{- include "common.tplvalues.render" (dict "value" .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVars "context" .) | nindent 4 }}
- {{- end }}
+ env:
+ - name: BITNAMI_DEBUG
+ value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }}
+ {{- if .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVars "context" .) | nindent 4 }}
+ {{- end }}
+ {{- if .Values.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 4 }}
+ {{- end }}
{{- if or .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVarsCM .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVarsSecret }}
envFrom:
{{- if .Values.defaultInitContainers.loadDAGsPlugins.extraEnvVarsCM }}
@@ -417,9 +440,15 @@ Returns shared structure between sync-dags and sync-plugins sidecars
{{- else }}
command: ["/bin/bash"]
{{- end }}
- {{- if .Values.defaultSidecars.syncDAGsPlugins.extraEnvVars }}
- env: {{- include "common.tplvalues.render" (dict "value" .Values.defaultSidecars.syncDAGsPlugins.extraEnvVars "context" .) | nindent 4 }}
- {{- end }}
+ env:
+ - name: BITNAMI_DEBUG
+ value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }}
+ {{- if .Values.defaultSidecars.syncDAGsPlugins.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.defaultSidecars.syncDAGsPlugins.extraEnvVars "context" .) | nindent 4 }}
+ {{- end }}
+ {{- if .Values.extraEnvVars }}
+ {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 4 }}
+ {{- end }}
{{- if or .Values.defaultSidecars.syncDAGsPlugins.extraEnvVarsCM .Values.defaultSidecars.syncDAGsPlugins.extraEnvVarsSecret }}
envFrom:
{{- if .Values.defaultSidecars.syncDAGsPlugins.extraEnvVarsCM }}
diff --git a/bitnami/airflow/templates/config/configmap.yaml b/bitnami/airflow/templates/config/configmap.yaml
index ccd56c46887878..d7d0953621ce8c 100644
--- a/bitnami/airflow/templates/config/configmap.yaml
+++ b/bitnami/airflow/templates/config/configmap.yaml
@@ -14,6 +14,9 @@ ref: https://airflow.apache.org/docs/apache-airflow/stable/configurations-ref.ht
core:
load_examples: {{ ternary "True" "False" .Values.loadExamples | squote }}
executor: {{ .Values.executor | quote }}
+ {{- if (include "airflow.isImageMajorVersion3" .) }}
+ execution_api_server_url: {{ printf "http://%s:%s/execution/" (include "airflow.web.fullname" .) (.Values.service.ports.http | toString) | quote }}
+ {{- end }}
logging:
colored_console_log: 'False'
metrics:
@@ -24,15 +27,26 @@ metrics:
scheduler:
standalone_dag_processor: {{ ternary "True" "False" .Values.dagProcessor.enabled | squote }}
triggerer:
+ {{- if (include "airflow.isImageMajorVersion2" .) }}
default_capacity: {{ .Values.triggerer.defaultCapacity | quote }}
+ {{- else }}
+ capacity: {{ .Values.triggerer.defaultCapacity | quote }}
+ {{- end }}
webserver:
base_url: {{ include "airflow.baseUrl" . | quote }}
enable_proxy_fix: {{ ternary "True" "False" (and .Values.ingress.enabled .Values.ingress.tls) | squote }}
- web_server_port: {{ .Values.web.containerPorts.http | quote }}
{{- if .Values.web.tls.enabled }}
web_server_ssl_cert: "/opt/bitnami/airflow/certs/tls.crt"
web_server_ssl_key: "/opt/bitnami/airflow/certs/tls.key"
{{- end }}
+ {{- if (include "airflow.isImageMajorVersion2" .) }}
+ web_server_port: {{ .Values.web.containerPorts.http | quote }}
+ {{- end }}
+{{- if (include "airflow.isImageMajorVersion3" .) }}
+api:
+ base_url: {{ include "airflow.baseUrl" . | quote }}
+ port: {{ .Values.web.containerPorts.http | quote }}
+{{- end }}
{{- if contains "KubernetesExecutor" .Values.executor }}
kubernetes_executor:
namespace: {{ include "common.names.namespace" . | quote }}
diff --git a/bitnami/airflow/templates/config/secret.yaml b/bitnami/airflow/templates/config/secret.yaml
index 092a12fddd5692..1a4170c54b30c9 100644
--- a/bitnami/airflow/templates/config/secret.yaml
+++ b/bitnami/airflow/templates/config/secret.yaml
@@ -29,4 +29,11 @@ data:
{{- else }}
airflow-secret-key: {{ randAlphaNum 32 | b64enc | b64enc | quote }}
{{- end }}
+ {{- if (include "airflow.isImageMajorVersion3" .) }}
+ {{- if or (include "common.secrets.exists" (dict "secret" (include "common.names.fullname" .) "context" $)) (not (empty .Values.auth.jwtSecretKey)) }}
+ airflow-jwt-secret-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "airflow-jwt-secret-key" "providedValues" (list "auth.jwtSecretKey") "failOnNew" false "context" $) }}
+ {{- else }}
+ airflow-jwt-secret-key: {{ randAlphaNum 32 | b64enc | b64enc | quote }}
+ {{- end }}
+ {{- end }}
{{- end }}
diff --git a/bitnami/airflow/templates/dag-processor/deployment.yaml b/bitnami/airflow/templates/dag-processor/deployment.yaml
index f5a127aa2ca13e..ea62597029aa87 100644
--- a/bitnami/airflow/templates/dag-processor/deployment.yaml
+++ b/bitnami/airflow/templates/dag-processor/deployment.yaml
@@ -113,6 +113,8 @@ spec:
value: {{ include "airflow.redis.host" . | quote }}
- name: REDIS_PORT_NUMBER
value: {{ include "airflow.redis.port" . | quote }}
+ - name: PYTHONPYCACHEPREFIX
+ value: "/opt/bitnami/airflow/venv/tmp"
{{- end }}
{{- if .Values.extraEnvVars }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }}
@@ -143,15 +145,12 @@ spec:
{{- if .Values.dagProcessor.customLivenessProbe }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.dagProcessor.customLivenessProbe "context" $) | trim | nindent 12 }}
{{- else if .Values.dagProcessor.livenessProbe.enabled }}
- {{- $livenessTimeout := sub (int .Values.dagProcessor.livenessProbe.timeoutSeconds) 1 }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.dagProcessor.livenessProbe "enabled") "context" $) | nindent 12 }}
exec:
command:
- - /bin/bash
- - -ec
- - |
- export CONNECTION_CHECK_MAX_COUNT=0
- timeout {{ $livenessTimeout }} airflow jobs check --job-type DagProcessorJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ - pgrep
+ - -f
+ - "airflow dag-processor"
{{- end }}
{{- if .Values.dagProcessor.customReadinessProbe }}
readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.dagProcessor.customReadinessProbe "context" $) | trim | nindent 12 }}
@@ -163,7 +162,8 @@ spec:
- /bin/bash
- -ec
- |
- timeout {{ $readinessTimeout }} airflow jobs check --job-type DagProcessorJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ export CONNECTION_CHECK_MAX_COUNT=0
+ timeout {{ $readinessTimeout }} airflow jobs check --job-type DagProcessorJob --local --limit 0 {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
{{- end }}
{{- if .Values.dagProcessor.customStartupProbe }}
startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.dagProcessor.customStartupProbe "context" $) | nindent 12 }}
@@ -176,7 +176,7 @@ spec:
- -ec
- |
export CONNECTION_CHECK_MAX_COUNT=0
- timeout {{ $startupTimeout }} airflow jobs check --job-type DagProcessorJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ timeout {{ $startupTimeout }} airflow jobs check --job-type DagProcessorJob --local --limit 0 {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
{{- end }}
{{- end }}
{{- if .Values.dagProcessor.lifecycleHooks }}
@@ -209,6 +209,11 @@ spec:
- name: empty-dir
mountPath: /opt/bitnami/airflow/config/airflow_local_settings.py
subPath: app-conf-dir/airflow_local_settings.py
+ {{- if and .Values.web.containerSecurityContext.enabled .Values.web.containerSecurityContext.readOnlyRootFilesystem }}
+ - name: empty-dir
+ mountPath: /opt/bitnami/airflow/venv/tmp
+ subPath: app-pyc-cache-dir
+ {{- end }}
{{- if .Values.usePasswordFiles }}
- name: airflow-secrets
mountPath: /opt/bitnami/airflow/secrets
diff --git a/bitnami/airflow/templates/scheduler/deployment.yaml b/bitnami/airflow/templates/scheduler/deployment.yaml
index ac98901ba91a0b..5b3ba78b4e6b9a 100644
--- a/bitnami/airflow/templates/scheduler/deployment.yaml
+++ b/bitnami/airflow/templates/scheduler/deployment.yaml
@@ -108,6 +108,8 @@ spec:
value: "scheduler"
- name: AIRFLOW_EXECUTOR
value: {{ .Values.executor }}
+ - name: PYTHONPYCACHEPREFIX
+ value: "/opt/bitnami/airflow/venv/tmp"
{{- if or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor") }}
- name: REDIS_HOST
value: {{ include "airflow.redis.host" . | quote }}
@@ -155,15 +157,12 @@ spec:
{{- if .Values.scheduler.customLivenessProbe }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.scheduler.customLivenessProbe "context" $) | trim | nindent 12 }}
{{- else if .Values.scheduler.livenessProbe.enabled }}
- {{- $livenessTimeout := sub (int .Values.scheduler.livenessProbe.timeoutSeconds) 1 }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.scheduler.livenessProbe "enabled") "context" $) | nindent 12 }}
exec:
command:
- - /bin/bash
- - -ec
- - |
- export CONNECTION_CHECK_MAX_COUNT=0
- timeout {{ $livenessTimeout }} airflow jobs check --job-type SchedulerJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ - pgrep
+ - -f
+ - "airflow scheduler"
{{- end }}
{{- if .Values.scheduler.customReadinessProbe }}
readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.scheduler.customReadinessProbe "context" $) | trim | nindent 12 }}
@@ -175,7 +174,8 @@ spec:
- /bin/bash
- -ec
- |
- timeout {{ $readinessTimeout }} airflow jobs check --job-type SchedulerJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ export CONNECTION_CHECK_MAX_COUNT=0
+ timeout {{ $readinessTimeout }} airflow jobs check --job-type SchedulerJob --local --limit 0 {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
{{- end }}
{{- if .Values.scheduler.customStartupProbe }}
startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.scheduler.customStartupProbe "context" $) | nindent 12 }}
@@ -188,7 +188,7 @@ spec:
- -ec
- |
export CONNECTION_CHECK_MAX_COUNT=0
- timeout {{ $startupTimeout }} airflow jobs check --job-type SchedulerJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ timeout {{ $startupTimeout }} airflow jobs check --job-type SchedulerJob --local --limit 0 {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
{{- end }}
{{- end }}
{{- if .Values.scheduler.lifecycleHooks }}
@@ -221,6 +221,11 @@ spec:
- name: empty-dir
mountPath: /opt/bitnami/airflow/config/airflow_local_settings.py
subPath: app-conf-dir/airflow_local_settings.py
+ {{- if and .Values.web.containerSecurityContext.enabled .Values.web.containerSecurityContext.readOnlyRootFilesystem }}
+ - name: empty-dir
+ mountPath: /opt/bitnami/airflow/venv/tmp
+ subPath: app-pyc-cache-dir
+ {{- end }}
{{- if .Values.usePasswordFiles }}
- name: airflow-secrets
mountPath: /opt/bitnami/airflow/secrets
diff --git a/bitnami/airflow/templates/setup-db-job.yaml b/bitnami/airflow/templates/setup-db-job.yaml
index 04f4bd7ae993ef..e5c576bd98a379 100644
--- a/bitnami/airflow/templates/setup-db-job.yaml
+++ b/bitnami/airflow/templates/setup-db-job.yaml
@@ -70,12 +70,23 @@ spec:
if ! airflow_execute db check-migrations; then
info "Populating database"
+ {{- if (include "airflow.isImageMajorVersion2" .) }}
airflow_execute db init
+ {{- else }}
+ airflow_execute db migrate
+ {{- end }}
airflow_create_admin_user
+ info "Synchronizing internal metadata"
+ airflow_execute sync-perm
+ true
else
info "Upgrading database schema"
+ {{- if (include "airflow.isImageMajorVersion2" .) }}
airflow_execute db upgrade
+ {{- else }}
+ airflow_execute db migrate
+ {{- end }}
true
fi
{{- end }}
diff --git a/bitnami/airflow/templates/triggerer/statefulset.yaml b/bitnami/airflow/templates/triggerer/statefulset.yaml
index 37b6f2e3c91b95..b89a7300076c90 100644
--- a/bitnami/airflow/templates/triggerer/statefulset.yaml
+++ b/bitnami/airflow/templates/triggerer/statefulset.yaml
@@ -112,6 +112,8 @@ spec:
value: "triggerer"
- name: AIRFLOW_EXECUTOR
value: {{ .Values.executor }}
+ - name: PYTHONPYCACHEPREFIX
+ value: "/opt/bitnami/airflow/venv/tmp"
{{- if or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor") }}
- name: REDIS_HOST
value: {{ include "airflow.redis.host" . | quote }}
@@ -150,15 +152,12 @@ spec:
{{- if .Values.triggerer.customLivenessProbe }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.triggerer.customLivenessProbe "context" $) | trim | nindent 12 }}
{{- else if .Values.triggerer.livenessProbe.enabled }}
- {{- $livenessTimeout := sub (int .Values.triggerer.livenessProbe.timeoutSeconds) 1 }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.triggerer.livenessProbe "enabled") "context" $) | nindent 12 }}
exec:
command:
- - /bin/bash
- - -ec
- - |
- export CONNECTION_CHECK_MAX_COUNT=0
- timeout {{ $livenessTimeout }} airflow jobs check --job-type TriggererJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ - pgrep
+ - -f
+ - "airflow triggerer"
{{- end }}
{{- if .Values.triggerer.customReadinessProbe }}
readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.triggerer.customReadinessProbe "context" $) | trim | nindent 12 }}
@@ -170,7 +169,8 @@ spec:
- /bin/bash
- -ec
- |
- timeout {{ $readinessTimeout }} airflow jobs check --job-type TriggererJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ export CONNECTION_CHECK_MAX_COUNT=0
+ timeout {{ $readinessTimeout }} airflow jobs check --job-type TriggererJob --local --limit 0 {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
{{- end }}
{{- if .Values.triggerer.customStartupProbe }}
startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.triggerer.customStartupProbe "context" $) | nindent 12 }}
@@ -183,7 +183,7 @@ spec:
- -ec
- |
export CONNECTION_CHECK_MAX_COUNT=0
- timeout {{ $startupTimeout }} airflow jobs check --job-type TriggererJob --local {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
+ timeout {{ $startupTimeout }} airflow jobs check --job-type TriggererJob --local --limit 0 {{- if not .Values.diagnosticMode.enabled }} 2>/dev/null {{- end }}
{{- end }}
{{- end }}
{{- if .Values.triggerer.lifecycleHooks }}
@@ -213,6 +213,11 @@ spec:
- name: empty-dir
mountPath: /opt/bitnami/airflow/config/airflow_local_settings.py
subPath: app-conf-dir/airflow_local_settings.py
+ {{- if and .Values.web.containerSecurityContext.enabled .Values.web.containerSecurityContext.readOnlyRootFilesystem }}
+ - name: empty-dir
+ mountPath: /opt/bitnami/airflow/venv/tmp
+ subPath: app-pyc-cache-dir
+ {{- end }}
{{- if .Values.usePasswordFiles }}
- name: airflow-secrets
mountPath: /opt/bitnami/airflow/secrets
diff --git a/bitnami/airflow/templates/web/configmap.yaml b/bitnami/airflow/templates/web/configmap.yaml
index 682d7ea6f4c96e..530f0bbb1ff76f 100644
--- a/bitnami/airflow/templates/web/configmap.yaml
+++ b/bitnami/airflow/templates/web/configmap.yaml
@@ -42,7 +42,11 @@ data:
AUTH_LDAP_TLS_CACERTFILE = {{ printf "%s/%s" .Values.ldap.tls.certificatesMountPath .Values.ldap.tls.CAFilename | squote }}
{{- end }}
{{- else }}
+ {{- if (include "airflow.isImageMajorVersion2" .) }}
from airflow.www.fab_security.manager import AUTH_DB
+ {{- else }}
+ from flask_appbuilder.const import AUTH_DB
+ {{- end }}
AUTH_TYPE = AUTH_DB
{{- end }}
diff --git a/bitnami/airflow/templates/web/deployment.yaml b/bitnami/airflow/templates/web/deployment.yaml
index 4ef6da01d765e6..39e3cc41417a68 100644
--- a/bitnami/airflow/templates/web/deployment.yaml
+++ b/bitnami/airflow/templates/web/deployment.yaml
@@ -123,6 +123,12 @@ spec:
key: airflow-password
{{- end }}
{{- end }}
+ - name: PYTHONPYCACHEPREFIX
+ value: "/opt/bitnami/airflow/venv/tmp"
+ {{- if (include "airflow.isImageMajorVersion2" .) }}
+ - name: AIRFLOW_COMPONENT_TYPE
+ value: "webserver"
+ {{- end }}
{{- if .Values.extraEnvVars }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }}
{{- end }}
@@ -175,19 +181,13 @@ spec:
livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.web.customLivenessProbe "context" $) | nindent 12 }}
{{- else if .Values.web.livenessProbe.enabled }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.web.livenessProbe "enabled") "context" $) | nindent 12 }}
- exec:
- command:
- - pgrep
- - -f
- - airflow-webserver
- {{- end }}
- {{- if .Values.web.customReadinessProbe }}
- readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.web.customReadinessProbe "context" $) | nindent 12 }}
- {{- else if .Values.web.readinessProbe.enabled }}
- readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.web.readinessProbe "enabled") "context" $) | nindent 12 }}
{{- if contains "127.0.0.1" (include "airflow.baseUrl" .) }}
httpGet:
+ {{- if (include "airflow.isImageMajorVersion3" .) }}
+ path: /api/v2/monitor/health
+ {{- else }}
path: /health
+ {{- end }}
port: http
scheme: {{ ternary "HTTPS" "HTTP" .Values.web.tls.enabled }}
{{- else }}
@@ -195,6 +195,16 @@ spec:
port: http
{{- end }}
{{- end }}
+ {{- if .Values.web.customReadinessProbe }}
+ readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.web.customReadinessProbe "context" $) | nindent 12 }}
+ {{- else if .Values.web.readinessProbe.enabled }}
+ readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.web.readinessProbe "enabled") "context" $) | nindent 12 }}
+ exec:
+ command:
+ - pgrep
+ - -f
+ - airflow
+ {{- end }}
{{- end }}
{{- if .Values.web.lifecycleHooks }}
lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.web.lifecycleHooks "context" $) | nindent 12 }}
@@ -229,6 +239,11 @@ spec:
- name: empty-dir
mountPath: /opt/bitnami/airflow/webserver_config.py
subPath: app-base-dir/webserver_config.py
+ {{- if and .Values.web.containerSecurityContext.enabled .Values.web.containerSecurityContext.readOnlyRootFilesystem }}
+ - name: empty-dir
+ mountPath: /opt/bitnami/airflow/venv/tmp
+ subPath: app-pyc-cache-dir
+ {{- end }}
{{- if .Values.usePasswordFiles }}
- name: airflow-secrets
mountPath: /opt/bitnami/airflow/secrets
@@ -282,7 +297,7 @@ spec:
projected:
sources:
- secret:
- name: {{ include "airflow.secretName" . }}
+ name: {{ include "airflow.secretName" . }}
- secret:
name: {{ include "airflow.database.secretName" . }}
{{- if .Values.ldap.enabled }}
diff --git a/bitnami/airflow/templates/web/service.yaml b/bitnami/airflow/templates/web/service.yaml
index ff0a7b5bf490f2..04522299cdcbea 100644
--- a/bitnami/airflow/templates/web/service.yaml
+++ b/bitnami/airflow/templates/web/service.yaml
@@ -6,7 +6,7 @@ SPDX-License-Identifier: APACHE-2.0
apiVersion: v1
kind: Service
metadata:
- name: {{ include "common.names.fullname" . }}
+ name: {{ include "airflow.web.fullname" . }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }}
app.kubernetes.io/component: web
diff --git a/bitnami/airflow/templates/worker/statefulset.yaml b/bitnami/airflow/templates/worker/statefulset.yaml
index cbf3cdc51ab450..9d4669309fe04d 100644
--- a/bitnami/airflow/templates/worker/statefulset.yaml
+++ b/bitnami/airflow/templates/worker/statefulset.yaml
@@ -114,6 +114,8 @@ spec:
value: "worker"
- name: AIRFLOW_EXECUTOR
value: {{ include "airflow.worker.executor" . }}
+ - name: PYTHONPYCACHEPREFIX
+ value: "/opt/bitnami/airflow/venv/tmp"
{{- if or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor") }}
- name: REDIS_HOST
value: {{ include "airflow.redis.host" . | quote }}
@@ -172,6 +174,13 @@ spec:
livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.worker.customLivenessProbe "context" $) | nindent 12 }}
{{- else if .Values.worker.livenessProbe.enabled }}
livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.worker.livenessProbe "enabled") "context" $) | nindent 12 }}
+ tcpSocket:
+ port: worker
+ {{- end }}
+ {{- if .Values.worker.customReadinessProbe }}
+ readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.worker.customReadinessProbe "context" $) | nindent 12 }}
+ {{- else if .Values.worker.readinessProbe.enabled }}
+ readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.worker.readinessProbe "enabled") "context" $) | nindent 12 }}
exec:
command:
- sh
@@ -180,13 +189,6 @@ spec:
. /opt/bitnami/airflow/venv/bin/activate && \
CONNECTION_CHECK_MAX_COUNT=0 python -m celery --app airflow.providers.celery.executors.celery_executor.app inspect ping -d celery@$(hostname)
{{- end }}
- {{- if .Values.worker.customReadinessProbe }}
- readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.worker.customReadinessProbe "context" $) | nindent 12 }}
- {{- else if .Values.worker.readinessProbe.enabled }}
- readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.worker.readinessProbe "enabled") "context" $) | nindent 12 }}
- tcpSocket:
- port: worker
- {{- end }}
{{- end }}
{{- if .Values.worker.lifecycleHooks }}
lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.worker.lifecycleHooks "context" $) | nindent 12 }}
@@ -221,6 +223,11 @@ spec:
- name: empty-dir
mountPath: /opt/bitnami/airflow/webserver_config.py
subPath: app-base-dir/webserver_config.py
+ {{- if and .Values.web.containerSecurityContext.enabled .Values.web.containerSecurityContext.readOnlyRootFilesystem }}
+ - name: empty-dir
+ mountPath: /opt/bitnami/airflow/venv/tmp
+ subPath: app-pyc-cache-dir
+ {{- end }}
{{- if .Values.usePasswordFiles }}
- name: airflow-secrets
mountPath: /opt/bitnami/airflow/secrets
diff --git a/bitnami/airflow/values.yaml b/bitnami/airflow/values.yaml
index 6f97e0167a6bfd..5f59ee280c5a71 100644
--- a/bitnami/airflow/values.yaml
+++ b/bitnami/airflow/values.yaml
@@ -94,7 +94,7 @@ diagnosticMode:
image:
registry: docker.io
repository: bitnami/airflow
- tag: 2.10.5-debian-12-r11
+ tag: 3.0.0-debian-12-r2
digest: ""
## Specify a imagePullPolicy
## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
@@ -132,6 +132,10 @@ auth:
## ref: https://airflow.apache.org/docs/apache-airflow/stable/configurations-ref.html#secret-key
##
secretKey: ""
+ ## @param auth.jwtSecretKey JWT secret key to run your flask app
+ ## ref: https://airflow.apache.org/docs/apache-airflow/stable/configurations-ref.html#secret-key
+ ##
+ jwtSecretKey: ""
## @param auth.existingSecret Name of an existing secret to use for Airflow credentials
## `auth.password`, `auth.fernetKey`, and `auth.secretKey` will be ignored and picked up from this secret
## The secret must contain the keys `airflow-password`, `airflow-fernet-key` and `airflow-secret-key'
@@ -1218,7 +1222,7 @@ scheduler:
dagProcessor:
## @param dagProcessor.enabled Run Airflow Dag Processor Manager as a standalone component
##
- enabled: false
+ enabled: true
## @param dagProcessor.replicaCount Number of Airflow Dag Processor replicas
##
replicaCount: 1
@@ -1559,7 +1563,7 @@ dagProcessor:
triggerer:
## @param triggerer.enabled Run Airflow Triggerer as a standalone component
##
- enabled: false
+ enabled: true
## @param triggerer.defaultCapacity How many triggers a single Triggerer can run at once
##
defaultCapacity: 1000