Freeze the version of docker-py to 0.3.0 and create a fancy streaming json decoder to work around the lack of newlines in push statuses.

This commit is contained in:
jakedt 2014-03-28 17:53:33 -04:00
parent fd941ed3a4
commit 7c14190d2a
3 changed files with 44 additions and 14 deletions

View file

@ -21,7 +21,7 @@ xhtml2pdf
logstash_formatter logstash_formatter
redis redis
hiredis hiredis
git+https://github.com/dotcloud/docker-py.git docker-py
loremipsum loremipsum
pygithub pygithub
flask-restful flask-restful

View file

@ -16,7 +16,7 @@ beautifulsoup4==4.3.2
blinker==1.3 blinker==1.3
boto==2.27.0 boto==2.27.0
distribute==0.6.34 distribute==0.6.34
git+https://github.com/dotcloud/docker-py.git docker-py==0.3.0
ecdsa==0.11 ecdsa==0.11
gevent==1.0 gevent==1.0
greenlet==0.4.2 greenlet==0.4.2

View file

@ -49,12 +49,43 @@ class StatusWrapper(object):
build_logs.set_status(self._uuid, self._status) build_logs.set_status(self._uuid, self._status)
def unwrap_stream(json_stream): class _IncompleteJsonError(Exception):
for json_entry in json_stream: def __init__(self, start_from):
try: self.start_from = start_from
yield json.loads(json_entry).values()[0]
except ValueError:
logger.debug('Invalid json block: %s' % json_entry) class _StreamingJSONDecoder(json.JSONDecoder):
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
def decode(self, s, _w=WHITESPACE.match):
"""Return the Python representation of ``s`` (a ``str`` or ``unicode``
instance containing a JSON document)
"""
start_from = 0
while start_from < len(s):
try:
obj, end = self.raw_decode(s[start_from:], idx=_w(s[start_from:], 0).end())
except ValueError:
raise _IncompleteJsonError(start_from)
end = _w(s[start_from:], end).end()
start_from += end
yield obj
class StreamingDockerClient(Client):
def _stream_helper(self, response):
"""Generator for data coming from a chunked-encoded HTTP response."""
content_buf = ''
for content in response.iter_content(chunk_size=256):
content_buf += content
try:
for val in json.loads(content_buf, cls=_StreamingJSONDecoder):
yield val
content_buf = ''
except _IncompleteJsonError as exc:
content_buf = content_buf[exc.start_from:]
class DockerfileBuildContext(object): class DockerfileBuildContext(object):
@ -65,12 +96,12 @@ class DockerfileBuildContext(object):
self._repo = repo self._repo = repo
self._tag_names = tag_names self._tag_names = tag_names
self._push_token = push_token self._push_token = push_token
self._cl = Client(timeout=1200) self._cl = StreamingDockerClient(timeout=1200)
self._status = StatusWrapper(build_uuid) self._status = StatusWrapper(build_uuid)
self._build_logger = partial(build_logs.append_log_message, build_uuid) self._build_logger = partial(build_logs.append_log_message, build_uuid)
dockerfile_path = os.path.join(self._build_dir, dockerfile_subdir, dockerfile_path = os.path.join(self._build_dir, dockerfile_subdir,
"Dockerfile") 'Dockerfile')
self._num_steps = DockerfileBuildContext.__count_steps(dockerfile_path) self._num_steps = DockerfileBuildContext.__count_steps(dockerfile_path)
logger.debug('Will build and push to repo %s with tags named: %s' % logger.debug('Will build and push to repo %s with tags named: %s' %
@ -117,7 +148,7 @@ class DockerfileBuildContext(object):
current_step = 0 current_step = 0
built_image = None built_image = None
for status in unwrap_stream(build_status): for status in build_status:
fully_unwrapped = "" fully_unwrapped = ""
if isinstance(status, dict): if isinstance(status, dict):
if len(status) > 0: if len(status) > 0:
@ -179,9 +210,8 @@ class DockerfileBuildContext(object):
logger.debug('Pushing to repo %s' % self._repo) logger.debug('Pushing to repo %s' % self._repo)
resp = self._cl.push(self._repo, stream=True) resp = self._cl.push(self._repo, stream=True)
for status_str in resp: for status in resp:
status = json.loads(status_str) logger.debug('Status: %s', status)
logger.debug('Status: %s', status_str)
if u'status' in status: if u'status' in status:
status_msg = status[u'status'] status_msg = status[u'status']