Skip to content

Commit

Permalink
Merge pull request docker#644 from docker/memory-memswap-hostconfig
Browse files Browse the repository at this point in the history
memory / memswap in hostconfig
  • Loading branch information
shin- committed Jun 30, 2015
2 parents c8c957c + a12ba1a commit ac90a87
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 63 deletions.
6 changes: 3 additions & 3 deletions docker/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,11 +450,11 @@ def copy(self, container, resource):

def create_container(self, image, command=None, hostname=None, user=None,
detach=False, stdin_open=False, tty=False,
mem_limit=0, ports=None, environment=None, dns=None,
volumes=None, volumes_from=None,
mem_limit=None, ports=None, environment=None,
dns=None, volumes=None, volumes_from=None,
network_disabled=False, name=None, entrypoint=None,
cpu_shares=None, working_dir=None, domainname=None,
memswap_limit=0, cpuset=None, host_config=None,
memswap_limit=None, cpuset=None, host_config=None,
mac_address=None, labels=None, volume_driver=None):

if isinstance(volumes, six.string_types):
Expand Down
39 changes: 32 additions & 7 deletions docker/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,21 @@ def create_host_config(
dns=None, dns_search=None, volumes_from=None, network_mode=None,
restart_policy=None, cap_add=None, cap_drop=None, devices=None,
extra_hosts=None, read_only=None, pid_mode=None, ipc_mode=None,
security_opt=None, ulimits=None, log_config=None
security_opt=None, ulimits=None, log_config=None, mem_limit=None,
memswap_limit=None
):
host_config = {}

if mem_limit is not None:
if isinstance(mem_limit, six.string_types):
mem_limit = parse_bytes(mem_limit)
host_config['Memory'] = 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

if pid_mode not in (None, 'host'):
raise errors.DockerException(
'Invalid value for pid param: {0}'.format(pid_mode)
Expand Down Expand Up @@ -503,10 +514,10 @@ def create_host_config(

def create_container_config(
version, image, command, hostname=None, user=None, detach=False,
stdin_open=False, tty=False, mem_limit=0, ports=None, environment=None,
stdin_open=False, tty=False, mem_limit=None, ports=None, environment=None,
dns=None, volumes=None, volumes_from=None, network_disabled=False,
entrypoint=None, cpu_shares=None, working_dir=None, domainname=None,
memswap_limit=0, cpuset=None, host_config=None, mac_address=None,
memswap_limit=None, cpuset=None, host_config=None, mac_address=None,
labels=None, volume_driver=None
):
if isinstance(command, six.string_types):
Expand All @@ -522,10 +533,24 @@ def create_container_config(
'labels were only introduced in API version 1.18'
)

if volume_driver is not None and compare_version('1.19', version) < 0:
raise errors.InvalidVersion(
'Volume drivers were only introduced in API version 1.19'
)
if compare_version('1.19', version) < 0:
if volume_driver is not None:
raise errors.InvalidVersion(
'Volume drivers were only introduced in API version 1.19'
)
mem_limit = mem_limit if mem_limit is not None else 0
memswap_limit = memswap_limit if memswap_limit is not None else 0
else:
if mem_limit is not None:
raise errors.InvalidVersion(
'mem_limit has been moved to host_config in API version 1.19'
)

if memswap_limit is not None:
raise errors.InvalidVersion(
'memswap_limit has been moved to host_config in API '
'version 1.19'
)

if isinstance(labels, list):
labels = dict((lbl, six.text_type('')) for lbl in labels)
Expand Down
109 changes: 56 additions & 53 deletions tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,10 @@ def base_create_payload(self, img='busybox', cmd=None):
if not cmd:
cmd = ['true']
return {"Tty": False, "Image": img, "Cmd": cmd,
"AttachStdin": False, "Memory": 0,
"AttachStdin": False,
"AttachStderr": True, "AttachStdout": True,
"StdinOnce": False,
"OpenStdin": False, "NetworkDisabled": False,
"MemorySwap": 0
}

def test_ctor(self):
Expand Down Expand Up @@ -337,11 +336,10 @@ def test_create_container(self):
self.assertEqual(json.loads(args[1]['data']),
json.loads('''
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
"AttachStdin": false, "Memory": 0,
"AttachStdin": false,
"AttachStderr": true, "AttachStdout": true,
"StdinOnce": false,
"OpenStdin": false, "NetworkDisabled": false,
"MemorySwap": 0}'''))
"OpenStdin": false, "NetworkDisabled": false}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -361,12 +359,11 @@ def test_create_container_with_binds(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["ls", "/mnt"], "AttachStdin": false,
"Volumes": {"/mnt": {}}, "Memory": 0,
"Volumes": {"/mnt": {}},
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"MemorySwap": 0}'''))
"NetworkDisabled": false}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -386,12 +383,11 @@ def test_create_container_with_volume_string(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["ls", "/mnt"], "AttachStdin": false,
"Volumes": {"/mnt": {}}, "Memory": 0,
"Volumes": {"/mnt": {}},
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"MemorySwap": 0}'''))
"NetworkDisabled": false}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -409,16 +405,15 @@ def test_create_container_with_ports(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["ls"], "AttachStdin": false,
"Memory": 0, "ExposedPorts": {
"ExposedPorts": {
"1111/tcp": {},
"2222/udp": {},
"3333/tcp": {}
},
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"MemorySwap": 0}'''))
"NetworkDisabled": false}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -436,13 +431,11 @@ def test_create_container_with_entrypoint(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["hello"], "AttachStdin": false,
"Memory": 0,
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"Entrypoint": "cowsay",
"MemorySwap": 0}'''))
"Entrypoint": "cowsay"}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -460,13 +453,11 @@ def test_create_container_with_cpu_shares(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["ls"], "AttachStdin": false,
"Memory": 0,
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"CpuShares": 5,
"MemorySwap": 0}'''))
"CpuShares": 5}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -484,14 +475,12 @@ def test_create_container_with_cpuset(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["ls"], "AttachStdin": false,
"Memory": 0,
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"Cpuset": "0,1",
"CpusetCpus": "0,1",
"MemorySwap": 0}'''))
"CpusetCpus": "0,1"}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -509,13 +498,11 @@ def test_create_container_with_working_dir(self):
json.loads('''
{"Tty": false, "Image": "busybox",
"Cmd": ["ls"], "AttachStdin": false,
"Memory": 0,
"AttachStderr": true,
"AttachStdout": true, "OpenStdin": false,
"StdinOnce": false,
"NetworkDisabled": false,
"WorkingDir": "/root",
"MemorySwap": 0}'''))
"WorkingDir": "/root"}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand All @@ -531,11 +518,10 @@ def test_create_container_with_stdin_open(self):
self.assertEqual(json.loads(args[1]['data']),
json.loads('''
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
"AttachStdin": true, "Memory": 0,
"AttachStdin": true,
"AttachStderr": true, "AttachStdout": true,
"StdinOnce": true,
"OpenStdin": true, "NetworkDisabled": false,
"MemorySwap": 0}'''))
"OpenStdin": true, "NetworkDisabled": false}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})

