File moto-pr3444-fix-docker.patch of Package python-moto

From 204fdabcc9d84b5efdaecae3fcc86c5bc893c38a Mon Sep 17 00:00:00 2001
From: Bert Blommers <info@bertblommers.nl>
Date: Sun, 8 Nov 2020 13:49:27 +0000
Subject: [PATCH 1/5] #3359 - Downgrade Docker-version to not break mock_lambda
 without Docker running

---
 setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index bcbc88a20..1eb781dbc 100755
--- a/setup.py
+++ b/setup.py
@@ -78,7 +78,7 @@ def get_version():
 _dep_PyYAML = "PyYAML>=5.1"
 _dep_python_jose = "python-jose[cryptography]>=3.1.0,<4.0.0"
 _dep_python_jose_ecdsa_pin = "ecdsa<0.15"  # https://github.com/spulec/moto/pull/3263#discussion_r477404984
-_dep_docker = "docker>=2.5.1"
+_dep_docker = "docker>=2.5.1,<=4.3.0"  # https://github.com/spulec/moto/issues/3359
 _dep_jsondiff = "jsondiff>=1.1.2"
 _dep_aws_xray_sdk = "aws-xray-sdk!=0.96,>=0.93"
 _dep_idna = "idna<3,>=2.5"

From c0700aa704356e314ac06d08542fcedf24af34ab Mon Sep 17 00:00:00 2001
From: Bert Blommers <info@bertblommers.nl>
Date: Sun, 8 Nov 2020 14:16:02 +0000
Subject: [PATCH 2/5] Revert "#3359 - Downgrade Docker-version to not break
 mock_lambda without Docker running"

This reverts commit 204fdabcc9d84b5efdaecae3fcc86c5bc893c38a.
---
 setup.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index 1eb781dbc..bcbc88a20 100755
--- a/setup.py
+++ b/setup.py
@@ -78,7 +78,7 @@ def get_version():
 _dep_PyYAML = "PyYAML>=5.1"
 _dep_python_jose = "python-jose[cryptography]>=3.1.0,<4.0.0"
 _dep_python_jose_ecdsa_pin = "ecdsa<0.15"  # https://github.com/spulec/moto/pull/3263#discussion_r477404984
-_dep_docker = "docker>=2.5.1,<=4.3.0"  # https://github.com/spulec/moto/issues/3359
+_dep_docker = "docker>=2.5.1"
 _dep_jsondiff = "jsondiff>=1.1.2"
 _dep_aws_xray_sdk = "aws-xray-sdk!=0.96,>=0.93"
 _dep_idna = "idna<3,>=2.5"

From 390a4d55102f49cade830bf422ebf36e3be7dacb Mon Sep 17 00:00:00 2001
From: Bert Blommers <info@bertblommers.nl>
Date: Sun, 8 Nov 2020 14:18:49 +0000
Subject: [PATCH 3/5] #3359 - Only initiate Docker when invoking Lambdas

---
 moto/awslambda/models.py | 38 +++++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py
index ce9c78fc6..12f98ec0c 100644
--- a/moto/awslambda/models.py
+++ b/moto/awslambda/models.py
@@ -162,25 +162,11 @@ def __init__(self, spec, region, validate_s3=True, version=1):
         self.run_time = spec["Runtime"]
         self.logs_backend = logs_backends[self.region]
         self.environment_vars = spec.get("Environment", {}).get("Variables", {})
-        self.docker_client = docker.from_env()
+        self.docker_client = None
         self.policy = None
         self.state = "Active"
         self.reserved_concurrency = spec.get("ReservedConcurrentExecutions", None)
 
-        # Unfortunately mocking replaces this method w/o fallback enabled, so we
-        # need to replace it if we detect it's been mocked
-        if requests.adapters.HTTPAdapter.send != _orig_adapter_send:
-            _orig_get_adapter = self.docker_client.api.get_adapter
-
-            def replace_adapter_send(*args, **kwargs):
-                adapter = _orig_get_adapter(*args, **kwargs)
-
-                if isinstance(adapter, requests.adapters.HTTPAdapter):
-                    adapter.send = functools.partial(_orig_adapter_send, adapter)
-                return adapter
-
-            self.docker_client.api.get_adapter = replace_adapter_send
-
         # optional
         self.description = spec.get("Description", "")
         self.memory_size = spec.get("MemorySize", 128)
