Skip to content

Commit 6d0e2d6

Browse files
committed
Update auth.resolve_repository_name
More relaxed version that matches the constraints imposed by the current version of the docker daemon. Few unit tests to verify the new cases. Client.pull was trying to set the tag value when it wasn't supposed to, fixed now. utils.parse_repository_tag is simpler and supports @sha... notation Signed-off-by: Joffrey F <[email protected]>
1 parent 1ca2bc5 commit 6d0e2d6

File tree

4 files changed

+55
-41
lines changed

4 files changed

+55
-41
lines changed

docker/api/image.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ def pull(self, repository, tag=None, stream=False,
158158
if not tag:
159159
repository, tag = utils.parse_repository_tag(repository)
160160
registry, repo_name = auth.resolve_repository_name(repository)
161-
if repo_name.count(":") == 1:
162-
repository, tag = repository.rsplit(":", 1)
163161

164162
params = {
165163
'tag': tag,
@@ -174,7 +172,8 @@ def pull(self, repository, tag=None, stream=False,
174172
log.debug('Looking for auth config')
175173
if not self._auth_configs:
176174
log.debug(
177-
"No auth config in memory - loading from filesystem")
175+
"No auth config in memory - loading from filesystem"
176+
)
178177
self._auth_configs = auth.load_config()
179178
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
180179
# Do not fail here if no authentication exists for this

docker/auth/auth.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
import json
1717
import logging
1818
import os
19-
import warnings
2019

2120
import six
2221

23-
from .. import constants
2422
from .. import errors
2523

2624
INDEX_NAME = 'index.docker.io'
@@ -31,31 +29,29 @@
3129
log = logging.getLogger(__name__)
3230

3331

34-
def resolve_repository_name(repo_name, insecure=False):
35-
if insecure:
36-
warnings.warn(
37-
constants.INSECURE_REGISTRY_DEPRECATION_WARNING.format(
38-
'resolve_repository_name()'
39-
), DeprecationWarning
40-
)
41-
32+
def resolve_repository_name(repo_name):
4233
if '://' in repo_name:
4334
raise errors.InvalidRepository(
44-
'Repository name cannot contain a scheme ({0})'.format(repo_name))
45-
parts = repo_name.split('/', 1)
46-
if '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost':
47-
# This is a docker index repo (ex: foo/bar or ubuntu)
48-
return INDEX_NAME, repo_name
49-
if len(parts) < 2:
50-
raise errors.InvalidRepository(
51-
'Invalid repository name ({0})'.format(repo_name))
35+
'Repository name cannot contain a scheme ({0})'.format(repo_name)
36+
)
5237

53-
if 'index.docker.io' in parts[0]:
38+
index_name, remote_name = split_repo_name(repo_name)
39+
if index_name[0] == '-' or index_name[-1] == '-':
5440
raise errors.InvalidRepository(
55-
'Invalid repository name, try "{0}" instead'.format(parts[1])
41+
'Invalid index name ({0}). Cannot begin or end with a'
42+
' hyphen.'.format(index_name)
5643
)
44+
return index_name, remote_name
45+
5746

58-
return parts[0], parts[1]
47+
def split_repo_name(repo_name):
48+
parts = repo_name.split('/', 1)
49+
if len(parts) == 1 or (
50+
'.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'
51+
):
52+
# This is a docker index repo (ex: username/foobar or ubuntu)
53+
return INDEX_NAME, repo_name
54+
return tuple(parts)
5955

6056

6157
def resolve_authconfig(authconfig, registry=None):

docker/utils/utils.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,14 @@ def convert_volume_binds(binds):
283283
return result
284284

285285

286-
def parse_repository_tag(repo):
287-
column_index = repo.rfind(':')
288-
if column_index < 0:
289-
return repo, None
290-
tag = repo[column_index + 1:]
291-
slash_index = tag.find('/')
292-
if slash_index < 0:
293-
return repo[:column_index], tag
294-
295-
return repo, None
286+
def parse_repository_tag(repo_name):
287+
parts = repo_name.rsplit('@', 1)
288+
if len(parts) == 2:
289+
return tuple(parts)
290+
parts = repo_name.rsplit(':', 1)
291+
if len(parts) == 2 and '/' not in parts[1]:
292+
return tuple(parts)
293+
return repo_name, None
296294

297295

298296
# Based on utils.go:ParseHost http://tinyurl.com/nkahcfh

tests/unit/auth_test.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import tempfile
1010

1111
from docker import auth
12+
from docker import errors
1213

1314
from .. import base
1415

@@ -29,25 +30,31 @@ def test_803_urlsafe_encode(self):
2930
assert b'_' in encoded
3031

3132

32-
class ResolveAuthTest(base.BaseTestCase):
33-
auth_config = {
34-
'https://index.docker.io/v1/': {'auth': 'indexuser'},
35-
'my.registry.net': {'auth': 'privateuser'},
36-
'http://legacy.registry.url/v1/': {'auth': 'legacyauth'}
37-
}
38-
33+
class ResolveRepositoryNameTest(base.BaseTestCase):
3934
def test_resolve_repository_name_hub_library_image(self):
4035
self.assertEqual(
4136
auth.resolve_repository_name('image'),
4237
('index.docker.io', 'image'),
4338
)
4439

40+
def test_resolve_repository_name_dotted_hub_library_image(self):
41+
self.assertEqual(
42+
auth.resolve_repository_name('image.valid'),
43+
('index.docker.io', 'image.valid')
44+
)
45+
4546
def test_resolve_repository_name_hub_image(self):
4647
self.assertEqual(
4748
auth.resolve_repository_name('username/image'),
4849
('index.docker.io', 'username/image'),
4950
)
5051

52+
def test_explicit_hub_index_library_image(self):
53+
self.assertEqual(
54+
auth.resolve_repository_name('index.docker.io/image'),
55+
('index.docker.io', 'image')
56+
)
57+
5158
def test_resolve_repository_name_private_registry(self):
5259
self.assertEqual(
5360
auth.resolve_repository_name('my.registry.net/image'),
@@ -90,6 +97,20 @@ def test_resolve_repository_name_localhost_with_username(self):
9097
('localhost', 'username/image'),
9198
)
9299

100+
def test_invalid_index_name(self):
101+
self.assertRaises(
102+
errors.InvalidRepository,
103+
lambda: auth.resolve_repository_name('-gecko.com/image')
104+
)
105+
106+
107+
class ResolveAuthTest(base.BaseTestCase):
108+
auth_config = {
109+
'https://index.docker.io/v1/': {'auth': 'indexuser'},
110+
'my.registry.net': {'auth': 'privateuser'},
111+
'http://legacy.registry.url/v1/': {'auth': 'legacyauth'}
112+
}
113+
93114
def test_resolve_authconfig_hostname_only(self):
94115
self.assertEqual(
95116
auth.resolve_authconfig(self.auth_config, 'my.registry.net'),

0 commit comments

Comments
 (0)