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)