@@ -242,6 +228,26 @@ def replace_adapter_send(*args, **kwargs):
 
         self.tags = dict()
 
+    def initiate_docker_client(self):
+        # We should only initiate the Docker Client at runtime.
+        # The docker.from_env() call will fall if Docker is not running
+        if self.docker_client is None:
+            self.docker_client = docker.from_env()
+
+            # Unfortunately mocking replaces this method w/o fallback enabled, so we
+            # need to replace it if we detect it's been mocked
+            if requests.adapters.HTTPAdapter.send != _orig_adapter_send:
+                _orig_get_adapter = self.docker_client.api.get_adapter
+
+                def replace_adapter_send(*args, **kwargs):
+                    adapter = _orig_get_adapter(*args, **kwargs)
+
+                    if isinstance(adapter, requests.adapters.HTTPAdapter):
+                        adapter.send = functools.partial(_orig_adapter_send, adapter)
+                    return adapter
+
+                self.docker_client.api.get_adapter = replace_adapter_send
+
     def set_version(self, version):
         self.function_arn = make_function_ver_arn(
             self.region, ACCOUNT_ID, self.function_name, version
@@ -412,6 +418,8 @@ def _invoke_lambda(self, code, event=None, context=None):
 
             env_vars.update(self.environment_vars)
 
+            self.initiate_docker_client()
+
             container = exit_code = None
             log_config = docker.types.LogConfig(type=docker.types.LogConfig.types.JSON)
             with _DockerDataVolumeContext(self) as data_vol:

From 8d3cc3ef326ac4d82b79a5e20276bc9215c85fd7 Mon Sep 17 00:00:00 2001
From: Bert Blommers <info@bertblommers.nl>
Date: Sun, 8 Nov 2020 15:16:53 +0000
Subject: [PATCH 4/5] #3359 - Reuse Docker-on-request for AWSLambda and Batch

---
 moto/awslambda/models.py | 31 ++++---------------------------
 moto/batch/models.py     | 22 +++-------------------
 moto/utilities/docker.py | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 46 deletions(-)
 create mode 100644 moto/utilities/docker.py

diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py
index 12f98ec0c..c5f29fd68 100644
--- a/moto/awslambda/models.py
+++ b/moto/awslambda/models.py
@@ -17,13 +17,12 @@
 import re
 import zipfile
 import uuid
-import functools
 import tarfile
 import calendar
 import threading
 import traceback
 import weakref
-import requests.adapters
+import requests.exceptions
 
 from boto3 import Session
 
@@ -47,6 +46,7 @@
 from moto.dynamodb2 import dynamodb_backends2
 from moto.dynamodbstreams import dynamodbstreams_backends
 from moto.core import ACCOUNT_ID
+from moto.utilities.docker import DockerModel
 
 logger = logging.getLogger(__name__)
 
@@ -55,7 +55,6 @@
 except ImportError:
     from backports.tempfile import TemporaryDirectory
 
-_orig_adapter_send = requests.adapters.HTTPAdapter.send
 docker_3 = docker.__version__[0] >= "3"
 
 
@@ -151,8 +150,9 @@ def __exit__(self, exc_type, exc_val, exc_tb):
                     raise  # multiple processes trying to use same volume?
 
 
-class LambdaFunction(CloudFormationModel):
+class LambdaFunction(CloudFormationModel, DockerModel):
     def __init__(self, spec, region, validate_s3=True, version=1):
+        DockerModel.__init__(self)
         # required
         self.region = region
         self.code = spec["Code"]
@@ -162,7 +162,6 @@ def __init__(self, spec, region, validate_s3=True, version=1):
         self.run_time = spec["Runtime"]
         self.logs_backend = logs_backends[self.region]
         self.environment_vars = spec.get("Environment", {}).get("Variables", {})
-        self.docker_client = None
         self.policy = None
         self.state = "Active"
         self.reserved_concurrency = spec.get("ReservedConcurrentExecutions", None)
@@ -228,26 +227,6 @@ def __init__(self, spec, region, validate_s3=True, version=1):
 
         self.tags = dict()
 
-    def initiate_docker_client(self):
-        # We should only initiate the Docker Client at runtime.
-        # The docker.from_env() call will fall if Docker is not running
-        if self.docker_client is None:
-            self.docker_client = docker.from_env()
-
-            # Unfortunately mocking replaces this method w/o fallback enabled, so we
-            # need to replace it if we detect it's been mocked
-            if requests.adapters.HTTPAdapter.send != _orig_adapter_send:
-                _orig_get_adapter = self.docker_client.api.get_adapter
-
-                def replace_adapter_send(*args, **kwargs):
-                    adapter = _orig_get_adapter(*args, **kwargs)
-
-                    if isinstance(adapter, requests.adapters.HTTPAdapter):
-                        adapter.send = functools.partial(_orig_adapter_send, adapter)
-                    return adapter
-
-                self.docker_client.api.get_adapter = replace_adapter_send
-
     def set_version(self, version):
         self.function_arn = make_function_ver_arn(
             self.region, ACCOUNT_ID, self.function_name, version
@@ -418,8 +397,6 @@ def _invoke_lambda(self, code, event=None, context=None):
 
             env_vars.update(self.environment_vars)
 
-            self.initiate_docker_client()
-
             container = exit_code = None
             log_config = docker.types.LogConfig(type=docker.types.LogConfig.types.JSON)
             with _DockerDataVolumeContext(self) as data_vol:
diff --git a/moto/batch/models.py b/moto/batch/models.py
index c4bc81a73..6a2d889bc 100644
--- a/moto/batch/models.py
+++ b/moto/batch/models.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals
 import re
-import requests.adapters
 from itertools import cycle
 import six
 import datetime
@@ -8,7 +7,6 @@
 import uuid
 import logging
 import docker
-import functools
 import threading
 import dateutil.parser
 from boto3 import Session
@@ -30,8 +28,8 @@
 from moto.ec2.models import INSTANCE_TYPES as EC2_INSTANCE_TYPES
 from moto.iam.exceptions import IAMNotFoundException
 from moto.core import ACCOUNT_ID as DEFAULT_ACCOUNT_ID
+from moto.utilities.docker import DockerModel
 
-_orig_adapter_send = requests.adapters.HTTPAdapter.send
 logger = logging.getLogger(__name__)
 COMPUTE_ENVIRONMENT_NAME_REGEX = re.compile(
     r"^[A-Za-z0-9][A-Za-z0-9_-]{1,126}[A-Za-z0-9]$"
@@ -311,7 +309,7 @@ def create_from_cloudformation_json(
         return backend.get_job_definition_by_arn(arn)
 
 
-class Job(threading.Thread, BaseModel):
+class Job(threading.Thread, BaseModel, DockerModel):
     def __init__(self, name, job_def, job_queue, log_backend, container_overrides):
         """
         Docker Job
@@ -324,6 +322,7 @@ def __init__(self, name, job_def, job_queue, log_backend, container_overrides):
         :type log_backend: moto.logs.models.LogsBackend
         """
         threading.Thread.__init__(self)
+        DockerModel.__init__(self)
 
         self.job_name = name
         self.job_id = str(uuid.uuid4())
@@ -342,24 +341,9 @@ def __init__(self, name, job_def, job_queue, log_backend, container_overrides):
         self.daemon = True
         self.name = "MOTO-BATCH-" + self.job_id
 
-        self.docker_client = docker.from_env()
         self._log_backend = log_backend
         self.log_stream_name = None
 
-        # Unfortunately mocking replaces this method w/o fallback enabled, so we
-        # need to replace it if we detect it's been mocked
-        if requests.adapters.HTTPAdapter.send != _orig_adapter_send:
-            _orig_get_adapter = self.docker_client.api.get_adapter
-
-            def replace_adapter_send(*args, **kwargs):
-                adapter = _orig_get_adapter(*args, **kwargs)
-
-                if isinstance(adapter, requests.adapters.HTTPAdapter):
-                    adapter.send = functools.partial(_orig_adapter_send, adapter)
-                return adapter
-
-            self.docker_client.api.get_adapter = replace_adapter_send
-
     def describe(self):
         result = {
             "jobDefinition": self.job_definition.arn,
diff --git a/moto/utilities/docker.py b/moto/utilities/docker.py
new file mode 100644
index 000000000..576a9df1d
--- /dev/null
+++ b/moto/utilities/docker.py
@@ -0,0 +1,33 @@
+import docker
+import functools
+import requests.adapters
+
+
+_orig_adapter_send = requests.adapters.HTTPAdapter.send
+
+
+class DockerModel:
+    def __init__(self):
+        self.__docker_client = None
+
+    @property
+    def docker_client(self):
+        if self.__docker_client is None:
+            # We should only initiate the Docker Client at runtime.
+            # The docker.from_env() call will fall if Docker is not running
+            self.__docker_client = docker.from_env()
+
+            # Unfortunately mocking replaces this method w/o fallback enabled, so we
+            # need to replace it if we detect it's been mocked
+            if requests.adapters.HTTPAdapter.send != _orig_adapter_send:
+                _orig_get_adapter = self.docker_client.api.get_adapter
+
+                def replace_adapter_send(*args, **kwargs):
+                    adapter = _orig_get_adapter(*args, **kwargs)
+
+                    if isinstance(adapter, requests.adapters.HTTPAdapter):
+                        adapter.send = functools.partial(_orig_adapter_send, adapter)
+                    return adapter
+
+                self.docker_client.api.get_adapter = replace_adapter_send
+        return self.__docker_client

From b5b1c45d68446d242be58b02089e1120bb9f6a51 Mon Sep 17 00:00:00 2001
From: Bert Blommers <info@bertblommers.nl>
Date: Mon, 9 Nov 2020 16:31:18 +0000
Subject: [PATCH 5/5] Rename DockerUtilities to differentiate from
 docker-dependency

---
 moto/awslambda/models.py                          | 2 +-
 moto/batch/models.py                              | 2 +-
 moto/utilities/{docker.py => docker_utilities.py} | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename moto/utilities/{docker.py => docker_utilities.py} (100%)

diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py
index c5f29fd68..a26fcba40 100644
--- a/moto/awslambda/models.py
+++ b/moto/awslambda/models.py
@@ -46,7 +46,7 @@
 from moto.dynamodb2 import dynamodb_backends2
 from moto.dynamodbstreams import dynamodbstreams_backends
 from moto.core import ACCOUNT_ID
-from moto.utilities.docker import DockerModel
+from moto.utilities.docker_utilities import DockerModel
 
 logger = logging.getLogger(__name__)
 
diff --git a/moto/batch/models.py b/moto/batch/models.py
index 6a2d889bc..f729144d8 100644
--- a/moto/batch/models.py
+++ b/moto/batch/models.py
@@ -28,7 +28,7 @@
 from moto.ec2.models import INSTANCE_TYPES as EC2_INSTANCE_TYPES
 from moto.iam.exceptions import IAMNotFoundException
 from moto.core import ACCOUNT_ID as DEFAULT_ACCOUNT_ID
-from moto.utilities.docker import DockerModel
+from moto.utilities.docker_utilities import DockerModel
 
 logger = logging.getLogger(__name__)
 COMPUTE_ENVIRONMENT_NAME_REGEX = re.compile(
diff --git a/moto/utilities/docker.py b/moto/utilities/docker_utilities.py
similarity index 100%
rename from moto/utilities/docker.py
rename to moto/utilities/docker_utilities.py
openSUSE Build Service is sponsored by