Expand Down Expand Up @@ -581,78 +567,95 @@ def test_create_named_container(self):
self.assertEqual(json.loads(args[1]['data']),
json.loads('''
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
"AttachStdin": false, "Memory": 0,
"AttachStdin": false,
"AttachStderr": true, "AttachStdout": true,
"StdinOnce": false,
"OpenStdin": false, "NetworkDisabled": false,
"MemorySwap": 0}'''))
"OpenStdin": false, "NetworkDisabled": false}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
self.assertEqual(args[1]['params'], {'name': 'marisa-kirisame'})

def test_create_container_with_mem_limit_as_int(self):
try:
self.client.create_container('busybox', 'true',
mem_limit=128.0)
self.client.create_container(
'busybox', 'true', host_config=create_host_config(
mem_limit=128.0
)
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))

args = fake_request.call_args
data = json.loads(args[1]['data'])
self.assertEqual(data['Memory'], 128.0)
self.assertEqual(data['HostConfig']['Memory'], 128.0)

def test_create_container_with_mem_limit_as_string(self):
try:
self.client.create_container('busybox', 'true',
mem_limit='128')
self.client.create_container(
'busybox', 'true', host_config=create_host_config(
mem_limit='128'
)
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))

args = fake_request.call_args
data = json.loads(args[1]['data'])
self.assertEqual(data['Memory'], 128.0)
self.assertEqual(data['HostConfig']['Memory'], 128.0)

def test_create_container_with_mem_limit_as_string_with_k_unit(self):
try:
self.client.create_container('busybox', 'true',
mem_limit='128k')
self.client.create_container(
'busybox', 'true', host_config=create_host_config(
mem_limit='128k'
)
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))

args = fake_request.call_args
data = json.loads(args[1]['data'])
self.assertEqual(data['Memory'], 128.0 * 1024)
self.assertEqual(data['HostConfig']['Memory'], 128.0 * 1024)

def test_create_container_with_mem_limit_as_string_with_m_unit(self):
try:
self.client.create_container('busybox', 'true',
mem_limit='128m')
self.client.create_container(
'busybox', 'true', host_config=create_host_config(
mem_limit='128m'
)
)

except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))

args = fake_request.call_args
data = json.loads(args[1]['data'])
self.assertEqual(data['Memory'], 128.0 * 1024 * 1024)
self.assertEqual(data['HostConfig']['Memory'], 128.0 * 1024 * 1024)

def test_create_container_with_mem_limit_as_string_with_g_unit(self):
try:
self.client.create_container('busybox', 'true',
mem_limit='128g')
self.client.create_container(
'busybox', 'true', host_config=create_host_config(
mem_limit='128g'
)
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))

args = fake_request.call_args
data = json.loads(args[1]['data'])
self.assertEqual(data['Memory'], 128.0 * 1024 * 1024 * 1024)
self.assertEqual(
data['HostConfig']['Memory'], 128.0 * 1024 * 1024 * 1024
)

def test_create_container_with_mem_limit_as_string_with_wrong_value(self):
self.assertRaises(docker.errors.DockerException,
self.client.create_container,
'busybox', 'true', mem_limit='128p')
self.assertRaises(
docker.errors.DockerException, create_host_config, mem_limit='128p'
)

self.assertRaises(docker.errors.DockerException,
self.client.create_container,
'busybox', 'true', mem_limit='1f28')
self.assertRaises(
docker.errors.DockerException, create_host_config, mem_limit='1f28'
)

def test_start_container(self):
try:
Expand Down

0 comments on commit ac90a87

Please sign in to comment.