mirror of https://github.com/docker/docker-py.git
Make sure the build command in the client sends the auth credentials along. Required for "FROM " lines that pull from private registries
This commit is contained in:
parent
2d56149831
commit
9ae3bcd2f3
|
@ -87,6 +87,10 @@ def resolve_authconfig(authconfig, registry=None):
|
||||||
return authconfig.get(swap_protocol(registry), None)
|
return authconfig.get(swap_protocol(registry), None)
|
||||||
|
|
||||||
|
|
||||||
|
def encode_auth(auth_info):
|
||||||
|
return base64.b64encode(auth_info.get('username', '') + b':' +
|
||||||
|
auth_info.get('password', ''))
|
||||||
|
|
||||||
def decode_auth(auth):
|
def decode_auth(auth):
|
||||||
if isinstance(auth, six.string_types):
|
if isinstance(auth, six.string_types):
|
||||||
auth = auth.encode('ascii')
|
auth = auth.encode('ascii')
|
||||||
|
@ -100,6 +104,12 @@ def encode_header(auth):
|
||||||
return base64.b64encode(auth_json)
|
return base64.b64encode(auth_json)
|
||||||
|
|
||||||
|
|
||||||
|
def encode_full_header(auth):
|
||||||
|
""" Returns the given auth block encoded for the X-Registry-Config header.
|
||||||
|
"""
|
||||||
|
return encode_header({'configs': auth})
|
||||||
|
|
||||||
|
|
||||||
def load_config(root=None):
|
def load_config(root=None):
|
||||||
"""Loads authentication data from a Docker configuration file in the given
|
"""Loads authentication data from a Docker configuration file in the given
|
||||||
root directory."""
|
root directory."""
|
||||||
|
|
|
@ -28,7 +28,7 @@ from .utils import utils
|
||||||
if not six.PY3:
|
if not six.PY3:
|
||||||
import websocket
|
import websocket
|
||||||
|
|
||||||
DEFAULT_DOCKER_API_VERSION = '1.8'
|
DEFAULT_DOCKER_API_VERSION = '1.9'
|
||||||
DEFAULT_TIMEOUT_SECONDS = 60
|
DEFAULT_TIMEOUT_SECONDS = 60
|
||||||
STREAM_HEADER_SIZE_BYTES = 8
|
STREAM_HEADER_SIZE_BYTES = 8
|
||||||
|
|
||||||
|
@ -361,6 +361,17 @@ class Client(requests.Session):
|
||||||
if context is not None:
|
if context is not None:
|
||||||
headers = {'Content-Type': 'application/tar'}
|
headers = {'Content-Type': 'application/tar'}
|
||||||
|
|
||||||
|
if utils.compare_version('1.9', self._version) >= 0:
|
||||||
|
# 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.
|
||||||
|
if not self._auth_configs:
|
||||||
|
self._auth_configs = auth.load_config()
|
||||||
|
|
||||||
|
# Send the full auth configuration (if any exists), since the build
|
||||||
|
# could use any (or all) of the registries.
|
||||||
|
if self._auth_configs:
|
||||||
|
headers['X-Registry-Config'] = auth.encode_full_header(self._auth_configs)
|
||||||
|
|
||||||
response = self._post(
|
response = self._post(
|
||||||
u,
|
u,
|
||||||
data=context,
|
data=context,
|
||||||
|
@ -618,7 +629,7 @@ class Client(requests.Session):
|
||||||
self._auth_configs = auth.load_config()
|
self._auth_configs = auth.load_config()
|
||||||
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
|
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
|
||||||
|
|
||||||
# Do not fail here if no atuhentication exists for this specific
|
# Do not fail here if no authentication exists for this specific
|
||||||
# registry as we can have a readonly pull. Just put the header if
|
# registry as we can have a readonly pull. Just put the header if
|
||||||
# we can.
|
# we can.
|
||||||
if authcfg:
|
if authcfg:
|
||||||
|
@ -644,7 +655,7 @@ class Client(requests.Session):
|
||||||
self._auth_configs = auth.load_config()
|
self._auth_configs = auth.load_config()
|
||||||
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
|
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
|
||||||
|
|
||||||
# Do not fail here if no atuhentication exists for this specific
|
# Do not fail here if no authentication exists for this specific
|
||||||
# registry as we can have a readonly pull. Just put the header if
|
# registry as we can have a readonly pull. Just put the header if
|
||||||
# we can.
|
# we can.
|
||||||
if authcfg:
|
if authcfg:
|
||||||
|
|
|
@ -32,7 +32,7 @@ class BaseTestCase(unittest.TestCase):
|
||||||
tmp_containers = []
|
tmp_containers = []
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.client = docker.Client()
|
self.client = docker.Client(base_url='http://localhost:4243')
|
||||||
self.client.pull('busybox')
|
self.client.pull('busybox')
|
||||||
self.tmp_imgs = []
|
self.tmp_imgs = []
|
||||||
self.tmp_containers = []
|
self.tmp_containers = []
|
||||||
|
@ -755,6 +755,29 @@ class TestBuildFromStringIO(BaseTestCase):
|
||||||
self.assertNotEqual(logs, '')
|
self.assertNotEqual(logs, '')
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildWithAuth(BaseTestCase):
|
||||||
|
def runTest(self):
|
||||||
|
if self.client._version < 1.9:
|
||||||
|
return
|
||||||
|
|
||||||
|
key = 'K4104GON3P4Q6ZUJFZRRC2ZQTBJ5YT0UMZD7TGT7ZVIR8Y05FAH2TJQI6Y90SMIB'
|
||||||
|
self.client.login('quay+fortesting', key, registry='https://quay.io/v1/', email='')
|
||||||
|
|
||||||
|
script = io.BytesIO('\n'.join([
|
||||||
|
'FROM quay.io/quay/teststuff',
|
||||||
|
'MAINTAINER docker-py',
|
||||||
|
'RUN mkdir -p /tmp/test',
|
||||||
|
]).encode('ascii'))
|
||||||
|
|
||||||
|
stream = self.client.build(fileobj=script, stream=True)
|
||||||
|
logs = ''
|
||||||
|
for chunk in stream:
|
||||||
|
logs += chunk
|
||||||
|
|
||||||
|
self.assertNotEqual(logs, '')
|
||||||
|
self.assertEqual(logs.find('HTTP code: 403'), -1)
|
||||||
|
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
# PY SPECIFIC TESTS #
|
# PY SPECIFIC TESTS #
|
||||||
#######################
|
#######################
|
||||||
|
@ -820,7 +843,7 @@ class TestLoadJSONConfig(BaseTestCase):
|
||||||
class TestConnectionTimeout(unittest.TestCase):
|
class TestConnectionTimeout(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.timeout = 0.5
|
self.timeout = 0.5
|
||||||
self.client = docker.client.Client(base_url='http://192.168.10.2:4243',
|
self.client = docker.client.Client(base_url='http://localhost:4243',
|
||||||
timeout=self.timeout)
|
timeout=self.timeout)
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
Loading…
Reference in New Issue