This is an automated email from the ASF dual-hosted git repository.
potiuk 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 118da9db7ef Fix XCom sidecar helper mutating the caller's pod volumes
(#72522)
118da9db7ef is described below
commit 118da9db7efa1bb19434014553b539bf5bd0348d
Author: Henry Chen <[email protected]>
AuthorDate: Wed Sep 9 07:23:26 2026 +0800
Fix XCom sidecar helper mutating the caller's pod volumes (#72522)
add_xcom_sidecar deep-copies the input pod so callers keep an untouched
object, but it then pointed the copy's volumes back at the original pod's
list before inserting the xcom volume. Any caller reusing the same pod
object accumulated one extra "xcom" volume per call, which the Kubernetes
API rejects as a duplicate. KubernetesPodOperator was only shielded
because reconcile_pods happens to deep-copy first.
The default V1Volume and V1VolumeMount were also inserted as the shared
module-level instances, so editing them on one pod silently changed every
other pod built by the helper and the defaults themselves.
---
.../providers/cncf/kubernetes/utils/xcom_sidecar.py | 6 +++---
.../unit/cncf/kubernetes/utils/test_xcom_sidecar.py | 17 +++++++++++++++++
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git
a/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/xcom_sidecar.py
b/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/xcom_sidecar.py
index 5bf26975b32..5b6f34d8bd9 100644
---
a/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/xcom_sidecar.py
+++
b/providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/xcom_sidecar.py
@@ -62,10 +62,10 @@ def add_xcom_sidecar(
) -> k8s.V1Pod:
"""Add sidecar."""
pod_cp = copy.deepcopy(pod)
- pod_cp.spec.volumes = pod.spec.volumes or []
- pod_cp.spec.volumes.insert(0, PodDefaults.VOLUME)
+ pod_cp.spec.volumes = pod_cp.spec.volumes or []
+ pod_cp.spec.volumes.insert(0, copy.deepcopy(PodDefaults.VOLUME))
pod_cp.spec.containers[0].volume_mounts =
pod_cp.spec.containers[0].volume_mounts or []
- pod_cp.spec.containers[0].volume_mounts.insert(0, PodDefaults.VOLUME_MOUNT)
+ pod_cp.spec.containers[0].volume_mounts.insert(0,
copy.deepcopy(PodDefaults.VOLUME_MOUNT))
sidecar = copy.deepcopy(PodDefaults.SIDECAR_CONTAINER)
sidecar.image = sidecar_container_image or
PodDefaults.SIDECAR_CONTAINER.image
if sidecar_container_resources:
diff --git
a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_xcom_sidecar.py
b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_xcom_sidecar.py
index 7fc9e9b4796..34b04673923 100644
---
a/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_xcom_sidecar.py
+++
b/providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_xcom_sidecar.py
@@ -69,3 +69,20 @@ def test_add_xcom_sidecar_empty_security_context():
def test_add_xcom_sidecar_does_not_mutate_shared_default():
add_xcom_sidecar(_base_pod(),
sidecar_container_security_context={"readOnlyRootFilesystem": True})
assert PodDefaults.SIDECAR_CONTAINER.security_context is None
+
+
+def test_add_xcom_sidecar_does_not_mutate_input_pod_volumes():
+ pod = _base_pod()
+ pod.spec.volumes = [k8s.V1Volume(name="data",
empty_dir=k8s.V1EmptyDirVolumeSource())]
+
+ result = add_xcom_sidecar(pod)
+
+ assert [v.name for v in pod.spec.volumes] == ["data"]
+ assert [v.name for v in result.spec.volumes] == ["xcom", "data"]
+
+
+def test_add_xcom_sidecar_copies_default_volume_and_mount():
+ result = add_xcom_sidecar(_base_pod())
+
+ assert result.spec.volumes[0] is not PodDefaults.VOLUME
+ assert result.spec.containers[0].volume_mounts[0] is not
PodDefaults.VOLUME_MOUNT