mirror of https://github.com/docker/docker-py.git
Add support for experimental platform flag in build and pull
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
bf5e7702df
commit
f95b958429
|
|
@ -19,7 +19,7 @@ class BuildApiMixin(object):
|
||||||
forcerm=False, dockerfile=None, container_limits=None,
|
forcerm=False, dockerfile=None, container_limits=None,
|
||||||
decode=False, buildargs=None, gzip=False, shmsize=None,
|
decode=False, buildargs=None, gzip=False, shmsize=None,
|
||||||
labels=None, cache_from=None, target=None, network_mode=None,
|
labels=None, cache_from=None, target=None, network_mode=None,
|
||||||
squash=None, extra_hosts=None):
|
squash=None, extra_hosts=None, platform=None):
|
||||||
"""
|
"""
|
||||||
Similar to the ``docker build`` command. Either ``path`` or ``fileobj``
|
Similar to the ``docker build`` command. Either ``path`` or ``fileobj``
|
||||||
needs to be set. ``path`` can be a local path (to a directory
|
needs to be set. ``path`` can be a local path (to a directory
|
||||||
|
|
@ -103,6 +103,7 @@ class BuildApiMixin(object):
|
||||||
single layer.
|
single layer.
|
||||||
extra_hosts (dict): Extra hosts to add to /etc/hosts in building
|
extra_hosts (dict): Extra hosts to add to /etc/hosts in building
|
||||||
containers, as a mapping of hostname to IP address.
|
containers, as a mapping of hostname to IP address.
|
||||||
|
platform (str): Platform in the format ``os[/arch[/variant]]``
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A generator for the build output.
|
A generator for the build output.
|
||||||
|
|
@ -243,6 +244,13 @@ class BuildApiMixin(object):
|
||||||
extra_hosts = utils.format_extra_hosts(extra_hosts)
|
extra_hosts = utils.format_extra_hosts(extra_hosts)
|
||||||
params.update({'extrahosts': extra_hosts})
|
params.update({'extrahosts': extra_hosts})
|
||||||
|
|
||||||
|
if platform is not None:
|
||||||
|
if utils.version_lt(self._version, '1.32'):
|
||||||
|
raise errors.InvalidVersion(
|
||||||
|
'platform was only introduced in API version 1.32'
|
||||||
|
)
|
||||||
|
params['platform'] = platform
|
||||||
|
|
||||||
if context is not None:
|
if context is not None:
|
||||||
headers = {'Content-Type': 'application/tar'}
|
headers = {'Content-Type': 'application/tar'}
|
||||||
if encoding:
|
if encoding:
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,8 @@ class ImageApiMixin(object):
|
||||||
return self._result(self._post(url, params=params), True)
|
return self._result(self._post(url, params=params), True)
|
||||||
|
|
||||||
def pull(self, repository, tag=None, stream=False,
|
def pull(self, repository, tag=None, stream=False,
|
||||||
insecure_registry=False, auth_config=None, decode=False):
|
insecure_registry=False, auth_config=None, decode=False,
|
||||||
|
platform=None):
|
||||||
"""
|
"""
|
||||||
Pulls an image. Similar to the ``docker pull`` command.
|
Pulls an image. Similar to the ``docker pull`` command.
|
||||||
|
|
||||||
|
|
@ -336,6 +337,7 @@ class ImageApiMixin(object):
|
||||||
:py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for
|
:py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for
|
||||||
this request. ``auth_config`` should contain the ``username``
|
this request. ``auth_config`` should contain the ``username``
|
||||||
and ``password`` keys to be valid.
|
and ``password`` keys to be valid.
|
||||||
|
platform (str): Platform in the format ``os[/arch[/variant]]``
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(generator or str): The output
|
(generator or str): The output
|
||||||
|
|
@ -376,7 +378,7 @@ class ImageApiMixin(object):
|
||||||
}
|
}
|
||||||
headers = {}
|
headers = {}
|
||||||
|
|
||||||
if utils.compare_version('1.5', self._version) >= 0:
|
if utils.version_gte(self._version, '1.5'):
|
||||||
if auth_config is None:
|
if auth_config is None:
|
||||||
header = auth.get_config_header(self, registry)
|
header = auth.get_config_header(self, registry)
|
||||||
if header:
|
if header:
|
||||||
|
|
@ -385,6 +387,13 @@ class ImageApiMixin(object):
|
||||||
log.debug('Sending supplied auth config')
|
log.debug('Sending supplied auth config')
|
||||||
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
|
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
|
||||||
|
|
||||||
|
if platform is not None:
|
||||||
|
if utils.version_lt(self._version, '1.32'):
|
||||||
|
raise errors.InvalidVersion(
|
||||||
|
'platform was only introduced in API version 1.32'
|
||||||
|
)
|
||||||
|
params['platform'] = platform
|
||||||
|
|
||||||
response = self._post(
|
response = self._post(
|
||||||
self._url('/images/create'), params=params, headers=headers,
|
self._url('/images/create'), params=params, headers=headers,
|
||||||
stream=stream, timeout=None
|
stream=stream, timeout=None
|
||||||
|
|
|
||||||
|
|
@ -579,6 +579,8 @@ class ContainerCollection(Collection):
|
||||||
inside the container.
|
inside the container.
|
||||||
pids_limit (int): Tune a container's pids limit. Set ``-1`` for
|
pids_limit (int): Tune a container's pids limit. Set ``-1`` for
|
||||||
unlimited.
|
unlimited.
|
||||||
|
platform (str): Platform in the format ``os[/arch[/variant]]``.
|
||||||
|
Only used if the method needs to pull the requested image.
|
||||||
ports (dict): Ports to bind inside the container.
|
ports (dict): Ports to bind inside the container.
|
||||||
|
|
||||||
The keys of the dictionary are the ports to bind inside the
|
The keys of the dictionary are the ports to bind inside the
|
||||||
|
|
@ -700,7 +702,9 @@ class ContainerCollection(Collection):
|
||||||
if isinstance(image, Image):
|
if isinstance(image, Image):
|
||||||
image = image.id
|
image = image.id
|
||||||
stream = kwargs.pop('stream', False)
|
stream = kwargs.pop('stream', False)
|
||||||
detach = kwargs.pop("detach", False)
|
detach = kwargs.pop('detach', False)
|
||||||
|
platform = kwargs.pop('platform', None)
|
||||||
|
|
||||||
if detach and remove:
|
if detach and remove:
|
||||||
if version_gte(self.client.api._version, '1.25'):
|
if version_gte(self.client.api._version, '1.25'):
|
||||||
kwargs["auto_remove"] = True
|
kwargs["auto_remove"] = True
|
||||||
|
|
@ -718,7 +722,7 @@ class ContainerCollection(Collection):
|
||||||
container = self.create(image=image, command=command,
|
container = self.create(image=image, command=command,
|
||||||
detach=detach, **kwargs)
|
detach=detach, **kwargs)
|
||||||
except ImageNotFound:
|
except ImageNotFound:
|
||||||
self.client.images.pull(image)
|
self.client.images.pull(image, platform=platform)
|
||||||
container = self.create(image=image, command=command,
|
container = self.create(image=image, command=command,
|
||||||
detach=detach, **kwargs)
|
detach=detach, **kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,7 @@ class ImageCollection(Collection):
|
||||||
single layer.
|
single layer.
|
||||||
extra_hosts (dict): Extra hosts to add to /etc/hosts in building
|
extra_hosts (dict): Extra hosts to add to /etc/hosts in building
|
||||||
containers, as a mapping of hostname to IP address.
|
containers, as a mapping of hostname to IP address.
|
||||||
|
platform (str): Platform in the format ``os[/arch[/variant]]``.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(:py:class:`Image`): The built image.
|
(:py:class:`Image`): The built image.
|
||||||
|
|
@ -265,6 +266,7 @@ class ImageCollection(Collection):
|
||||||
:py:meth:`~docker.client.DockerClient.login` has set for
|
:py:meth:`~docker.client.DockerClient.login` has set for
|
||||||
this request. ``auth_config`` should contain the ``username``
|
this request. ``auth_config`` should contain the ``username``
|
||||||
and ``password`` keys to be valid.
|
and ``password`` keys to be valid.
|
||||||
|
platform (str): Platform in the format ``os[/arch[/variant]]``
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(:py:class:`Image`): The image that has been pulled.
|
(:py:class:`Image`): The image that has been pulled.
|
||||||
|
|
|
||||||
|
|
@ -377,3 +377,18 @@ class BuildTest(BaseAPIIntegrationTest):
|
||||||
def test_build_gzip_custom_encoding(self):
|
def test_build_gzip_custom_encoding(self):
|
||||||
with self.assertRaises(errors.DockerException):
|
with self.assertRaises(errors.DockerException):
|
||||||
self.client.build(path='.', gzip=True, encoding='text/html')
|
self.client.build(path='.', gzip=True, encoding='text/html')
|
||||||
|
|
||||||
|
@requires_api_version('1.32')
|
||||||
|
@requires_experimental(until=None)
|
||||||
|
def test_build_invalid_platform(self):
|
||||||
|
script = io.BytesIO('FROM busybox\n'.encode('ascii'))
|
||||||
|
|
||||||
|
with pytest.raises(errors.APIError) as excinfo:
|
||||||
|
stream = self.client.build(
|
||||||
|
fileobj=script, stream=True, platform='foobar'
|
||||||
|
)
|
||||||
|
for _ in stream:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert excinfo.value.status_code == 400
|
||||||
|
assert 'invalid platform' in excinfo.exconly()
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ from six.moves import socketserver
|
||||||
|
|
||||||
import docker
|
import docker
|
||||||
|
|
||||||
from ..helpers import requires_api_version
|
from ..helpers import requires_api_version, requires_experimental
|
||||||
from .base import BaseAPIIntegrationTest, BUSYBOX
|
from .base import BaseAPIIntegrationTest, BUSYBOX
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -67,6 +67,15 @@ class PullImageTest(BaseAPIIntegrationTest):
|
||||||
img_info = self.client.inspect_image('hello-world')
|
img_info = self.client.inspect_image('hello-world')
|
||||||
self.assertIn('Id', img_info)
|
self.assertIn('Id', img_info)
|
||||||
|
|
||||||
|
@requires_api_version('1.32')
|
||||||
|
@requires_experimental(until=None)
|
||||||
|
def test_pull_invalid_platform(self):
|
||||||
|
with pytest.raises(docker.errors.APIError) as excinfo:
|
||||||
|
self.client.pull('hello-world', platform='foobar')
|
||||||
|
|
||||||
|
assert excinfo.value.status_code == 500
|
||||||
|
assert 'invalid platform' in excinfo.exconly()
|
||||||
|
|
||||||
|
|
||||||
class CommitTest(BaseAPIIntegrationTest):
|
class CommitTest(BaseAPIIntegrationTest):
|
||||||
def test_commit(self):
|
def test_commit(self):
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ class ContainerCollectionTest(unittest.TestCase):
|
||||||
container = client.containers.run('alpine', 'sleep 300', detach=True)
|
container = client.containers.run('alpine', 'sleep 300', detach=True)
|
||||||
|
|
||||||
assert container.id == FAKE_CONTAINER_ID
|
assert container.id == FAKE_CONTAINER_ID
|
||||||
client.api.pull.assert_called_with('alpine', tag=None)
|
client.api.pull.assert_called_with('alpine', platform=None, tag=None)
|
||||||
|
|
||||||
def test_run_with_error(self):
|
def test_run_with_error(self):
|
||||||
client = make_fake_client()
|
client = make_fake_client()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue