From c2d867b1178285061ba4fba7e099fcb200900c2b Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Wed, 4 Sep 2013 22:27:51 -0400 Subject: [PATCH 1/4] Implement attach_websocket() for attaching with WebSockets instead of HTTP streaming --- docker/client.py | 25 +++++++++++++++++-------- requirements.txt | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/docker/client.py b/docker/client.py index 9c0c0c4e..7a9c59b5 100644 --- a/docker/client.py +++ b/docker/client.py @@ -24,6 +24,8 @@ import auth import unixconn import utils +import websocket + class APIError(requests.exceptions.HTTPError): def __init__(self, message, response, explanation=None): @@ -139,23 +141,23 @@ class Client(requests.Session): return self.post(url, json.dumps(data2), **kwargs) def attach_socket(self, container, params=None): - if params is None: - params = { - 'stdout': 1, - 'stderr': 1, - 'stream': 1 - } if isinstance(container, dict): container = container.get('Id') - u = self._url("/containers/{0}/attach".format(container)) - res = self.post(u, None, params=params, stream=True) + res = self.post(u, None, params=self._attach_params(params), stream=True) self._raise_for_status(res) # hijack the underlying socket from requests, icky # but for some reason requests.iter_contents and ilk # eventually block return res.raw._fp.fp._sock + def attach_websocket(self, container, params=None): + url = self._url("/containers/{0}/attach/ws".format(container)) + req = requests.Request("POST", url, params=self._attach_params(params)) + full_url = req.prepare().url.replace("http://", "ws://", 1) + print full_url + return websocket.create_connection(full_url) + def attach(self, container): socket = self.attach_socket(container) @@ -166,6 +168,13 @@ class Client(requests.Session): else: break + def _attach_params(self, override=None): + return override or { + 'stdout': 1, + 'stderr': 1, + 'stream': 1 + } + def build(self, path=None, tag=None, quiet=False, fileobj=None, nocache=False): remote = context = headers = None if path is None and fileobj is None: diff --git a/requirements.txt b/requirements.txt index e5209b74..32cc7aa4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ requests==1.2.0 six==1.3.0 +websocket-client==0.11.0 From 6e659ba12a4944a7a8eacceb66aa281e003586cc Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Thu, 5 Sep 2013 22:46:24 -0400 Subject: [PATCH 2/4] Move creation of websocket connection to its own method, so subclasses can override --- docker/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docker/client.py b/docker/client.py index 7a9c59b5..28927dd4 100644 --- a/docker/client.py +++ b/docker/client.py @@ -155,8 +155,10 @@ class Client(requests.Session): url = self._url("/containers/{0}/attach/ws".format(container)) req = requests.Request("POST", url, params=self._attach_params(params)) full_url = req.prepare().url.replace("http://", "ws://", 1) - print full_url - return websocket.create_connection(full_url) + return self._create_websocket_connection(full_url) + + def _create_websocket_connection(self, url): + return websocket.create_connection(url) def attach(self, container): socket = self.attach_socket(container) From cf35b3843319f906ebb35b4478c62a63a70a9396 Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Fri, 13 Sep 2013 12:51:23 -0400 Subject: [PATCH 3/4] Support https:// URLs (replacing with wss://) when attaching websocket --- docker/client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/client.py b/docker/client.py index 28927dd4..78f7abcf 100644 --- a/docker/client.py +++ b/docker/client.py @@ -154,7 +154,9 @@ class Client(requests.Session): def attach_websocket(self, container, params=None): url = self._url("/containers/{0}/attach/ws".format(container)) req = requests.Request("POST", url, params=self._attach_params(params)) - full_url = req.prepare().url.replace("http://", "ws://", 1) + full_url = req.prepare().url + full_url = full_url.replace("http://", "ws://", 1) + full_url = full_url.replace("https://", "wss://", 1) return self._create_websocket_connection(full_url) def _create_websocket_connection(self, url): From bd938b5879734cc061676e677dcdb3c147ff125c Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Wed, 6 Nov 2013 17:21:41 +0000 Subject: [PATCH 4/4] Use websockets by passing 'ws' param to attach_socket --- docker/client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docker/client.py b/docker/client.py index 78f7abcf..d1a7f9ce 100644 --- a/docker/client.py +++ b/docker/client.py @@ -140,7 +140,10 @@ class Client(requests.Session): kwargs['headers']['Content-Type'] = 'application/json' return self.post(url, json.dumps(data2), **kwargs) - def attach_socket(self, container, params=None): + def attach_socket(self, container, params=None, ws=False): + if ws: + return self._attach_websocket(container, params) + if isinstance(container, dict): container = container.get('Id') u = self._url("/containers/{0}/attach".format(container)) @@ -151,7 +154,7 @@ class Client(requests.Session): # eventually block return res.raw._fp.fp._sock - def attach_websocket(self, container, params=None): + def _attach_websocket(self, container, params=None): url = self._url("/containers/{0}/attach/ws".format(container)) req = requests.Request("POST", url, params=self._attach_params(params)) full_url = req.prepare().url