From c6f715bfcfc35d520749ba6331577e27a5f39761 Mon Sep 17 00:00:00 2001 From: Lucy Linder Date: Wed, 10 Apr 2024 11:42:43 +0200 Subject: [PATCH] feat: support cpuperiod and cpuquota build arguments (Docker v1.19+) Add support for the new container limits introduced in Docker v1.19 for restricting cpu usage during build. See https://docs.docker.com/engine/api/version-history/#v119-api-changes Signed-off-by: Lucy Linder --- docker/api/build.py | 11 +++++++++++ docker/constants.py | 11 ++++++++--- docker/models/images.py | 4 ++++ tests/unit/api_build_test.py | 12 +++++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/docker/api/build.py b/docker/api/build.py index 47216a58f..2499d8b91 100644 --- a/docker/api/build.py +++ b/docker/api/build.py @@ -83,6 +83,10 @@ def build(self, path=None, tag=None, quiet=False, fileobj=None, - cpushares (int): CPU shares (relative weight) - cpusetcpus (str): CPUs in which to allow execution, e.g., ``"0-3"``, ``"0,1"`` + - cpuperiod (int): (Docker API v1.19+) The length of a CPU + period in microseconds + - cpuquota (int): (Docker API v1.19+) Microseconds of CPU + time that the container can get in a CPU period decode (bool): If set to ``True``, the returned stream will be decoded into dicts on the fly. Default ``False`` shmsize (int): Size of `/dev/shm` in bytes. The size must be @@ -135,6 +139,13 @@ def build(self, path=None, tag=None, quiet=False, fileobj=None, raise errors.DockerException( f"invalid tag '{tag}': invalid reference format" ) + introduced_in = constants.CONTAINER_LIMITS_KEYS[key] + if introduced_in is not None: + if utils.version_lt(self._version, introduced_in): + raise errors.InvalidVersion( + f"container limit '{key}' was only introduced" + f" in API version {introduced_in}" + ) if custom_context: if not fileobj: raise TypeError("You must specify fileobj with custom_context") diff --git a/docker/constants.py b/docker/constants.py index 3c527b47e..a996e1547 100644 --- a/docker/constants.py +++ b/docker/constants.py @@ -6,9 +6,14 @@ MINIMUM_DOCKER_API_VERSION = '1.24' DEFAULT_TIMEOUT_SECONDS = 60 STREAM_HEADER_SIZE_BYTES = 8 -CONTAINER_LIMITS_KEYS = [ - 'memory', 'memswap', 'cpushares', 'cpusetcpus' -] +CONTAINER_LIMITS_KEYS = { + 'memory': None, + 'memswap': None, + 'cpushares': None, + 'cpusetcpus': None, + 'cpuperiod': "1.19", + 'cpuquota': "1.19", +} DEFAULT_HTTP_HOST = "127.0.0.1" DEFAULT_UNIX_SOCKET = "http+unix:///var/run/docker.sock" diff --git a/docker/models/images.py b/docker/models/images.py index 4f058d24d..58e2f7efd 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -259,6 +259,10 @@ def build(self, **kwargs): - cpushares (int): CPU shares (relative weight) - cpusetcpus (str): CPUs in which to allow execution, e.g., ``"0-3"``, ``"0,1"`` + - cpuperiod (int): (Docker API v1.19+) The length of a CPU + period in microseconds + - cpuquota (int): (Docker API v1.19+) Microseconds of CPU + time that the container can get in a CPU period shmsize (int): Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB labels (dict): A dictionary of labels to set on the image diff --git a/tests/unit/api_build_test.py b/tests/unit/api_build_test.py index 01958c3e1..d2e03b58d 100644 --- a/tests/unit/api_build_test.py +++ b/tests/unit/api_build_test.py @@ -8,7 +8,7 @@ from docker import auth, errors from docker.api.build import process_dockerfile -from ..helpers import make_tree +from ..helpers import make_tree, requires_api_version from .api_test import BaseAPIClientTest, fake_request, url_prefix @@ -133,6 +133,16 @@ def test_build_container_with_container_limits(self): }, ) + @requires_api_version('1.19') + def test_build_container_with_container_limits_cpu(self): + self.client.build( + ".", + container_limits={ + "cpuquota": 50000, + "cpuperiod": 100000, + }, + ) + def test_build_container_invalid_container_limits(self): with pytest.raises(docker.errors.DockerException): self.client.build(".", container_limits={"foo": "bar"})