This is an automated email from the ASF dual-hosted git repository.
Miretpl 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 81b487227dc Use airflowHome for logs mount in wait-for-migrations init
container (#75060)
81b487227dc is described below
commit 81b487227dc69a6dacf192217809fa80e062cd36
Author: W. H. Wang <[email protected]>
AuthorDate: Sat Nov 7 03:14:59 2026 +0800
Use airflowHome for logs mount in wait-for-migrations init container
(#75060)
The wait-for-airflow-migrations init container in the scheduler,
triggerer and worker pods mounted the logs volume at a hard-coded
/opt/airflow/logs, while the main containers mount it under
airflowHome. With a custom airflowHome the init container ended up
with its logs on a different path than the rest of the pod, which
breaks setups such as readOnlyRootFilesystem where the logs directory
must be a writable volume in every container that runs Airflow.
closes: #56015
Co-authored-by: Przemysław Mirowski
<[email protected]>
---
.../templates/scheduler/scheduler-deployment.yaml | 2 +-
.../templates/triggerer/triggerer-deployment.yaml | 2 +-
chart/templates/workers/worker-deployment.yaml | 2 +-
.../helm_tests/airflow_core/test_scheduler.py | 27 ++++++++++++++-----
.../helm_tests/airflow_core/test_triggerer.py | 31 +++++++++++++++++-----
chart/tests/helm_tests/airflow_core/test_worker.py | 31 +++++++++++++++++-----
6 files changed, 72 insertions(+), 23 deletions(-)
diff --git a/chart/templates/scheduler/scheduler-deployment.yaml
b/chart/templates/scheduler/scheduler-deployment.yaml
index ad58ac1ec35..22c48c40bf8 100644
--- a/chart/templates/scheduler/scheduler-deployment.yaml
+++ b/chart/templates/scheduler/scheduler-deployment.yaml
@@ -153,7 +153,7 @@ spec:
{{- end }}
volumeMounts:
- name: logs
- mountPath: "/opt/airflow/logs"
+ mountPath: {{ template "airflow_logs" . }}
{{- if .Values.logs.persistence.subPath }}
subPath: {{ .Values.logs.persistence.subPath }}
{{- end }}
diff --git a/chart/templates/triggerer/triggerer-deployment.yaml
b/chart/templates/triggerer/triggerer-deployment.yaml
index 05bd9d2b43b..2f66a880c29 100644
--- a/chart/templates/triggerer/triggerer-deployment.yaml
+++ b/chart/templates/triggerer/triggerer-deployment.yaml
@@ -144,7 +144,7 @@ spec:
{{- end }}
volumeMounts:
- name: logs
- mountPath: "/opt/airflow/logs"
+ mountPath: {{ template "airflow_logs" . }}
{{- if .Values.logs.persistence.subPath }}
subPath: {{ .Values.logs.persistence.subPath }}
{{- end }}
diff --git a/chart/templates/workers/worker-deployment.yaml
b/chart/templates/workers/worker-deployment.yaml
index 8f0d2eee5db..86c5bef18fd 100644
--- a/chart/templates/workers/worker-deployment.yaml
+++ b/chart/templates/workers/worker-deployment.yaml
@@ -247,7 +247,7 @@ spec:
{{- end }}
volumeMounts:
- name: logs
- mountPath: "/opt/airflow/logs"
+ mountPath: {{ template "airflow_logs" . }}
{{- if .Values.logs.persistence.subPath }}
subPath: {{ .Values.logs.persistence.subPath }}
{{- end }}
diff --git a/chart/tests/helm_tests/airflow_core/test_scheduler.py
b/chart/tests/helm_tests/airflow_core/test_scheduler.py
index 30ba62e6212..c039eb50d92 100644
--- a/chart/tests/helm_tests/airflow_core/test_scheduler.py
+++ b/chart/tests/helm_tests/airflow_core/test_scheduler.py
@@ -113,11 +113,21 @@ class TestScheduler:
({"persistence": {"enabled": True, "subPath": "test/logs"}},
"test/logs"),
],
)
- def test_logs_mount_on_wait_for_migrations_initcontainer(self,
logs_values, expect_sub_path):
+ @pytest.mark.parametrize(
+ ("airflow_home", "expected_logs_mount_path"),
+ [
+ (None, "/opt/airflow/logs"),
+ ("/usr/local/airflow", "/usr/local/airflow/logs"),
+ ],
+ )
+ def test_logs_mount_on_wait_for_migrations_initcontainer(
+ self, logs_values, expect_sub_path, airflow_home,
expected_logs_mount_path
+ ):
+ values = {"logs": logs_values}
+ if airflow_home is not None:
+ values["airflowHome"] = airflow_home
docs = render_chart(
- values={
- "logs": logs_values,
- },
+ values=values,
show_only=["templates/scheduler/scheduler-deployment.yaml"],
)
@@ -128,11 +138,16 @@ class TestScheduler:
assert mounts is not None, (
"wait-for-airflow-migrations initContainer not found or has no
volumeMounts"
)
- assert any(m.get("name") == "logs" and m.get("mountPath") ==
"/opt/airflow/logs" for m in mounts)
+ main_container_logs_mount_path = jmespath.search(
+ "spec.template.spec.containers[?name=='scheduler'] |
[0].volumeMounts[?name=='logs'] | [0].mountPath",
+ docs[0],
+ )
+ assert main_container_logs_mount_path == expected_logs_mount_path
+ assert any(m.get("name") == "logs" and m.get("mountPath") ==
expected_logs_mount_path for m in mounts)
if expect_sub_path is not None:
assert any(
m.get("name") == "logs"
- and m.get("mountPath") == "/opt/airflow/logs"
+ and m.get("mountPath") == expected_logs_mount_path
and m.get("subPath") == expect_sub_path
for m in mounts
)
diff --git a/chart/tests/helm_tests/airflow_core/test_triggerer.py
b/chart/tests/helm_tests/airflow_core/test_triggerer.py
index 85643149de8..6b4d5286c02 100644
--- a/chart/tests/helm_tests/airflow_core/test_triggerer.py
+++ b/chart/tests/helm_tests/airflow_core/test_triggerer.py
@@ -108,12 +108,24 @@ class TestTriggerer:
({"persistence": {"enabled": True, "subPath": "test/logs"}},
"test/logs"),
],
)
- def test_logs_mount_on_wait_for_migrations_initcontainer(self,
logs_values, expect_sub_path):
+ @pytest.mark.parametrize(
+ ("airflow_home", "expected_logs_mount_path"),
+ [
+ (None, "/opt/airflow/logs"),
+ ("/usr/local/airflow", "/usr/local/airflow/logs"),
+ ],
+ )
+ def test_logs_mount_on_wait_for_migrations_initcontainer(
+ self, logs_values, expect_sub_path, airflow_home,
expected_logs_mount_path
+ ):
+ values = {
+ "logs": logs_values,
+ "triggerer": {"enabled": True},
+ }
+ if airflow_home is not None:
+ values["airflowHome"] = airflow_home
docs = render_chart(
- values={
- "logs": logs_values,
- "triggerer": {"enabled": True},
- },
+ values=values,
show_only=["templates/triggerer/triggerer-deployment.yaml"],
)
@@ -124,11 +136,16 @@ class TestTriggerer:
assert mounts is not None, (
"wait-for-airflow-migrations initContainer not found or has no
volumeMounts"
)
- assert any(m.get("name") == "logs" and m.get("mountPath") ==
"/opt/airflow/logs" for m in mounts)
+ main_container_logs_mount_path = jmespath.search(
+ "spec.template.spec.containers[?name=='triggerer'] |
[0].volumeMounts[?name=='logs'] | [0].mountPath",
+ docs[0],
+ )
+ assert main_container_logs_mount_path == expected_logs_mount_path
+ assert any(m.get("name") == "logs" and m.get("mountPath") ==
expected_logs_mount_path for m in mounts)
if expect_sub_path is not None:
assert any(
m.get("name") == "logs"
- and m.get("mountPath") == "/opt/airflow/logs"
+ and m.get("mountPath") == expected_logs_mount_path
and m.get("subPath") == expect_sub_path
for m in mounts
)
diff --git a/chart/tests/helm_tests/airflow_core/test_worker.py
b/chart/tests/helm_tests/airflow_core/test_worker.py
index 79d195a6a1a..c069bc4cdf2 100644
--- a/chart/tests/helm_tests/airflow_core/test_worker.py
+++ b/chart/tests/helm_tests/airflow_core/test_worker.py
@@ -167,12 +167,24 @@ class TestWorker:
({"persistence": {"enabled": True, "subPath": "test/logs"}},
"test/logs"),
],
)
- def test_logs_mount_on_wait_for_migrations_initcontainer(self,
logs_values, expect_sub_path):
+ @pytest.mark.parametrize(
+ ("airflow_home", "expected_logs_mount_path"),
+ [
+ (None, "/opt/airflow/logs"),
+ ("/usr/local/airflow", "/usr/local/airflow/logs"),
+ ],
+ )
+ def test_logs_mount_on_wait_for_migrations_initcontainer(
+ self, logs_values, expect_sub_path, airflow_home,
expected_logs_mount_path
+ ):
+ values = {
+ "executor": "CeleryExecutor",
+ "logs": logs_values,
+ }
+ if airflow_home is not None:
+ values["airflowHome"] = airflow_home
docs = render_chart(
- values={
- "executor": "CeleryExecutor",
- "logs": logs_values,
- },
+ values=values,
show_only=["templates/workers/worker-deployment.yaml"],
)
@@ -183,11 +195,16 @@ class TestWorker:
assert mounts is not None, (
"wait-for-airflow-migrations initContainer not found or has no
volumeMounts"
)
- assert any(m.get("name") == "logs" and m.get("mountPath") ==
"/opt/airflow/logs" for m in mounts)
+ main_container_logs_mount_path = jmespath.search(
+ "spec.template.spec.containers[?name=='worker'] |
[0].volumeMounts[?name=='logs'] | [0].mountPath",
+ docs[0],
+ )
+ assert main_container_logs_mount_path == expected_logs_mount_path
+ assert any(m.get("name") == "logs" and m.get("mountPath") ==
expected_logs_mount_path for m in mounts)
if expect_sub_path is not None:
assert any(
m.get("name") == "logs"
- and m.get("mountPath") == "/opt/airflow/logs"
+ and m.get("mountPath") == expected_logs_mount_path
and m.get("subPath") == expect_sub_path
for m in mounts
)