diff --git a/docker/api/build.py b/docker/api/build.py index f9678a39..42a1a296 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): + squash=None, extra_hosts=None): """ Similar to the ``docker build`` command. Either ``path`` or ``fileobj`` needs to be set. ``path`` can be a local path (to a directory @@ -101,6 +101,8 @@ class BuildApiMixin(object): build squash (bool): Squash the resulting images layers into a single layer. + extra_hosts (dict): Extra hosts to add to /etc/hosts in building + containers, as a mapping of hostname to IP address. Returns: A generator for the build output. @@ -229,6 +231,17 @@ class BuildApiMixin(object): 'squash was only introduced in API version 1.25' ) + if extra_hosts is not None: + if utils.version_lt(self._version, '1.27'): + raise errors.InvalidVersion( + 'extra_hosts was only introduced in API version 1.27' + ) + + encoded_extra_hosts = [ + '{}:{}'.format(k, v) for k, v in extra_hosts.items() + ] + params.update({'extrahosts': encoded_extra_hosts}) + if context is not None: headers = {'Content-Type': 'application/tar'} if encoding: diff --git a/docker/models/images.py b/docker/models/images.py index 2aae46d8..82ca5413 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -153,6 +153,10 @@ class ImageCollection(Collection): Dockerfile network_mode (str): networking mode for the run commands during build + squash (bool): Squash the resulting images layers into a + single layer. + extra_hosts (dict): Extra hosts to add to /etc/hosts in building + containers, as a mapping of hostname to IP address. Returns: (:py:class:`Image`): The built image. diff --git a/tests/integration/api_build_test.py b/tests/integration/api_build_test.py index d0aa5c21..21464ff6 100644 --- a/tests/integration/api_build_test.py +++ b/tests/integration/api_build_test.py @@ -244,6 +244,38 @@ class BuildTest(BaseAPIIntegrationTest): with pytest.raises(errors.NotFound): self.client.inspect_image('dockerpytest_nonebuild') + @requires_api_version('1.27') + def test_build_with_extra_hosts(self): + img_name = 'dockerpytest_extrahost_build' + self.tmp_imgs.append(img_name) + + script = io.BytesIO('\n'.join([ + 'FROM busybox', + 'RUN ping -c1 hello.world.test', + 'RUN ping -c1 extrahost.local.test', + 'RUN cp /etc/hosts /hosts-file' + ]).encode('ascii')) + + stream = self.client.build( + fileobj=script, tag=img_name, + extra_hosts={ + 'extrahost.local.test': '127.0.0.1', + 'hello.world.test': '8.8.8.8', + }, decode=True + ) + for chunk in stream: + if 'errorDetail' in chunk: + pytest.fail(chunk) + + assert self.client.inspect_image(img_name) + ctnr = self.run_container(img_name, 'cat /hosts-file') + self.tmp_containers.append(ctnr) + logs = self.client.logs(ctnr) + if six.PY3: + logs = logs.decode('utf-8') + assert '127.0.0.1\textrahost.local.test' in logs + assert '8.8.8.8\thello.world.test' in logs + @requires_experimental(until=None) @requires_api_version('1.25') def test_build_squash(self):