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
+ )