Skip to content

Commit ac90a87

Browse files
committed
Merge pull request #644 from docker/memory-memswap-hostconfig
memory / memswap in hostconfig
2 parents c8c957c + a12ba1a commit ac90a87

File tree

3 files changed

+91
-63
lines changed

3 files changed

+91
-63
lines changed

docker/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,11 @@ def copy(self, container, resource):
450450

451451
def create_container(self, image, command=None, hostname=None, user=None,
452452
detach=False, stdin_open=False, tty=False,
453-
mem_limit=0, ports=None, environment=None, dns=None,
454-
volumes=None, volumes_from=None,
453+
mem_limit=None, ports=None, environment=None,
454+
dns=None, volumes=None, volumes_from=None,
455455
network_disabled=False, name=None, entrypoint=None,
456456
cpu_shares=None, working_dir=None, domainname=None,
457-
memswap_limit=0, cpuset=None, host_config=None,
457+
memswap_limit=None, cpuset=None, host_config=None,
458458
mac_address=None, labels=None, volume_driver=None):
459459

460460
if isinstance(volumes, six.string_types):

docker/utils/utils.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -383,10 +383,21 @@ def create_host_config(
383383
dns=None, dns_search=None, volumes_from=None, network_mode=None,
384384
restart_policy=None, cap_add=None, cap_drop=None, devices=None,
385385
extra_hosts=None, read_only=None, pid_mode=None, ipc_mode=None,
386-
security_opt=None, ulimits=None, log_config=None
386+
security_opt=None, ulimits=None, log_config=None, mem_limit=None,
387+
memswap_limit=None
387388
):
388389
host_config = {}
389390

391+
if mem_limit is not None:
392+
if isinstance(mem_limit, six.string_types):
393+
mem_limit = parse_bytes(mem_limit)
394+
host_config['Memory'] = mem_limit
395+
396+
if memswap_limit is not None:
397+
if isinstance(memswap_limit, six.string_types):
398+
memswap_limit = parse_bytes(memswap_limit)
399+
host_config['MemorySwap'] = memswap_limit
400+
390401
if pid_mode not in (None, 'host'):
391402
raise errors.DockerException(
392403
'Invalid value for pid param: {0}'.format(pid_mode)
@@ -503,10 +514,10 @@ def create_host_config(
503514

504515
def create_container_config(
505516
version, image, command, hostname=None, user=None, detach=False,
506-
stdin_open=False, tty=False, mem_limit=0, ports=None, environment=None,
517+
stdin_open=False, tty=False, mem_limit=None, ports=None, environment=None,
507518
dns=None, volumes=None, volumes_from=None, network_disabled=False,
508519
entrypoint=None, cpu_shares=None, working_dir=None, domainname=None,
509-
memswap_limit=0, cpuset=None, host_config=None, mac_address=None,
520+
memswap_limit=None, cpuset=None, host_config=None, mac_address=None,
510521
labels=None, volume_driver=None
511522
):
512523
if isinstance(command, six.string_types):
@@ -522,10 +533,24 @@ def create_container_config(
522533
'labels were only introduced in API version 1.18'
523534
)
524535

525-
if volume_driver is not None and compare_version('1.19', version) < 0:
526-
raise errors.InvalidVersion(
527-
'Volume drivers were only introduced in API version 1.19'
528-
)
536+
if compare_version('1.19', version) < 0:
537+
if volume_driver is not None:
538+
raise errors.InvalidVersion(
539+
'Volume drivers were only introduced in API version 1.19'
540+
)
541+
mem_limit = mem_limit if mem_limit is not None else 0
542+
memswap_limit = memswap_limit if memswap_limit is not None else 0
543+
else:
544+
if mem_limit is not None:
545+
raise errors.InvalidVersion(
546+
'mem_limit has been moved to host_config in API version 1.19'
547+
)
548+
549+
if memswap_limit is not None:
550+
raise errors.InvalidVersion(
551+
'memswap_limit has been moved to host_config in API '
552+
'version 1.19'
553+
)
529554

530555
if isinstance(labels, list):
531556
labels = dict((lbl, six.text_type('')) for lbl in labels)

tests/test.py

Lines changed: 56 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,10 @@ def base_create_payload(self, img='busybox', cmd=None):
124124
if not cmd:
125125
cmd = ['true']
126126
return {"Tty": False, "Image": img, "Cmd": cmd,
127-
"AttachStdin": False, "Memory": 0,
127+
"AttachStdin": False,
128128
"AttachStderr": True, "AttachStdout": True,
129129
"StdinOnce": False,
130130
"OpenStdin": False, "NetworkDisabled": False,
131-
"MemorySwap": 0
132131
}
133132

134133
def test_ctor(self):
@@ -337,11 +336,10 @@ def test_create_container(self):
337336
self.assertEqual(json.loads(args[1]['data']),
338337
json.loads('''
339338
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
340-
"AttachStdin": false, "Memory": 0,
339+
"AttachStdin": false,
341340
"AttachStderr": true, "AttachStdout": true,
342341
"StdinOnce": false,
343-
"OpenStdin": false, "NetworkDisabled": false,
344-
"MemorySwap": 0}'''))
342+
"OpenStdin": false, "NetworkDisabled": false}'''))
345343
self.assertEqual(args[1]['headers'],
346344
{'Content-Type': 'application/json'})
347345

@@ -361,12 +359,11 @@ def test_create_container_with_binds(self):
361359
json.loads('''
362360
{"Tty": false, "Image": "busybox",
363361
"Cmd": ["ls", "/mnt"], "AttachStdin": false,
364-
"Volumes": {"/mnt": {}}, "Memory": 0,
362+
"Volumes": {"/mnt": {}},
365363
"AttachStderr": true,
366364
"AttachStdout": true, "OpenStdin": false,
367365
"StdinOnce": false,
368-
"NetworkDisabled": false,
369-
"MemorySwap": 0}'''))
366+
"NetworkDisabled": false}'''))
370367
self.assertEqual(args[1]['headers'],
371368
{'Content-Type': 'application/json'})
372369

