diff options
author | Joffrey F <f.joffrey@gmail.com> | 2016-02-24 18:00:06 -0800 |
---|---|---|
committer | Joffrey F <f.joffrey@gmail.com> | 2016-02-24 18:00:06 -0800 |
commit | 81d8caaf36159bf1accd86eab2e157bf8dd071a9 (patch) | |
tree | fe7d2d7ba279f076b57b6ce964d5c132a76a43a9 | |
parent | cdf6dc8c3c5a400721633cff0c0bdf056ec2b52a (diff) | |
parent | 7440603d98d2ceb1d0df372cbf4b1591588a6949 (diff) | |
download | docker-py-81d8caaf36159bf1accd86eab2e157bf8dd071a9.tar.gz |
Merge pull request #916 from docker/container_update_feature
Support for container limits update
-rw-r--r-- | docker/api/container.py | 33 | ||||
-rw-r--r-- | docker/utils/utils.py | 74 | ||||
-rw-r--r-- | docs/api.md | 22 | ||||
-rw-r--r-- | tests/integration/container_test.py | 18 | ||||
-rw-r--r-- | tests/unit/container_test.py | 18 | ||||
-rw-r--r-- | tests/unit/fake_api.py | 7 |
6 files changed, 132 insertions, 40 deletions
diff --git a/docker/api/container.py b/docker/api/container.py index 8aa9aa2..ef17c27 100644 --- a/docker/api/container.py +++ b/docker/api/container.py @@ -398,6 +398,39 @@ class ContainerApiMixin(object): res = self._post(url) self._raise_for_status(res) + @utils.minimum_version('1.22') + @utils.check_resource + def update_container( + self, container, blkio_weight=None, cpu_period=None, cpu_quota=None, + cpu_shares=None, cpuset_cpus=None, cpuset_mems=None, mem_limit=None, + mem_reservation=None, memswap_limit=None, kernel_memory=None + ): + url = self._url('/containers/{0}/update', container) + data = {} + if blkio_weight: + data['BlkioWeight'] = blkio_weight + if cpu_period: + data['CpuPeriod'] = cpu_period + if cpu_shares: + data['CpuShares'] = cpu_shares + if cpu_quota: + data['CpuQuota'] = cpu_quota + if cpuset_cpus: + data['CpusetCpus'] = cpuset_cpus + if cpuset_mems: + data['CpusetMems'] = cpuset_mems + if mem_limit: + data['Memory'] = utils.parse_bytes(mem_limit) + if mem_reservation: + data['MemoryReservation'] = utils.parse_bytes(mem_reservation) + if memswap_limit: + data['MemorySwap'] = utils.parse_bytes(memswap_limit) + if kernel_memory: + data['KernelMemory'] = utils.parse_bytes(kernel_memory) + + res = self._post_json(url, data=data) + return self._result(res, True) + @utils.check_resource def wait(self, container, timeout=None): url = self._url("/containers/{0}/wait", container) diff --git a/docker/utils/utils.py b/docker/utils/utils.py index 8182a43..bc26ce8 100644 --- a/docker/utils/utils.py +++ b/docker/utils/utils.py @@ -518,41 +518,43 @@ def longint(n): def parse_bytes(s): + if isinstance(s, six.integer_types + (float,)): + return s if len(s) == 0: - s = 0 - else: - if s[-2:-1].isalpha() and s[-1].isalpha(): - if s[-1] == "b" or s[-1] == "B": - s = s[:-1] - units = BYTE_UNITS - suffix = s[-1].lower() - - # Check if the variable is a string representation of an int - # without a units part. Assuming that the units are bytes. - if suffix.isdigit(): - digits_part = s - suffix = 'b' - else: - digits_part = s[:-1] + return 0 - if suffix in units.keys() or suffix.isdigit(): - try: - digits = longint(digits_part) - except ValueError: - raise errors.DockerException( - 'Failed converting the string value for memory ({0}) to' - ' an integer.'.format(digits_part) - ) + if s[-2:-1].isalpha() and s[-1].isalpha(): + if s[-1] == "b" or s[-1] == "B": + s = s[:-1] + units = BYTE_UNITS + suffix = s[-1].lower() + + # Check if the variable is a string representation of an int + # without a units part. Assuming that the units are bytes. + if suffix.isdigit(): + digits_part = s + suffix = 'b' + else: + digits_part = s[:-1] - # Reconvert to long for the final result - s = longint(digits * units[suffix]) - else: + if suffix in units.keys() or suffix.isdigit(): + try: + digits = longint(digits_part) + except ValueError: raise errors.DockerException( - 'The specified value for memory ({0}) should specify the' - ' units. The postfix should be one of the `b` `k` `m` `g`' - ' characters'.format(s) + 'Failed converting the string value for memory ({0}) to' + ' an integer.'.format(digits_part) ) + # Reconvert to long for the final result + s = longint(digits * units[suffix]) + else: + raise errors.DockerException( + 'The specified value for memory ({0}) should specify the' + ' units. The postfix should be one of the `b` `k` `m` `g`' + ' characters'.format(s) + ) + return s @@ -594,16 +596,10 @@ def create_host_config(binds=None, port_bindings=None, lxc_conf=None, version = constants.DEFAULT_DOCKER_API_VERSION if mem_limit is not None: - if isinstance(mem_limit, six.string_types): - mem_limit = parse_bytes(mem_limit) - - host_config['Memory'] = mem_limit + host_config['Memory'] = parse_bytes(mem_limit) if memswap_limit is not None: - if isinstance(memswap_limit, six.string_types): - memswap_limit = parse_bytes(memswap_limit) - - host_config['MemorySwap'] = memswap_limit + host_config['MemorySwap'] = parse_bytes(memswap_limit) if mem_swappiness is not None: if version_lt(version, '1.20'): @@ -878,9 +874,9 @@ def create_container_config( if isinstance(labels, list): labels = dict((lbl, six.text_type('')) for lbl in labels) - if isinstance(mem_limit, six.string_types): + if mem_limit is not None: mem_limit = parse_bytes(mem_limit) - if isinstance(memswap_limit, six.string_types): + if memswap_limit is not None: memswap_limit = parse_bytes(memswap_limit) if isinstance(ports, list): diff --git a/docs/api.md b/docs/api.md index 32952bf..3b23ebd 100644 --- a/docs/api.md +++ b/docs/api.md @@ -998,12 +998,32 @@ Display the running processes of a container. ## unpause -Unpauses all processes within a container. +Unpause all processes within a container. **Params**: * container (str): The container to unpause +## update_container + +Update resource configs of one or more containers. + +**Params**: + +* container (str): The container to inspect +* blkio_weight (int): Block IO (relative weight), between 10 and 1000 +* cpu_period (int): Limit CPU CFS (Completely Fair Scheduler) period +* cpu_quota (int): Limit CPU CFS (Completely Fair Scheduler) quota +* cpu_shares (int): CPU shares (relative weight) +* cpuset_cpus (str): CPUs in which to allow execution +* cpuset_mems (str): MEMs in which to allow execution +* mem_limit (int or str): Memory limit +* mem_reservation (int or str): Memory soft limit +* memswap_limit (int or str): Total memory (memory + swap), -1 to disable swap +* kernel_memory (int or str): Kernel memory limit + +**Returns** (dict): Dictionary containing a `Warnings` key. + ## version Nearly identical to the `docker version` command. diff --git a/tests/integration/container_test.py b/tests/integration/container_test.py index aae7ad7..6120135 100644 --- a/tests/integration/container_test.py +++ b/tests/integration/container_test.py @@ -1044,3 +1044,21 @@ class GetContainerStatsTest(helpers.BaseTestCase): for key in ['read', 'network', 'precpu_stats', 'cpu_stats', 'memory_stats', 'blkio_stats']: self.assertIn(key, chunk) + + +class ContainerUpdateTest(helpers.BaseTestCase): + @requires_api_version('1.22') + def test_update_container(self): + old_mem_limit = 400 * 1024 * 1024 + new_mem_limit = 300 * 1024 * 1024 + container = self.client.create_container( + BUSYBOX, 'top', host_config=self.client.create_host_config( + mem_limit=old_mem_limit + ), cpu_shares=102 + ) + self.tmp_containers.append(container) + self.client.start(container) + self.client.update_container(container, mem_limit=new_mem_limit) + inspect_data = self.client.inspect_container(container) + self.assertEqual(inspect_data['HostConfig']['Memory'], new_mem_limit) + self.assertEqual(inspect_data['HostConfig']['CpuShares'], 102) diff --git a/tests/unit/container_test.py b/tests/unit/container_test.py index d66eeed..6e23f89 100644 --- a/tests/unit/container_test.py +++ b/tests/unit/container_test.py @@ -1452,3 +1452,21 @@ class ContainerTest(DockerClientTest): params={'ps_args': 'waux'}, timeout=DEFAULT_TIMEOUT_SECONDS ) + + @requires_api_version('1.22') + def test_container_update(self): + self.client.update_container( + fake_api.FAKE_CONTAINER_ID, mem_limit='2k', cpu_shares=124, + blkio_weight=345 + ) + args = fake_request.call_args + self.assertEqual( + args[0][1], url_prefix + 'containers/3cc2351ab11b/update' + ) + self.assertEqual( + json.loads(args[1]['data']), + {'Memory': 2 * 1024, 'CpuShares': 124, 'BlkioWeight': 345} + ) + self.assertEqual( + args[1]['headers']['Content-Type'], 'application/json' + ) diff --git a/tests/unit/fake_api.py b/tests/unit/fake_api.py index 8852da0..9952595 100644 --- a/tests/unit/fake_api.py +++ b/tests/unit/fake_api.py @@ -441,6 +441,11 @@ def get_fake_volume(): def fake_remove_volume(): return 204, None + +def post_fake_update_container(): + return 200, {'Warnings': []} + + # Maps real api url to fake response callback prefix = 'http+docker://localunixsocket' fake_responses = { @@ -478,6 +483,8 @@ fake_responses = { get_fake_diff, '{1}/{0}/containers/3cc2351ab11b/export'.format(CURRENT_VERSION, prefix): get_fake_export, + '{1}/{0}/containers/3cc2351ab11b/update'.format(CURRENT_VERSION, prefix): + post_fake_update_container, '{1}/{0}/containers/3cc2351ab11b/exec'.format(CURRENT_VERSION, prefix): post_fake_exec_create, '{1}/{0}/exec/d5d177f121dc/start'.format(CURRENT_VERSION, prefix): |