From cb22cdc238dc6e9667bfb8ad8488fbc4312b26f5 Mon Sep 17 00:00:00 2001 From: shaealh Date: Tue, 14 Jul 2026 20:45:57 -0700 Subject: [PATCH 1/2] Decouple Docker provider service naming from Airflow core The Docker provider should not require a core utility import for generating ephemeral service names as provider/client separation progresses in #62063. --- .../providers/docker/operators/docker_swarm.py | 11 +++++++++-- .../tests/unit/docker/operators/test_docker_swarm.py | 6 +++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/providers/docker/src/airflow/providers/docker/operators/docker_swarm.py b/providers/docker/src/airflow/providers/docker/operators/docker_swarm.py index 3eb5db64c55a5..539cb1c2f7ad1 100644 --- a/providers/docker/src/airflow/providers/docker/operators/docker_swarm.py +++ b/providers/docker/src/airflow/providers/docker/operators/docker_swarm.py @@ -18,8 +18,10 @@ from __future__ import annotations +import random import re import shlex +import string from datetime import datetime from time import sleep from typing import TYPE_CHECKING, Literal @@ -29,12 +31,17 @@ from airflow.providers.common.compat.sdk import AirflowException from airflow.providers.docker.operators.docker import DockerOperator -from airflow.utils.strings import get_random_string if TYPE_CHECKING: from airflow.providers.common.compat.sdk import Context +def _generate_service_name(prefix: str) -> str: + """Generate a unique Docker Swarm service name.""" + suffix = "".join(random.choices(string.ascii_letters + string.digits, k=8)) + return f"{prefix}-{suffix}" + + class DockerSwarmOperator(DockerOperator): """ Execute a command as an ephemeral docker swarm service. @@ -191,7 +198,7 @@ def _run_service(self) -> None: placement=self.placement, log_driver=self.log_driver_config, ), - name=f"{self.service_prefix}-{get_random_string()}", + name=_generate_service_name(self.service_prefix), labels={"name": f"airflow__{self.dag_id}__{self.task_id}"}, mode=self.mode, ) diff --git a/providers/docker/tests/unit/docker/operators/test_docker_swarm.py b/providers/docker/tests/unit/docker/operators/test_docker_swarm.py index 65e83d45ddd27..ad050e7c04ea0 100644 --- a/providers/docker/tests/unit/docker/operators/test_docker_swarm.py +++ b/providers/docker/tests/unit/docker/operators/test_docker_swarm.py @@ -19,6 +19,7 @@ import contextlib import logging +import re from unittest import mock import pytest @@ -27,10 +28,13 @@ from docker.errors import APIError from airflow.providers.common.compat.sdk import AirflowException -from airflow.providers.docker.operators.docker_swarm import DockerSwarmOperator +from airflow.providers.docker.operators.docker_swarm import DockerSwarmOperator, _generate_service_name class TestDockerSwarmOperator: + def test_generate_service_name(self): + assert re.fullmatch(r"custom-prefix-[A-Za-z0-9]{8}", _generate_service_name("custom-prefix")) + @mock.patch("airflow.providers.docker.operators.docker_swarm.types") def test_execute(self, types_mock, docker_api_client_patcher, caplog): mock_obj = mock.Mock() From 48afc69c8cc52cec35b8ae2f93244f9bc91670f9 Mon Sep 17 00:00:00 2001 From: shaealh Date: Thu, 16 Jul 2026 21:09:54 -0700 Subject: [PATCH 2/2] Remove redundant Docker Swarm service name test The test only asserted the helper's output shape and did not add meaningful behavioral coverage. --- .../docker/tests/unit/docker/operators/test_docker_swarm.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/providers/docker/tests/unit/docker/operators/test_docker_swarm.py b/providers/docker/tests/unit/docker/operators/test_docker_swarm.py index ad050e7c04ea0..65e83d45ddd27 100644 --- a/providers/docker/tests/unit/docker/operators/test_docker_swarm.py +++ b/providers/docker/tests/unit/docker/operators/test_docker_swarm.py @@ -19,7 +19,6 @@ import contextlib import logging -import re from unittest import mock import pytest @@ -28,13 +27,10 @@ from docker.errors import APIError from airflow.providers.common.compat.sdk import AirflowException -from airflow.providers.docker.operators.docker_swarm import DockerSwarmOperator, _generate_service_name +from airflow.providers.docker.operators.docker_swarm import DockerSwarmOperator class TestDockerSwarmOperator: - def test_generate_service_name(self): - assert re.fullmatch(r"custom-prefix-[A-Za-z0-9]{8}", _generate_service_name("custom-prefix")) - @mock.patch("airflow.providers.docker.operators.docker_swarm.types") def test_execute(self, types_mock, docker_api_client_patcher, caplog): mock_obj = mock.Mock()