This is an automated email from the ASF dual-hosted git repository.

taragolis 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 c92b8db0d4 Fix construct `docker.TLSConfig` for `docker>=7` (#37481)
c92b8db0d4 is described below

commit c92b8db0d40672e6dd7e8cf064193e4371fcb2e8
Author: Andrey Anshin <[email protected]>
AuthorDate: Wed Feb 21 16:53:26 2024 +0400

    Fix construct `docker.TLSConfig` for `docker>=7` (#37481)
---
 airflow/providers/docker/hooks/docker.py    | 47 +++++++++++++++++++++++------
 airflow/providers/docker/provider.yaml      |  2 +-
 generated/provider_dependencies.json        |  2 +-
 pyproject.toml                              |  2 +-
 tests/providers/docker/hooks/test_docker.py | 40 +++++++++++++++++++-----
 5 files changed, 74 insertions(+), 19 deletions(-)

diff --git a/airflow/providers/docker/hooks/docker.py 
b/airflow/providers/docker/hooks/docker.py
index 763c3a7877..18ccfd7689 100644
--- a/airflow/providers/docker/hooks/docker.py
+++ b/airflow/providers/docker/hooks/docker.py
@@ -18,6 +18,8 @@
 from __future__ import annotations
 
 import json
+import sys
+import warnings
 from functools import cached_property
 from typing import TYPE_CHECKING, Any
 
@@ -103,15 +105,42 @@ class DockerHook(BaseHook):
         :param ssl_version: Version of SSL to use when communicating with 
docker daemon.
         """
         if ca_cert and client_cert and client_key:
-            # Ignore type error on SSL version here.
-            # It is deprecated and type annotation is wrong, and it should be 
string.
-            return TLSConfig(
-                ca_cert=ca_cert,
-                client_cert=(client_cert, client_key),
-                verify=verify,
-                ssl_version=ssl_version,
-                assert_hostname=assert_hostname,
-            )
+            from packaging.version import Version
+
+            if sys.version_info >= (3, 9):
+                from importlib.metadata import version
+            else:
+                from importlib_metadata import version
+
+            tls_config = {
+                "ca_cert": ca_cert,
+                "client_cert": (client_cert, client_key),
+                "verify": verify,
+                "assert_hostname": assert_hostname,
+                "ssl_version": ssl_version,
+            }
+
+            docker_py_version = Version(version("docker"))
+            if docker_py_version.major >= 7:
+                # `ssl_version` and `assert_hostname` removed into the 
`docker>=7`
+                # see: https://github.com/docker/docker-py/pull/3185
+                if tls_config.pop("ssl_version", None) is not None:
+                    warnings.warn(
+                        f"`ssl_version` removed in `docker.TLSConfig` 
constructor arguments "
+                        f"since `docker>=7`, but you use {docker_py_version}. "
+                        f"This parameter does not have any affect.",
+                        UserWarning,
+                        stacklevel=2,
+                    )
+                if tls_config.pop("assert_hostname", None) is not None:
+                    warnings.warn(
+                        f"`assert_hostname` removed in `docker.TLSConfig` 
constructor arguments "
+                        f"since `docker>=7`, but you use {docker_py_version}. "
+                        f"This parameter does not have any affect.",
+                        UserWarning,
+                        stacklevel=2,
+                    )
+            return TLSConfig(**tls_config)
         return False
 
     @cached_property
diff --git a/airflow/providers/docker/provider.yaml 
b/airflow/providers/docker/provider.yaml
index 0139dc9526..cc23725233 100644
--- a/airflow/providers/docker/provider.yaml
+++ b/airflow/providers/docker/provider.yaml
@@ -64,7 +64,7 @@ versions:
 
 dependencies:
   - apache-airflow>=2.6.0
-  - docker>=5.0.3
+  - docker>=6
   - python-dotenv>=0.21.0
 
 integrations:
diff --git a/generated/provider_dependencies.json 
b/generated/provider_dependencies.json
index a89c2b918c..781fbdd334 100644
--- a/generated/provider_dependencies.json
+++ b/generated/provider_dependencies.json
@@ -428,7 +428,7 @@
   "docker": {
     "deps": [
       "apache-airflow>=2.6.0",
-      "docker>=5.0.3",
+      "docker>=6",
       "python-dotenv>=0.21.0"
     ],
     "devel-deps": [],
diff --git a/pyproject.toml b/pyproject.toml
index 35adec58b7..87705a7492 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -679,7 +679,7 @@ discord = [ # source: 
airflow/providers/discord/provider.yaml
   "apache-airflow[http]",
 ]
 docker = [ # source: airflow/providers/docker/provider.yaml
-  "docker>=5.0.3",
+  "docker>=6",
   "python-dotenv>=0.21.0",
 ]
 elasticsearch = [ # source: airflow/providers/elasticsearch/provider.yaml
diff --git a/tests/providers/docker/hooks/test_docker.py 
b/tests/providers/docker/hooks/test_docker.py
index d96c8af275..758ab7b808 100644
--- a/tests/providers/docker/hooks/test_docker.py
+++ b/tests/providers/docker/hooks/test_docker.py
@@ -19,15 +19,26 @@ from __future__ import annotations
 
 import logging
 import ssl
+import sys
+import warnings
 from unittest import mock
 
 import pytest
 from docker import TLSConfig
 from docker.errors import APIError
+from packaging.version import Version
 
 from airflow.exceptions import AirflowException, AirflowNotFoundException
 from airflow.providers.docker.hooks.docker import DockerHook
 
+if sys.version_info >= (3, 9):
+    from importlib.metadata import version
+else:
+    from importlib_metadata import version
+
+
+DOCKER_PY_7_PLUS = Version(Version(version("docker")).base_version) >= 
Version("7")
+
 TEST_CONN_ID = "docker_test_connection"
 TEST_BASE_URL = "unix://var/run/docker.sock"
 TEST_TLS_BASE_URL = "tcp://localhost.foo.bar"
@@ -251,8 +262,8 @@ def 
test_construct_tls_config_missing_certs_args(tls_params: dict):
 @pytest.mark.parametrize(
     "ssl_version",
     [
-        pytest.param(ssl.PROTOCOL_TLSv1, id="TLSv1"),
-        pytest.param(ssl.PROTOCOL_TLSv1_2, id="TLSv1_2"),
+        # Other version-based constraints in `ssl` module marked as deprecated 
since Python 3.6.
+        pytest.param(ssl.PROTOCOL_TLS_CLIENT, id="auto-negotiate"),
         None,
     ],
 )
@@ -265,8 +276,23 @@ def test_construct_tls_config(assert_hostname, 
ssl_version):
     if ssl_version is not None:
         tls_params["ssl_version"] = ssl_version
 
-    with mock.patch.object(TLSConfig, "__init__", return_value=None) as 
mock_tls_config:
-        DockerHook.construct_tls_config(**tls_params)
-        mock_tls_config.assert_called_once_with(
-            **expected_call_args, assert_hostname=assert_hostname, 
ssl_version=ssl_version
-        )
+    if DOCKER_PY_7_PLUS and (assert_hostname is not None or ssl_version is not 
None):
+        ctx = pytest.warns(UserWarning, match="removed in `docker\.TLSConfig` 
constructor arguments")
+        no_warns = False
+    else:
+        ctx = warnings.catch_warnings()
+        no_warns = True
+
+    # Please note that spec should be set; otherwise we could miss removal 
into the constructor arguments.
+    with mock.patch.object(TLSConfig, "__init__", return_value=None, 
spec=TLSConfig) as mock_tls_config:
+        with ctx:
+            if no_warns:
+                warnings.simplefilter("error")
+            DockerHook.construct_tls_config(**tls_params)
+
+        if DOCKER_PY_7_PLUS:
+            mock_tls_config.assert_called_once_with(**expected_call_args)
+        else:
+            mock_tls_config.assert_called_once_with(
+                **expected_call_args, assert_hostname=assert_hostname, 
ssl_version=ssl_version
+            )

Reply via email to