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 e90d953e441 fix: pod_override existing init_containers (#62284)
e90d953e441 is described below

commit e90d953e4419ac8713f5b66432351897e6b48834
Author: Stanislav Chernov <[email protected]>
AuthorDate: Sun Feb 22 02:24:27 2026 +0300

    fix: pod_override existing init_containers (#62284)
    
    * fix: merge init containers by name in pod_override
    Previously, init containers were simply appended when using pod_override,
    leading to duplicates when the same container name existed in both base
    and client specs. Now init containers are properly reconciled by name,
    matching the behavior of regular containers - same-name containers are
    merged while others are appended.
    Fixes apache/airflow#61074
    
    * fix: preserve extend_object_field deepcopy for init_containers
    
    Keep the original extend_object_field call for init_containers to avoid
    mutating client_spec and producing empty lists instead of None. Only
    apply name-based reconciliation when both specs have init_containers.
---
 .../providers/cncf/kubernetes/pod_generator.py     | 47 ++++++++++++++++++++++
 .../unit/cncf/kubernetes/test_pod_generator.py     | 15 +++++++
 2 files changed, 62 insertions(+)

diff --git 
a/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/pod_generator.py
 
b/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/pod_generator.py
index 478a35045cc..7e5dc728d77 100644
--- 
a/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/pod_generator.py
+++ 
b/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/pod_generator.py
@@ -272,6 +272,10 @@ class PodGenerator:
                 base_spec.containers, client_spec.containers
             )
             merged_spec = extend_object_field(base_spec, client_spec, 
"init_containers")
+            if base_spec.init_containers and client_spec.init_containers:
+                merged_spec.init_containers = 
PodGenerator.reconcile_init_containers(
+                    base_spec.init_containers, client_spec.init_containers
+                )
             merged_spec = extend_object_field(base_spec, merged_spec, 
"volumes")
             return merge_objects(base_spec, merged_spec)
 
@@ -310,6 +314,49 @@ class PodGenerator:
             *PodGenerator.reconcile_containers(base_containers[1:], 
client_containers[1:]),
         ]
 
+    @staticmethod
+    def reconcile_init_containers(
+        base_containers: list[k8s.V1Container] | None,
+        client_containers: list[k8s.V1Container] | None,
+    ) -> list[k8s.V1Container]:
+        """
+        Merge Kubernetes init containers by name.
+
+        Containers with the same name are merged; others are appended.
+
+        :param base_containers: base init containers
+        :param client_containers: client init containers that override base
+        :return: the merged init containers
+        """
+        if not base_containers:
+            return client_containers or []
+        if not client_containers:
+            return base_containers
+
+        client_map = {c.name: c for c in client_containers}
+        merged = []
+        matched_names = set()
+
+        for base_container in base_containers:
+            if base_container.name in client_map:
+                client_container = client_map[base_container.name]
+                client_container = extend_object_field(base_container, 
client_container, "volume_mounts")
+                client_container = extend_object_field(base_container, 
client_container, "env")
+                client_container = extend_object_field(base_container, 
client_container, "env_from")
+                client_container = extend_object_field(base_container, 
client_container, "ports")
+                client_container = extend_object_field(base_container, 
client_container, "volume_devices")
+                client_container = merge_objects(base_container, 
client_container)
+                merged.append(client_container)
+                matched_names.add(base_container.name)
+            else:
+                merged.append(base_container)
+
+        for client_container in client_containers:
+            if client_container.name not in matched_names:
+                merged.append(client_container)
+
+        return merged
+
     @classmethod
     def construct_pod(
         cls,
diff --git 
a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_pod_generator.py 
b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_pod_generator.py
index dee72b483e5..db969eec3f7 100644
--- a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_pod_generator.py
+++ b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_pod_generator.py
@@ -668,6 +668,21 @@ class TestPodGenerator:
         res = PodGenerator.reconcile_specs(base_spec, client_spec)
         assert res.init_containers == base_spec.init_containers + 
client_spec.init_containers
 
+    def test_reconcile_specs_init_containers_same_name(self):
+        base_spec = k8s.V1PodSpec(
+            containers=[],
+            init_containers=[k8s.V1Container(name="init1", image="base_image", 
args=["base_arg"])],
+        )
+        client_spec = k8s.V1PodSpec(
+            containers=[],
+            init_containers=[k8s.V1Container(name="init1", 
image="client_image")],
+        )
+        res = PodGenerator.reconcile_specs(base_spec, client_spec)
+        assert len(res.init_containers) == 1
+        assert res.init_containers[0].name == "init1"
+        assert res.init_containers[0].image == "client_image"
+        assert res.init_containers[0].args == ["base_arg"]
+
     def test_deserialize_model_file(self, caplog, data_file):
         template_file = data_file("pods/template.yaml").as_posix()
         result = PodGenerator.deserialize_model_file(template_file)

Reply via email to