@@ -386,12 +383,11 @@ def test_create_container_with_volume_string(self):
386383
json.loads('''
387384
{"Tty": false, "Image": "busybox",
388385
"Cmd": ["ls", "/mnt"], "AttachStdin": false,
389-
"Volumes": {"/mnt": {}}, "Memory": 0,
386+
"Volumes": {"/mnt": {}},
390387
"AttachStderr": true,
391388
"AttachStdout": true, "OpenStdin": false,
392389
"StdinOnce": false,
393-
"NetworkDisabled": false,
394-
"MemorySwap": 0}'''))
390+
"NetworkDisabled": false}'''))
395391
self.assertEqual(args[1]['headers'],
396392
{'Content-Type': 'application/json'})
397393

@@ -409,16 +405,15 @@ def test_create_container_with_ports(self):
409405
json.loads('''
410406
{"Tty": false, "Image": "busybox",
411407
"Cmd": ["ls"], "AttachStdin": false,
412-
"Memory": 0, "ExposedPorts": {
408+
"ExposedPorts": {
413409
"1111/tcp": {},
414410
"2222/udp": {},
415411
"3333/tcp": {}
416412
},
417413
"AttachStderr": true,
418414
"AttachStdout": true, "OpenStdin": false,
419415
"StdinOnce": false,
420-
"NetworkDisabled": false,
421-
"MemorySwap": 0}'''))
416+
"NetworkDisabled": false}'''))
422417
self.assertEqual(args[1]['headers'],
423418
{'Content-Type': 'application/json'})
424419

