Skip to content

Commit 29219a2

Browse files
committed
Don't break when volume binds contain unicode characters
Also includes a few unit tests for utils.convert_volume_binds Signed-off-by: Joffrey F <[email protected]>
1 parent 5e331a5 commit 29219a2

File tree

2 files changed

+104
-6
lines changed

2 files changed

+104
-6
lines changed

docker/utils/utils.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,25 +242,36 @@ def convert_volume_binds(binds):
242242

243243
result = []
244244
for k, v in binds.items():
245+
if isinstance(k, six.binary_type):
246+
k = k.decode('utf-8')
247+
245248
if isinstance(v, dict):
246249
if 'ro' in v and 'mode' in v:
247250
raise ValueError(
248251
'Binding cannot contain both "ro" and "mode": {}'
249252
.format(repr(v))
250253
)
251254

255+
bind = v['bind']
256+
if isinstance(bind, six.binary_type):
257+
bind = bind.decode('utf-8')
258+
252259
if 'ro' in v:
253260
mode = 'ro' if v['ro'] else 'rw'
254261
elif 'mode' in v:
255262
mode = v['mode']
256263
else:
257264
mode = 'rw'
258265

259-
result.append('{0}:{1}:{2}'.format(
260-
k, v['bind'], mode
261-
))
266+
result.append(
267+
six.text_type('{0}:{1}:{2}').format(k, bind, mode)
268+
)
262269
else:
263-
result.append('{0}:{1}:rw'.format(k, v))
270+
if isinstance(v, six.binary_type):
271+
v = v.decode('utf-8')
272+
result.append(
273+
six.text_type('{0}:{1}:rw').format(k, v)
274+
)
264275
return result
265276

266277

tests/utils_test.py

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
1+
# -*- coding: utf-8 -*-
2+
13
import os
24
import os.path
35
import shutil
46
import tempfile
57

8+
import pytest
9+
import six
10+
611
from docker.client import Client
712
from docker.constants import DEFAULT_DOCKER_API_VERSION
813
from docker.errors import DockerException
914
from docker.utils import (
1015
parse_repository_tag, parse_host, convert_filters, kwargs_from_env,
1116
create_host_config, Ulimit, LogConfig, parse_bytes, parse_env_file,
12-
exclude_paths,
17+
exclude_paths, convert_volume_binds,
1318
)
1419
from docker.utils.ports import build_port_bindings, split_port
1520
from docker.auth import resolve_repository_name, resolve_authconfig
1621

1722
from . import base
1823
from .helpers import make_tree
1924

20-
import pytest
2125

2226
TEST_CERT_DIR = os.path.join(
2327
os.path.dirname(__file__),
@@ -192,6 +196,89 @@ def generate_tempfile(self, file_content=None):
192196
local_tempfile.close()
193197
return local_tempfile.name
194198

199+
def test_convert_volume_binds_empty(self):
200+
self.assertEqual(convert_volume_binds({}), [])
201+
self.assertEqual(convert_volume_binds([]), [])
202+
203+
def test_convert_volume_binds_list(self):
204+
data = ['/a:/a:ro', '/b:/c:z']
205+
self.assertEqual(convert_volume_binds(data), data)
206+
207+
def test_convert_volume_binds_complete(self):
208+
data = {
209+
'/mnt/vol1': {
210+
'bind': '/data',
211+
'mode': 'ro'
212+
}
213+
}
214+
self.assertEqual(convert_volume_binds(data), ['/mnt/vol1:/data:ro'])
215+
216+
def test_convert_volume_binds_compact(self):
217+
data = {
218+
'/mnt/vol1': '/data'
219+
}
220+
self.assertEqual(convert_volume_binds(data), ['/mnt/vol1:/data:rw'])
221+
222+
def test_convert_volume_binds_no_mode(self):
223+
data = {
224+
'/mnt/vol1': {
225+
'bind': '/data'
226+
}
227+
}
228+
self.assertEqual(convert_volume_binds(data), ['/mnt/vol1:/data:rw'])
229+
230+
def test_convert_volume_binds_unicode_bytes_input(self):
231+
if six.PY2:
232+
expected = [unicode('/mnt/지연:/unicode/박:rw', 'utf-8')]
233+
234+
data = {
235+
'/mnt/지연': {
236+
'bind': '/unicode/박',
237+
'mode': 'rw'
238+
}
239+
}
240+
self.assertEqual(
241+
convert_volume_binds(data), expected
242+
)
243+
else:
244+
expected = ['/mnt/지연:/unicode/박:rw']
245+
246+
data = {
247+
bytes('/mnt/지연', 'utf-8'): {
248+
'bind': bytes('/unicode/박', 'utf-8'),
249+
'mode': 'rw'
250+
}
251+
}
252+
self.assertEqual(
253+
convert_volume_binds(data), expected
254+
)
255+
256+
def test_convert_volume_binds_unicode_unicode_input(self):
257+
if six.PY2:
258+
expected = [unicode('/mnt/지연:/unicode/박:rw', 'utf-8')]
259+
260+
data = {
261+
unicode('/mnt/지연', 'utf-8'): {
262+
'bind': unicode('/unicode/박', 'utf-8'),
263+
'mode': 'rw'
264+
}
265+
}
266+
self.assertEqual(
267+
convert_volume_binds(data), expected
268+
)
269+
else:
270+
expected = ['/mnt/지연:/unicode/박:rw']
271+
272+
data = {
273+
'/mnt/지연': {
274+
'bind': '/unicode/박',
275+
'mode': 'rw'
276+
}
277+
}
278+
self.assertEqual(
279+
convert_volume_binds(data), expected
280+
)
281+
195282
def test_parse_repository_tag(self):
196283
self.assertEqual(parse_repository_tag("root"),
197284
("root", None))

0 commit comments

Comments
 (0)