Skip to content

Commit 72b9b72

Browse files
authored
Merge pull request #1570 from AlexeyRokhin/master
Add cpu_count, cpu_percent, nano_cpus parameters to container HostConfig.
2 parents d19572a + c2f83d5 commit 72b9b72

File tree

4 files changed

+98
-1
lines changed

4 files changed

+98
-1
lines changed

docker/models/containers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,9 @@ def run(self, image, command=None, stdout=True, stderr=False,
474474
cap_add (list of str): Add kernel capabilities. For example,
475475
``["SYS_ADMIN", "MKNOD"]``.
476476
cap_drop (list of str): Drop kernel capabilities.
477+
cpu_count (int): Number of usable CPUs (Windows only).
478+
cpu_percent (int): Usable percentage of the available CPUs
479+
(Windows only).
477480
cpu_period (int): The length of a CPU period in microseconds.
478481
cpu_quota (int): Microseconds of CPU time that the container can
479482
get in a CPU period.
@@ -541,6 +544,7 @@ def run(self, image, command=None, stdout=True, stderr=False,
541544
networks (:py:class:`list`): A list of network names to connect
542545
this container to.
543546
name (str): The name for this container.
547+
nano_cpus (int): CPU quota in units of 10-9 CPUs.
544548
network_disabled (bool): Disable networking.
545549
network_mode (str): One of:
546550
@@ -819,6 +823,8 @@ def prune(self, filters=None):
819823
'cap_add',
820824
'cap_drop',
821825
'cgroup_parent',
826+
'cpu_count',
827+
'cpu_percent',
822828
'cpu_period',
823829
'cpu_quota',
824830
'cpu_shares',
@@ -845,6 +851,7 @@ def prune(self, filters=None):
845851
'mem_reservation',
846852
'mem_swappiness',
847853
'memswap_limit',
854+
'nano_cpus',
848855
'network_mode',
849856
'oom_kill_disable',
850857
'oom_score_adj',

docker/types/containers.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ def __init__(self, version, binds=None, port_bindings=None,
118118
tmpfs=None, oom_score_adj=None, dns_opt=None, cpu_shares=None,
119119
cpuset_cpus=None, userns_mode=None, pids_limit=None,
120120
isolation=None, auto_remove=False, storage_opt=None,
121-
init=None, init_path=None, volume_driver=None):
121+
init=None, init_path=None, volume_driver=None,
122+
cpu_count=None, cpu_percent=None, nano_cpus=None):
122123

123124
if mem_limit is not None:
124125
self['Memory'] = parse_bytes(mem_limit)
@@ -433,6 +434,30 @@ def __init__(self, version, binds=None, port_bindings=None,
433434
raise host_config_version_error('volume_driver', '1.21')
434435
self['VolumeDriver'] = volume_driver
435436

437+
if cpu_count:
438+
if not isinstance(cpu_count, int):
439+
raise host_config_type_error('cpu_count', cpu_count, 'int')
440+
if version_lt(version, '1.25'):
441+
raise host_config_version_error('cpu_count', '1.25')
442+
443+
self['CpuCount'] = cpu_count
444+
445+
if cpu_percent:
446+
if not isinstance(cpu_percent, int):
447+
raise host_config_type_error('cpu_percent', cpu_percent, 'int')
448+
if version_lt(version, '1.25'):
449+
raise host_config_version_error('cpu_percent', '1.25')
450+
451+
self['CpuPercent'] = cpu_percent
452+
453+
if nano_cpus:
454+
if not isinstance(nano_cpus, int):
455+
raise host_config_type_error('nano_cpus', nano_cpus, 'int')
456+
if version_lt(version, '1.25'):
457+
raise host_config_version_error('nano_cpus', '1.25')
458+
459+
self['NanoCpus'] = nano_cpus
460+
436461

437462
def host_config_type_error(param, param_value, expected):
438463
error_msg = 'Invalid type for {0} param: expected {1} but found {2}'

tests/unit/api_container_test.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,38 @@ def test_create_container_with_unicode_envvars(self):
11521152
self.assertEqual(args[0][1], url_prefix + 'containers/create')
11531153
self.assertEqual(json.loads(args[1]['data'])['Env'], expected)
11541154

1155+
@requires_api_version('1.25')
1156+
def test_create_container_with_host_config_cpus(self):
1157+
self.client.create_container(
1158+
'busybox', 'ls', host_config=self.client.create_host_config(
1159+
cpu_count=1,
1160+
cpu_percent=20,
1161+
nano_cpus=1000
1162+
)
1163+
)
1164+
1165+
args = fake_request.call_args
1166+
self.assertEqual(args[0][1],
1167+
url_prefix + 'containers/create')
1168+
1169+
self.assertEqual(json.loads(args[1]['data']),
1170+
json.loads('''
1171+
{"Tty": false, "Image": "busybox",
1172+
"Cmd": ["ls"], "AttachStdin": false,
1173+
"AttachStderr": true,
1174+
"AttachStdout": true, "OpenStdin": false,
1175+
"StdinOnce": false,
1176+
"NetworkDisabled": false,
1177+
"HostConfig": {
1178+
"CpuCount": 1,
1179+
"CpuPercent": 20,
1180+
"NanoCpus": 1000,
1181+
"NetworkMode": "default"
1182+
}}'''))
1183+
self.assertEqual(
1184+
args[1]['headers'], {'Content-Type': 'application/json'}
1185+
)
1186+
11551187

11561188
class ContainerTest(BaseAPIClientTest):
11571189
def test_list_containers(self):

tests/unit/dockertypes_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,39 @@ def test_create_host_config_with_volume_driver(self):
173173
config = create_host_config(version='1.21', volume_driver='local')
174174
assert config.get('VolumeDriver') == 'local'
175175

176+
def test_create_host_config_invalid_cpu_count_types(self):
177+
with pytest.raises(TypeError):
178+
create_host_config(version='1.25', cpu_count='1')
179+
180+
def test_create_host_config_with_cpu_count(self):
181+
config = create_host_config(version='1.25', cpu_count=2)
182+
self.assertEqual(config.get('CpuCount'), 2)
183+
self.assertRaises(
184+
InvalidVersion, lambda: create_host_config(
185+
version='1.24', cpu_count=1))
186+
187+
def test_create_host_config_invalid_cpu_percent_types(self):
188+
with pytest.raises(TypeError):
189+
create_host_config(version='1.25', cpu_percent='1')
190+
191+
def test_create_host_config_with_cpu_percent(self):
192+
config = create_host_config(version='1.25', cpu_percent=15)
193+
self.assertEqual(config.get('CpuPercent'), 15)
194+
self.assertRaises(
195+
InvalidVersion, lambda: create_host_config(
196+
version='1.24', cpu_percent=10))
197+
198+
def test_create_host_config_invalid_nano_cpus_types(self):
199+
with pytest.raises(TypeError):
200+
create_host_config(version='1.25', nano_cpus='0')
201+
202+
def test_create_host_config_with_nano_cpus(self):
203+
config = create_host_config(version='1.25', nano_cpus=1000)
204+
self.assertEqual(config.get('NanoCpus'), 1000)
205+
self.assertRaises(
206+
InvalidVersion, lambda: create_host_config(
207+
version='1.24', nano_cpus=1))
208+
176209

177210
class ContainerConfigTest(unittest.TestCase):
178211
def test_create_container_config_volume_driver_warning(self):

0 commit comments

Comments
 (0)