diff options
author | Joffrey F <joffrey@docker.com> | 2018-01-08 18:11:29 -0800 |
---|---|---|
committer | Joffrey F <joffrey@docker.com> | 2018-01-23 16:59:09 -0800 |
commit | f95b958429b38dab50929e013db3c636a12e1536 (patch) | |
tree | b8de1cfd18d1c3c932592388143665f446e871f6 | |
parent | bf5e7702df3c835a5db4fc6b86500b4f4b659c14 (diff) | |
download | docker-py-1855-platform-option.tar.gz |
Add support for experimental platform flag in build and pull1855-platform-option
Signed-off-by: Joffrey F <joffrey@docker.com>
-rw-r--r-- | docker/api/build.py | 10 | ||||
-rw-r--r-- | docker/api/image.py | 13 | ||||
-rw-r--r-- | docker/models/containers.py | 8 | ||||
-rw-r--r-- | docker/models/images.py | 2 | ||||
-rw-r--r-- | tests/integration/api_build_test.py | 15 | ||||
-rw-r--r-- | tests/integration/api_image_test.py | 11 | ||||
-rw-r--r-- | tests/unit/models_containers_test.py | 2 |
7 files changed, 54 insertions, 7 deletions
diff --git a/docker/api/build.py b/docker/api/build.py index 34456ab..32238ef 100644 --- a/docker/api/build.py +++ b/docker/api/build.py @@ -19,7 +19,7 @@ class BuildApiMixin(object): forcerm=False, dockerfile=None, container_limits=None, decode=False, buildargs=None, gzip=False, shmsize=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`` needs to be set. ``path`` can be a local path (to a directory @@ -103,6 +103,7 @@ class BuildApiMixin(object): single layer. extra_hosts (dict): Extra hosts to add to /etc/hosts in building containers, as a mapping of hostname to IP address. + platform (str): Platform in the format ``os[/arch[/variant]]`` Returns: A generator for the build output. @@ -243,6 +244,13 @@ class BuildApiMixin(object): extra_hosts = utils.format_extra_hosts(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: headers = {'Content-Type': 'application/tar'} if encoding: diff --git a/docker/api/image.py b/docker/api/image.py index 7755312..065fae3 100644 --- a/docker/api/image.py +++ b/docker/api/image.py @@ -323,7 +323,8 @@ class ImageApiMixin(object): return self._result(self._post(url, params=params), True) 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. @@ -336,6 +337,7 @@ class ImageApiMixin(object): :py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for this request. ``auth_config`` should contain the ``username`` and ``password`` keys to be valid. + platform (str): Platform in the format ``os[/arch[/variant]]`` Returns: (generator or str): The output @@ -376,7 +378,7 @@ class ImageApiMixin(object): } headers = {} - if utils.compare_version('1.5', self._version) >= 0: + if utils.version_gte(self._version, '1.5'): if auth_config is None: header = auth.get_config_header(self, registry) if header: @@ -385,6 +387,13 @@ class ImageApiMixin(object): log.debug('Sending supplied 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( self._url('/images/create'), params=params, headers=headers, stream=stream, timeout=None diff --git a/docker/models/containers.py b/docker/models/containers.py index 6ba308e..5e2aa88 100644 --- a/docker/models/containers.py +++ b/docker/models/containers.py @@ -579,6 +579,8 @@ class ContainerCollection(Collection): inside the container. pids_limit (int): Tune a container's pids limit. Set ``-1`` for 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. The keys of the dictionary are the ports to bind inside the @@ -700,7 +702,9 @@ class ContainerCollection(Collection): if isinstance(image, Image): image = image.id 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 version_gte(self.client.api._version, '1.25'): kwargs["auto_remove"] = True @@ -718,7 +722,7 @@ class ContainerCollection(Collection): container = self.create(image=image, command=command, detach=detach, **kwargs) except ImageNotFound: - self.client.images.pull(image) + self.client.images.pull(image, platform=platform) container = self.create(image=image, command=command, detach=detach, **kwargs) diff --git a/docker/models/images.py b/docker/models/images.py index 82ca541..891c565 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -157,6 +157,7 @@ class ImageCollection(Collection): single layer. extra_hosts (dict): Extra hosts to add to /etc/hosts in building containers, as a mapping of hostname to IP address. + platform (str): Platform in the format ``os[/arch[/variant]]``. Returns: (:py:class:`Image`): The built image. @@ -265,6 +266,7 @@ class ImageCollection(Collection): :py:meth:`~docker.client.DockerClient.login` has set for this request. ``auth_config`` should contain the ``username`` and ``password`` keys to be valid. + platform (str): Platform in the format ``os[/arch[/variant]]`` Returns: (:py:class:`Image`): The image that has been pulled. diff --git a/tests/integration/api_build_test.py b/tests/integration/api_build_test.py index 7cc3234..245214e 100644 --- a/tests/integration/api_build_test.py +++ b/tests/integration/api_build_test.py @@ -377,3 +377,18 @@ class BuildTest(BaseAPIIntegrationTest): def test_build_gzip_custom_encoding(self): with self.assertRaises(errors.DockerException): 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() diff --git a/tests/integration/api_image_test.py b/tests/integration/api_image_test.py index 14fb77a..178c34e 100644 --- a/tests/integration/api_image_test.py +++ b/tests/integration/api_image_test.py @@ -14,7 +14,7 @@ from six.moves import socketserver import docker -from ..helpers import requires_api_version +from ..helpers import requires_api_version, requires_experimental from .base import BaseAPIIntegrationTest, BUSYBOX @@ -67,6 +67,15 @@ class PullImageTest(BaseAPIIntegrationTest): img_info = self.client.inspect_image('hello-world') 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): def test_commit(self): diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py index a479e83..95295a9 100644 --- a/tests/unit/models_containers_test.py +++ b/tests/unit/models_containers_test.py @@ -225,7 +225,7 @@ class ContainerCollectionTest(unittest.TestCase): container = client.containers.run('alpine', 'sleep 300', detach=True) 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): client = make_fake_client() |