@@ -436,13 +431,11 @@ def test_create_container_with_entrypoint(self):
436431
json.loads('''
437432
{"Tty": false, "Image": "busybox",
438433
"Cmd": ["hello"], "AttachStdin": false,
439-
"Memory": 0,
440434
"AttachStderr": true,
441435
"AttachStdout": true, "OpenStdin": false,
442436
"StdinOnce": false,
443437
"NetworkDisabled": false,
444-
"Entrypoint": "cowsay",
445-
"MemorySwap": 0}'''))
438+
"Entrypoint": "cowsay"}'''))
446439
self.assertEqual(args[1]['headers'],
447440
{'Content-Type': 'application/json'})
448441

@@ -460,13 +453,11 @@ def test_create_container_with_cpu_shares(self):
460453
json.loads('''
461454
{"Tty": false, "Image": "busybox",
462455
"Cmd": ["ls"], "AttachStdin": false,
463-
"Memory": 0,
464456
"AttachStderr": true,
465457
"AttachStdout": true, "OpenStdin": false,
466458
"StdinOnce": false,
467459
"NetworkDisabled": false,
468-
"CpuShares": 5,
469-
"MemorySwap": 0}'''))
460+
"CpuShares": 5}'''))
470461
self.assertEqual(args[1]['headers'],
471462
{'Content-Type': 'application/json'})
472463

@@ -484,14 +475,12 @@ def test_create_container_with_cpuset(self):
484475
json.loads('''
485476
{"Tty": false, "Image": "busybox",
486477
"Cmd": ["ls"], "AttachStdin": false,
487-
"Memory": 0,
488478
"AttachStderr": true,
489479
"AttachStdout": true, "OpenStdin": false,
490480
"StdinOnce": false,
491481
"NetworkDisabled": false,
492482
"Cpuset": "0,1",
493-
"CpusetCpus": "0,1",
494-
"MemorySwap": 0}'''))
483+
"CpusetCpus": "0,1"}'''))
495484
self.assertEqual(args[1]['headers'],
496485
{'Content-Type': 'application/json'})
497486

@@ -509,13 +498,11 @@ def test_create_container_with_working_dir(self):
509498
json.loads('''
510499
{"Tty": false, "Image": "busybox",
511500
"Cmd": ["ls"], "AttachStdin": false,
512-
"Memory": 0,
513501
"AttachStderr": true,
514502
"AttachStdout": true, "OpenStdin": false,
515503
"StdinOnce": false,
516504
"NetworkDisabled": false,
517-
"WorkingDir": "/root",
518-
"MemorySwap": 0}'''))
505+
"WorkingDir": "/root"}'''))
519506
self.assertEqual(args[1]['headers'],
520507
{'Content-Type': 'application/json'})
521508

@@ -531,11 +518,10 @@ def test_create_container_with_stdin_open(self):
531518
self.assertEqual(json.loads(args[1]['data']),
532519
json.loads('''
533520
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
534-
"AttachStdin": true, "Memory": 0,
521+
"AttachStdin": true,
535522
"AttachStderr": true, "AttachStdout": true,
536523
"StdinOnce": true,
537-
"OpenStdin": true, "NetworkDisabled": false,
538-
"MemorySwap": 0}'''))
524+
"OpenStdin": true, "NetworkDisabled": false}'''))
539525
self.assertEqual(args[1]['headers'],
540526
{'Content-Type': 'application/json'})
541527

@@ -581,78 +567,95 @@ def test_create_named_container(self):
581567
self.assertEqual(json.loads(args[1]['data']),
582568
json.loads('''
583569
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
584-
"AttachStdin": false, "Memory": 0,
570+
"AttachStdin": false,
585571
"AttachStderr": true, "AttachStdout": true,
586572
"StdinOnce": false,
587-
"OpenStdin": false, "NetworkDisabled": false,
588-
"MemorySwap": 0}'''))
573+
"OpenStdin": false, "NetworkDisabled": false}'''))
589574
self.assertEqual(args[1]['headers'],
590575
{'Content-Type': 'application/json'})
591576
self.assertEqual(args[1]['params'], {'name': 'marisa-kirisame'})
592577

