Stop pinging registries from the client

The daemon already pings the registry, so doing it on our end is
redundant and error-prone.

The `insecure_registry` argument to `push()`, `pull()` and `login()` has
been deprecated - in the latter case, it wasn't being used anyway.

The `insecure` argument to `docker.auth.resolve_repository_name()` has
also been deprecated.

`docker.utils.ping_registry()` has been deprecated.

`docker.auth.expand_registry_url()` has been removed.

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
This commit is contained in:
Aanand Prasad 2015-07-20 09:36:35 +01:00
parent 946eb964ad
commit 33e1a58b60
7 changed files with 138 additions and 28 deletions

View File

@ -1,4 +1,5 @@
from .auth import ( from .auth import (
INDEX_NAME,
INDEX_URL, INDEX_URL,
encode_header, encode_header,
load_config, load_config,

View File

@ -16,38 +16,33 @@ import base64
import fileinput import fileinput
import json import json
import os import os
import warnings
import six import six
from ..utils import utils
from .. import errors from .. import errors
INDEX_URL = 'https://index.docker.io/v1/' INDEX_NAME = 'index.docker.io'
INDEX_URL = 'https://{0}/v1/'.format(INDEX_NAME)
DOCKER_CONFIG_FILENAME = os.path.join('.docker', 'config.json') DOCKER_CONFIG_FILENAME = os.path.join('.docker', 'config.json')
LEGACY_DOCKER_CONFIG_FILENAME = '.dockercfg' LEGACY_DOCKER_CONFIG_FILENAME = '.dockercfg'
def expand_registry_url(hostname, insecure=False): def resolve_repository_name(repo_name, insecure=False):
if hostname.startswith('http:') or hostname.startswith('https:'): if insecure:
return hostname warnings.warn(
if utils.ping_registry('https://' + hostname): 'The `insecure` argument to resolve_repository_name() '
return 'https://' + hostname 'is deprecated and non-functional. Please remove it.',
elif insecure: DeprecationWarning
return 'http://' + hostname
else:
raise errors.DockerException(
"HTTPS endpoint unresponsive and insecure mode isn't enabled."
) )
def resolve_repository_name(repo_name, insecure=False):
if '://' in repo_name: if '://' in repo_name:
raise errors.InvalidRepository( raise errors.InvalidRepository(
'Repository name cannot contain a scheme ({0})'.format(repo_name)) 'Repository name cannot contain a scheme ({0})'.format(repo_name))
parts = repo_name.split('/', 1) parts = repo_name.split('/', 1)
if '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost': if '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost':
# This is a docker index repo (ex: foo/bar or ubuntu) # This is a docker index repo (ex: foo/bar or ubuntu)
return INDEX_URL, repo_name return INDEX_NAME, repo_name
if len(parts) < 2: if len(parts) < 2:
raise errors.InvalidRepository( raise errors.InvalidRepository(
'Invalid repository name ({0})'.format(repo_name)) 'Invalid repository name ({0})'.format(repo_name))
@ -57,7 +52,7 @@ def resolve_repository_name(repo_name, insecure=False):
'Invalid repository name, try "{0}" instead'.format(parts[1]) 'Invalid repository name, try "{0}" instead'.format(parts[1])
) )
return expand_registry_url(parts[0], insecure), parts[1] return parts[0], parts[1]
def resolve_authconfig(authconfig, registry=None): def resolve_authconfig(authconfig, registry=None):
@ -68,7 +63,7 @@ def resolve_authconfig(authconfig, registry=None):
Returns None if no match was found. Returns None if no match was found.
""" """
# Default to the public index server # Default to the public index server
registry = convert_to_hostname(registry) if registry else INDEX_URL registry = convert_to_hostname(registry) if registry else INDEX_NAME
if registry in authconfig: if registry in authconfig:
return authconfig[registry] return authconfig[registry]
@ -185,7 +180,7 @@ def load_config(config_path=None):
'Invalid or empty configuration file!') 'Invalid or empty configuration file!')
username, password = decode_auth(data[0]) username, password = decode_auth(data[0])
conf[INDEX_URL] = { conf[INDEX_NAME] = {
'username': username, 'username': username,
'password': password, 'password': password,
'email': data[1], 'email': data[1],

View File

@ -25,6 +25,7 @@ from . import constants
from . import errors from . import errors
from .auth import auth from .auth import auth
from .utils import utils, check_resource from .utils import utils, check_resource
from .constants import INSECURE_REGISTRY_DEPRECATION_WARNING
class Client(clientbase.ClientBase): class Client(clientbase.ClientBase):
@ -499,6 +500,12 @@ class Client(clientbase.ClientBase):
def login(self, username, password=None, email=None, registry=None, def login(self, username, password=None, email=None, registry=None,
reauth=False, insecure_registry=False, dockercfg_path=None): reauth=False, insecure_registry=False, dockercfg_path=None):
if insecure_registry:
warnings.warn(
INSECURE_REGISTRY_DEPRECATION_WARNING.format('login()'),
DeprecationWarning
)
# If we don't have any auth data so far, try reloading the config file # If we don't have any auth data so far, try reloading the config file
# one more time in case anything showed up in there. # one more time in case anything showed up in there.
# If dockercfg_path is passed check to see if the config file exists, # If dockercfg_path is passed check to see if the config file exists,
@ -584,11 +591,15 @@ class Client(clientbase.ClientBase):
def pull(self, repository, tag=None, stream=False, def pull(self, repository, tag=None, stream=False,
insecure_registry=False, auth_config=None): insecure_registry=False, auth_config=None):
if insecure_registry:
warnings.warn(
INSECURE_REGISTRY_DEPRECATION_WARNING.format('pull()'),
DeprecationWarning
)
if not tag: if not tag:
repository, tag = utils.parse_repository_tag(repository) repository, tag = utils.parse_repository_tag(repository)
registry, repo_name = auth.resolve_repository_name( registry, repo_name = auth.resolve_repository_name(repository)
repository, insecure=insecure_registry
)
if repo_name.count(":") == 1: if repo_name.count(":") == 1:
repository, tag = repository.rsplit(":", 1) repository, tag = repository.rsplit(":", 1)
@ -631,11 +642,15 @@ class Client(clientbase.ClientBase):
def push(self, repository, tag=None, stream=False, def push(self, repository, tag=None, stream=False,
insecure_registry=False): insecure_registry=False):
if insecure_registry:
warnings.warn(
INSECURE_REGISTRY_DEPRECATION_WARNING.format('push()'),
DeprecationWarning
)
if not tag: if not tag:
repository, tag = utils.parse_repository_tag(repository) repository, tag = utils.parse_repository_tag(repository)
registry, repo_name = auth.resolve_repository_name( registry, repo_name = auth.resolve_repository_name(repository)
repository, insecure=insecure_registry
)
u = self._url("/images/{0}/push".format(repository)) u = self._url("/images/{0}/push".format(repository))
params = { params = {
'tag': tag 'tag': tag

View File

@ -4,3 +4,7 @@ STREAM_HEADER_SIZE_BYTES = 8
CONTAINER_LIMITS_KEYS = [ CONTAINER_LIMITS_KEYS = [
'memory', 'memswap', 'cpushares', 'cpusetcpus' 'memory', 'memswap', 'cpushares', 'cpusetcpus'
] ]
INSECURE_REGISTRY_DEPRECATION_WARNING = \
'The `insecure_registry` argument to {} ' \
'is deprecated and non-functional. Please remove it.'

View File

@ -19,6 +19,7 @@ import json
import shlex import shlex
import tarfile import tarfile
import tempfile import tempfile
import warnings
from distutils.version import StrictVersion from distutils.version import StrictVersion
from fnmatch import fnmatch from fnmatch import fnmatch
from datetime import datetime from datetime import datetime
@ -120,6 +121,11 @@ def compare_version(v1, v2):
def ping_registry(url): def ping_registry(url):
warnings.warn(
'The `ping_registry` method is deprecated and will be removed.',
DeprecationWarning
)
return ping(url + '/v2/', [401]) or ping(url + '/v1/_ping') return ping(url + '/v2/', [401]) or ping(url + '/v1/_ping')

View File

@ -2424,9 +2424,9 @@ class DockerClientTest(Cleanup, base.BaseTestCase):
f.write('auth = {0}\n'.format(auth_)) f.write('auth = {0}\n'.format(auth_))
f.write('email = sakuya@scarlet.net') f.write('email = sakuya@scarlet.net')
cfg = docker.auth.load_config(dockercfg_path) cfg = docker.auth.load_config(dockercfg_path)
self.assertTrue(docker.auth.INDEX_URL in cfg) self.assertTrue(docker.auth.INDEX_NAME in cfg)
self.assertNotEqual(cfg[docker.auth.INDEX_URL], None) self.assertNotEqual(cfg[docker.auth.INDEX_NAME], None)
cfg = cfg[docker.auth.INDEX_URL] cfg = cfg[docker.auth.INDEX_NAME]
self.assertEqual(cfg['username'], 'sakuya') self.assertEqual(cfg['username'], 'sakuya')
self.assertEqual(cfg['password'], 'izayoi') self.assertEqual(cfg['password'], 'izayoi')
self.assertEqual(cfg['email'], 'sakuya@scarlet.net') self.assertEqual(cfg['email'], 'sakuya@scarlet.net')

View File

@ -9,7 +9,7 @@ from docker.utils import (
create_host_config, Ulimit, LogConfig, parse_bytes create_host_config, Ulimit, LogConfig, parse_bytes
) )
from docker.utils.ports import build_port_bindings, split_port from docker.utils.ports import build_port_bindings, split_port
from docker.auth import resolve_authconfig from docker.auth import resolve_repository_name, resolve_authconfig
import base import base
@ -167,6 +167,61 @@ class UtilsTest(base.BaseTestCase):
type=LogConfig.types.JSON, config='helloworld' type=LogConfig.types.JSON, config='helloworld'
)) ))
def test_resolve_repository_name(self):
# docker hub library image
self.assertEqual(
resolve_repository_name('image'),
('index.docker.io', 'image'),
)
# docker hub image
self.assertEqual(
resolve_repository_name('username/image'),
('index.docker.io', 'username/image'),
)
# private registry
self.assertEqual(
resolve_repository_name('my.registry.net/image'),
('my.registry.net', 'image'),
)
# private registry with port
self.assertEqual(
resolve_repository_name('my.registry.net:5000/image'),
('my.registry.net:5000', 'image'),
)
# private registry with username
self.assertEqual(
resolve_repository_name('my.registry.net/username/image'),
('my.registry.net', 'username/image'),
)
# no dots but port
self.assertEqual(
resolve_repository_name('hostname:5000/image'),
('hostname:5000', 'image'),
)
# no dots but port and username
self.assertEqual(
resolve_repository_name('hostname:5000/username/image'),
('hostname:5000', 'username/image'),
)
# localhost
self.assertEqual(
resolve_repository_name('localhost/image'),
('localhost', 'image'),
)
# localhost with username
self.assertEqual(
resolve_repository_name('localhost/username/image'),
('localhost', 'username/image'),
)
def test_resolve_authconfig(self): def test_resolve_authconfig(self):
auth_config = { auth_config = {
'https://index.docker.io/v1/': {'auth': 'indexuser'}, 'https://index.docker.io/v1/': {'auth': 'indexuser'},
@ -231,6 +286,40 @@ class UtilsTest(base.BaseTestCase):
resolve_authconfig(auth_config, 'does.not.exist') is None resolve_authconfig(auth_config, 'does.not.exist') is None
) )
def test_resolve_registry_and_auth(self):
auth_config = {
'https://index.docker.io/v1/': {'auth': 'indexuser'},
'my.registry.net': {'auth': 'privateuser'},
}
# library image
image = 'image'
self.assertEqual(
resolve_authconfig(auth_config, resolve_repository_name(image)[0]),
{'auth': 'indexuser'},
)
# docker hub image
image = 'username/image'
self.assertEqual(
resolve_authconfig(auth_config, resolve_repository_name(image)[0]),
{'auth': 'indexuser'},
)
# private registry
image = 'my.registry.net/image'
self.assertEqual(
resolve_authconfig(auth_config, resolve_repository_name(image)[0]),
{'auth': 'privateuser'},
)
# unauthenticated registry
image = 'other.registry.net/image'
self.assertEqual(
resolve_authconfig(auth_config, resolve_repository_name(image)[0]),
None,
)
def test_split_port_with_host_ip(self): def test_split_port_with_host_ip(self):
internal_port, external_port = split_port("127.0.0.1:1000:2000") internal_port, external_port = split_port("127.0.0.1:1000:2000")
self.assertEqual(internal_port, ["2000"]) self.assertEqual(internal_port, ["2000"])