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
             )

Reply via email to