mirror of https://github.com/docker/docker-py.git
Merge pull request #259 from dotcloud/166-complete-parse-host
Support same URL schemes as Docker
This commit is contained in:
commit
ed2b4581d7
|
@ -39,16 +39,9 @@ class Client(requests.Session):
|
||||||
def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
|
def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
|
||||||
timeout=DEFAULT_TIMEOUT_SECONDS):
|
timeout=DEFAULT_TIMEOUT_SECONDS):
|
||||||
super(Client, self).__init__()
|
super(Client, self).__init__()
|
||||||
if base_url is None:
|
base_url = utils.parse_host(base_url)
|
||||||
base_url = "http+unix://var/run/docker.sock"
|
if 'http+unix:///' in base_url:
|
||||||
if 'unix:///' in base_url:
|
|
||||||
base_url = base_url.replace('unix:/', 'unix:')
|
base_url = base_url.replace('unix:/', 'unix:')
|
||||||
if base_url.startswith('unix:'):
|
|
||||||
base_url = "http+" + base_url
|
|
||||||
if base_url.startswith('tcp:'):
|
|
||||||
base_url = base_url.replace('tcp:', 'http:')
|
|
||||||
if base_url.endswith('/'):
|
|
||||||
base_url = base_url[:-1]
|
|
||||||
self.base_url = base_url
|
self.base_url = base_url
|
||||||
self._version = version
|
self._version = version
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from .utils import (
|
from .utils import (
|
||||||
compare_version, convert_port_bindings, convert_volume_binds,
|
compare_version, convert_port_bindings, convert_volume_binds,
|
||||||
mkbuildcontext, ping, tar, parse_repository_tag
|
mkbuildcontext, ping, tar, parse_repository_tag, parse_host
|
||||||
) # flake8: noqa
|
) # flake8: noqa
|
||||||
|
|
|
@ -20,6 +20,11 @@ from distutils.version import StrictVersion
|
||||||
import requests
|
import requests
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from .. import errors
|
||||||
|
|
||||||
|
DEFAULT_HTTP_HOST = "127.0.0.1"
|
||||||
|
DEFAULT_UNIX_SOCKET = "http+unix://var/run/docker.sock"
|
||||||
|
|
||||||
|
|
||||||
def mkbuildcontext(dockerfile):
|
def mkbuildcontext(dockerfile):
|
||||||
f = tempfile.NamedTemporaryFile()
|
f = tempfile.NamedTemporaryFile()
|
||||||
|
@ -139,9 +144,71 @@ def parse_repository_tag(repo):
|
||||||
column_index = repo.rfind(':')
|
column_index = repo.rfind(':')
|
||||||
if column_index < 0:
|
if column_index < 0:
|
||||||
return repo, None
|
return repo, None
|
||||||
tag = repo[column_index+1:]
|
tag = repo[column_index + 1:]
|
||||||
slash_index = tag.find('/')
|
slash_index = tag.find('/')
|
||||||
if slash_index < 0:
|
if slash_index < 0:
|
||||||
return repo[:column_index], tag
|
return repo[:column_index], tag
|
||||||
|
|
||||||
return repo, None
|
return repo, None
|
||||||
|
|
||||||
|
|
||||||
|
# Based on utils.go:ParseHost http://tinyurl.com/nkahcfh
|
||||||
|
# fd:// protocol unsupported (for obvious reasons)
|
||||||
|
# Added support for http and https
|
||||||
|
# Protocol translation: tcp -> http, unix -> http+unix
|
||||||
|
def parse_host(addr):
|
||||||
|
proto = "http+unix"
|
||||||
|
host = DEFAULT_HTTP_HOST
|
||||||
|
port = None
|
||||||
|
if not addr or addr.strip() == 'unix://':
|
||||||
|
return DEFAULT_UNIX_SOCKET
|
||||||
|
|
||||||
|
addr = addr.strip()
|
||||||
|
if addr.startswith('http://'):
|
||||||
|
addr = addr.replace('http://', 'tcp://')
|
||||||
|
if addr.startswith('http+unix://'):
|
||||||
|
addr = addr.replace('http+unix://', 'unix://')
|
||||||
|
|
||||||
|
if addr == 'tcp://':
|
||||||
|
raise errors.DockerException("Invalid bind address format: %s" % addr)
|
||||||
|
elif addr.startswith('unix://'):
|
||||||
|
addr = addr[7:]
|
||||||
|
elif addr.startswith('tcp://'):
|
||||||
|
proto = "http"
|
||||||
|
addr = addr[6:]
|
||||||
|
elif addr.startswith('https://'):
|
||||||
|
proto = "https"
|
||||||
|
addr = addr[8:]
|
||||||
|
elif addr.startswith('fd://'):
|
||||||
|
raise errors.DockerException("fd protocol is not implemented")
|
||||||
|
else:
|
||||||
|
if "://" in addr:
|
||||||
|
raise errors.DockerException(
|
||||||
|
"Invalid bind address protocol: %s" % addr
|
||||||
|
)
|
||||||
|
proto = "http"
|
||||||
|
|
||||||
|
if proto != "http+unix" and ":" in addr:
|
||||||
|
host_parts = addr.split(':')
|
||||||
|
if len(host_parts) != 2:
|
||||||
|
raise errors.DockerException(
|
||||||
|
"Invalid bind address format: %s" % addr
|
||||||
|
)
|
||||||
|
if host_parts[0]:
|
||||||
|
host = host_parts[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
port = int(host_parts[1])
|
||||||
|
except Exception:
|
||||||
|
raise errors.DockerException(
|
||||||
|
"Invalid port: %s", addr
|
||||||
|
)
|
||||||
|
|
||||||
|
elif proto in ("http", "https") and ':' not in addr:
|
||||||
|
raise errors.DockerException("Bind address needs a port: %s" % addr)
|
||||||
|
else:
|
||||||
|
host = addr
|
||||||
|
|
||||||
|
if proto == "http+unix":
|
||||||
|
return "%s://%s" % (proto, host)
|
||||||
|
return "%s://%s:%d" % (proto, host, port)
|
||||||
|
|
|
@ -746,14 +746,14 @@ class DockerClientTest(unittest.TestCase):
|
||||||
assert c.base_url == "http+unix://socket"
|
assert c.base_url == "http+unix://socket"
|
||||||
|
|
||||||
def test_url_compatibility_http(self):
|
def test_url_compatibility_http(self):
|
||||||
c = docker.Client(base_url="http://hostname")
|
c = docker.Client(base_url="http://hostname:1234")
|
||||||
|
|
||||||
assert c.base_url == "http://hostname"
|
assert c.base_url == "http://hostname:1234"
|
||||||
|
|
||||||
def test_url_compatibility_tcp(self):
|
def test_url_compatibility_tcp(self):
|
||||||
c = docker.Client(base_url="tcp://hostname")
|
c = docker.Client(base_url="tcp://hostname:1234")
|
||||||
|
|
||||||
assert c.base_url == "http://hostname"
|
assert c.base_url == "http://hostname:1234"
|
||||||
|
|
||||||
def test_logs(self):
|
def test_logs(self):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from docker.utils import parse_repository_tag
|
from docker.errors import DockerException
|
||||||
|
from docker.utils import parse_repository_tag, parse_host
|
||||||
|
|
||||||
|
|
||||||
class UtilsTest(unittest.TestCase):
|
class UtilsTest(unittest.TestCase):
|
||||||
|
longMessage = True
|
||||||
|
|
||||||
def test_parse_repository_tag(self):
|
def test_parse_repository_tag(self):
|
||||||
self.assertEqual(parse_repository_tag("root"),
|
self.assertEqual(parse_repository_tag("root"),
|
||||||
|
@ -19,6 +21,37 @@ class UtilsTest(unittest.TestCase):
|
||||||
self.assertEqual(parse_repository_tag("url:5000/repo:tag"),
|
self.assertEqual(parse_repository_tag("url:5000/repo:tag"),
|
||||||
("url:5000/repo", "tag"))
|
("url:5000/repo", "tag"))
|
||||||
|
|
||||||
|
def test_parse_host(self):
|
||||||
|
invalid_hosts = [
|
||||||
|
'0.0.0.0',
|
||||||
|
'tcp://',
|
||||||
|
'udp://127.0.0.1',
|
||||||
|
'udp://127.0.0.1:2375',
|
||||||
|
]
|
||||||
|
|
||||||
|
valid_hosts = {
|
||||||
|
'0.0.0.1:5555': 'http://0.0.0.1:5555',
|
||||||
|
':6666': 'http://127.0.0.1:6666',
|
||||||
|
'tcp://:7777': 'http://127.0.0.1:7777',
|
||||||
|
'http://:7777': 'http://127.0.0.1:7777',
|
||||||
|
'https://kokia.jp:2375': 'https://kokia.jp:2375',
|
||||||
|
'': 'http+unix://var/run/docker.sock',
|
||||||
|
None: 'http+unix://var/run/docker.sock',
|
||||||
|
'unix:///var/run/docker.sock': 'http+unix:///var/run/docker.sock',
|
||||||
|
'unix://': 'http+unix://var/run/docker.sock'
|
||||||
|
}
|
||||||
|
|
||||||
|
for host in invalid_hosts:
|
||||||
|
try:
|
||||||
|
parsed = parse_host(host)
|
||||||
|
self.fail('Expected to fail but success: %s -> %s' % (
|
||||||
|
host, parsed
|
||||||
|
))
|
||||||
|
except DockerException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for host, expected in valid_hosts.items():
|
||||||
|
self.assertEqual(parse_host(host), expected, msg=host)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Reference in New Issue