593578
def test_create_container_with_mem_limit_as_int(self):
594579
try:
595-
self.client.create_container('busybox', 'true',
596-
mem_limit=128.0)
580+
self.client.create_container(
581+
'busybox', 'true', host_config=create_host_config(
582+
mem_limit=128.0
583+
)
584+
)
597585
except Exception as e:
598586
self.fail('Command should not raise exception: {0}'.format(e))
599587

600588
args = fake_request.call_args
601589
data = json.loads(args[1]['data'])
602-
self.assertEqual(data['Memory'], 128.0)
590+
self.assertEqual(data['HostConfig']['Memory'], 128.0)
603591

604592
def test_create_container_with_mem_limit_as_string(self):
605593
try:
606-
self.client.create_container('busybox', 'true',
607-
mem_limit='128')
594+
self.client.create_container(
595+
'busybox', 'true', host_config=create_host_config(
596+
mem_limit='128'
597+
)
598+
)
608599
except Exception as e:
609600
self.fail('Command should not raise exception: {0}'.format(e))
610601

611602
args = fake_request.call_args
612603
data = json.loads(args[1]['data'])
613-
self.assertEqual(data['Memory'], 128.0)
604+
self.assertEqual(data['HostConfig']['Memory'], 128.0)
614605

615606
def test_create_container_with_mem_limit_as_string_with_k_unit(self):
616607
try:
617-
self.client.create_container('busybox', 'true',
618-
mem_limit='128k')
608+
self.client.create_container(
609+
'busybox', 'true', host_config=create_host_config(
610+
mem_limit='128k'
611+
)
612+
)
619613
except Exception as e:
620614
self.fail('Command should not raise exception: {0}'.format(e))
621615

622616
args = fake_request.call_args
623617
data = json.loads(args[1]['data'])
624-
self.assertEqual(data['Memory'], 128.0 * 1024)
618+
self.assertEqual(data['HostConfig']['Memory'], 128.0 * 1024)
625619

626620
def test_create_container_with_mem_limit_as_string_with_m_unit(self):
627621
try:
628-
self.client.create_container('busybox', 'true',
629-
mem_limit='128m')
622+
self.client.create_container(
623+
'busybox', 'true', host_config=create_host_config(
624+
mem_limit='128m'
625+
)
626+
)
627+
630628
except Exception as e:
631629
self.fail('Command should not raise exception: {0}'.format(e))
632630

633631
args = fake_request.call_args
634632
data = json.loads(args[1]['data'])
635-
self.assertEqual(data['Memory'], 128.0 * 1024 * 1024)
633+
self.assertEqual(data['HostConfig']['Memory'], 128.0 * 1024 * 1024)
636634

637635
def test_create_container_with_mem_limit_as_string_with_g_unit(self):
638636
try:
639-
self.client.create_container('busybox', 'true',
640-
mem_limit='128g')
637+
self.client.create_container(
638+
'busybox', 'true', host_config=create_host_config(
639+
mem_limit='128g'
640+
)
641+
)
641642
except Exception as e:
642643
self.fail('Command should not raise exception: {0}'.format(e))
643644

644645
args = fake_request.call_args
645646
data = json.loads(args[1]['data'])
646-
self.assertEqual(data['Memory'], 128.0 * 1024 * 1024 * 1024)
647+
self.assertEqual(
648+
data['HostConfig']['Memory'], 128.0 * 1024 * 1024 * 1024
649+
)
647650

648651
def test_create_container_with_mem_limit_as_string_with_wrong_value(self):
649-
self.assertRaises(docker.errors.DockerException,
650-
self.client.create_container,
651-
'busybox', 'true', mem_limit='128p')
652+
self.assertRaises(
653+
docker.errors.DockerException, create_host_config, mem_limit='128p'
654+
)
652655

653-
self.assertRaises(docker.errors.DockerException,
654-
self.client.create_container,
655-
'busybox', 'true', mem_limit='1f28')
656+
self.assertRaises(
657+
docker.errors.DockerException, create_host_config, mem_limit='1f28'
658+
)
656659

657660
def test_start_container(self):
658661
try:

0 commit comments

Comments
 (0)