Repository: docker/docker-py

Issue:
Problem when using the DOCKER_HOST variable in combination with docker-compose and https://
Hi,

I'm trying to use docker & docker-compose with the DOCKER_HOST env-variable to control a remote docker-host.

at first I configured the variables on the docker client machine as follows:

    export DOCKER_CERT_PATH=/vagrant/docker
    export DOCKER_TLS_VERIFY=1
    export DOCKER_HOST=my-docker-vm.cloudapp.azure.com:2376

This lead to an error in docker-compose as discussed in this issue docker/compose#2634

Once I added the `https://` protocol prefix to the hostname the connection problem with docker-compose went away...

    export DOCKER_HOST=https://my-docker-vm.cloudapp.azure.com:2376

But with this format of the DOCKER_HOST variable now the docker CLI is complaining about the format...

    docker ps
    Invalid bind address format: https://my-docker-vm.cloudapp.azure.com:2376

I think this error is triggered here: https://github.com/docker/docker-py/blob/62d9964cc1881f6f3cd021594cd40fd80a8fc855/docker/utils/utils.py#L388

The code is not expecting to find two occurrences of double-dots `:` in the host variable, but for some reason it does.

PS: also the ambiguity of the two error messages in `utils.py` could be improved, since at L368 & at L388 both errors emit the same message, but for different reasons ;)

Thanks & Regards,
Wolfgang

Discussion:

Patch:
diff --git a/docker/client.py b/docker/client.py
index fb186cc7..7d1f7c46 100644
--- a/docker/client.py
+++ b/docker/client.py
@@ -45,17 +45,17 @@ class Client(
                  timeout=constants.DEFAULT_TIMEOUT_SECONDS, tls=False):
         super(Client, self).__init__()
 
-        if tls and (not base_url or not base_url.startswith('https://')):
+        if tls and not base_url:
             raise errors.TLSParameterError(
-                'If using TLS, the base_url argument must begin with '
-                '"https://".')
+                'If using TLS, the base_url argument must be provided.'
+            )
 
         self.base_url = base_url
         self.timeout = timeout
 
         self._auth_configs = auth.load_config()
 
-        base_url = utils.parse_host(base_url, sys.platform)
+        base_url = utils.parse_host(base_url, sys.platform, tls=bool(tls))
         if base_url.startswith('http+unix://'):
             self._custom_adapter = unixconn.UnixAdapter(base_url, timeout)
             self.mount('http+docker://', self._custom_adapter)
diff --git a/docker/utils/utils.py b/docker/utils/utils.py
index 1ce1867c..dc46f1ef 100644
--- a/docker/utils/utils.py
+++ b/docker/utils/utils.py
@@ -345,7 +345,7 @@ def parse_repository_tag(repo_name):
 # fd:// protocol unsupported (for obvious reasons)
 # Added support for http and https
 # Protocol translation: tcp -> http, unix -> http+unix
-def parse_host(addr, platform=None):
+def parse_host(addr, platform=None, tls=False):
     proto = "http+unix"
     host = DEFAULT_HTTP_HOST
     port = None
@@ -381,7 +381,7 @@ def parse_host(addr, platform=None):
             raise errors.DockerException(
                 "Invalid bind address protocol: {0}".format(addr)
             )
-        proto = "http"
+        proto = "https" if tls else "http"
 
     if proto != "http+unix" and ":" in addr:
         host_parts = addr.split(':')


Test patch:
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index 83d2a98d..63ea10e7 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -360,6 +360,11 @@ class ParseHostTest(base.BaseTestCase):
 
             assert parse_host(val, 'win32') == tcp_port
 
+    def test_parse_host_tls(self):
+        host_value = 'myhost.docker.net:3348'
+        expected_result = 'https://myhost.docker.net:3348'
+        self.assertEqual(parse_host(host_value, None, True), expected_result)
+
 
 class ParseRepositoryTagTest(base.BaseTestCase):
     sha = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'