summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAanand Prasad <aanand.prasad@gmail.com>2015-09-25 09:52:38 +0200
committerAanand Prasad <aanand.prasad@gmail.com>2015-09-25 09:52:38 +0200
commit26e22bbd391c9712db643d85087a5113d11c6c82 (patch)
treea464861a0fc2c684b3730a347e80d72997075707
parent02f330d8dc3da47215bed47b44fac73941ea6920 (diff)
parent3c5185c199a0ac52c58eeca5ef9e2133e0f4803e (diff)
downloaddocker-py-26e22bbd391c9712db643d85087a5113d11c6c82.tar.gz
Merge pull request #770 from docker/cpu_cfs_opts_support
Support for cpu_quota and cpu_period
-rw-r--r--docker/utils/utils.py29
-rw-r--r--tests/utils_test.py279
2 files changed, 182 insertions, 126 deletions
diff --git a/docker/utils/utils.py b/docker/utils/utils.py
index 46b3516..36edf8d 100644
--- a/docker/utils/utils.py
+++ b/docker/utils/utils.py
@@ -457,7 +457,8 @@ def create_host_config(
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, mem_limit=None,
- memswap_limit=None, cgroup_parent=None, group_add=None, version=None
+ memswap_limit=None, cgroup_parent=None, group_add=None, cpu_quota=None,
+ cpu_period=None, version=None
):
host_config = {}
@@ -518,7 +519,7 @@ def create_host_config(
host_config['Devices'] = parse_devices(devices)
if group_add:
- if compare_version(version, '1.20') < 0:
+ if version_lt(version, '1.20'):
raise errors.InvalidVersion(
'group_add param not supported for API version < 1.20'
)
@@ -601,6 +602,30 @@ def create_host_config(
log_config = LogConfig(**log_config)
host_config['LogConfig'] = log_config
+ if cpu_quota:
+ if not isinstance(cpu_quota, int):
+ raise TypeError(
+ 'Invalid type for cpu_quota param: expected int but'
+ ' found {0}'.format(type(cpu_quota))
+ )
+ if version_lt(version, '1.19'):
+ raise errors.InvalidVersion(
+ 'cpu_quota param not supported for API version < 1.19'
+ )
+ host_config['CpuQuota'] = cpu_quota
+
+ if cpu_period:
+ if not isinstance(cpu_period, int):
+ raise TypeError(
+ 'Invalid type for cpu_period param: expected int but'
+ ' found {0}'.format(type(cpu_period))
+ )
+ if version_lt(version, '1.19'):
+ raise errors.InvalidVersion(
+ 'cpu_period param not supported for API version < 1.19'
+ )
+ host_config['CpuPeriod'] = cpu_period
+
return host_config
diff --git a/tests/utils_test.py b/tests/utils_test.py
index b67ac4e..45929f7 100644
--- a/tests/utils_test.py
+++ b/tests/utils_test.py
@@ -25,6 +25,159 @@ TEST_CERT_DIR = os.path.join(
)
+class HostConfigTest(base.BaseTestCase):
+ def test_create_host_config_no_options(self):
+ config = create_host_config(version='1.19')
+ self.assertFalse('NetworkMode' in config)
+
+ def test_create_host_config_no_options_newer_api_version(self):
+ config = create_host_config(version='1.20')
+ self.assertEqual(config['NetworkMode'], 'default')
+
+ def test_create_host_config_invalid_cpu_cfs_types(self):
+ with pytest.raises(TypeError):
+ create_host_config(version='1.20', cpu_quota='0')
+
+ with pytest.raises(TypeError):
+ create_host_config(version='1.20', cpu_period='0')
+
+ with pytest.raises(TypeError):
+ create_host_config(version='1.20', cpu_quota=23.11)
+
+ with pytest.raises(TypeError):
+ create_host_config(version='1.20', cpu_period=1999.0)
+
+ def test_create_host_config_with_cpu_quota(self):
+ config = create_host_config(version='1.20', cpu_quota=1999)
+ self.assertEqual(config.get('CpuQuota'), 1999)
+
+ def test_create_host_config_with_cpu_period(self):
+ config = create_host_config(version='1.20', cpu_period=1999)
+ self.assertEqual(config.get('CpuPeriod'), 1999)
+
+
+class UlimitTest(base.BaseTestCase):
+ def test_create_host_config_dict_ulimit(self):
+ ulimit_dct = {'name': 'nofile', 'soft': 8096}
+ config = create_host_config(
+ ulimits=[ulimit_dct], version=DEFAULT_DOCKER_API_VERSION
+ )
+ self.assertIn('Ulimits', config)
+ self.assertEqual(len(config['Ulimits']), 1)
+ ulimit_obj = config['Ulimits'][0]
+ self.assertTrue(isinstance(ulimit_obj, Ulimit))
+ self.assertEqual(ulimit_obj.name, ulimit_dct['name'])
+ self.assertEqual(ulimit_obj.soft, ulimit_dct['soft'])
+ self.assertEqual(ulimit_obj['Soft'], ulimit_obj.soft)
+
+ def test_create_host_config_dict_ulimit_capitals(self):
+ ulimit_dct = {'Name': 'nofile', 'Soft': 8096, 'Hard': 8096 * 4}
+ config = create_host_config(
+ ulimits=[ulimit_dct], version=DEFAULT_DOCKER_API_VERSION
+ )
+ self.assertIn('Ulimits', config)
+ self.assertEqual(len(config['Ulimits']), 1)
+ ulimit_obj = config['Ulimits'][0]
+ self.assertTrue(isinstance(ulimit_obj, Ulimit))
+ self.assertEqual(ulimit_obj.name, ulimit_dct['Name'])
+ self.assertEqual(ulimit_obj.soft, ulimit_dct['Soft'])
+ self.assertEqual(ulimit_obj.hard, ulimit_dct['Hard'])
+ self.assertEqual(ulimit_obj['Soft'], ulimit_obj.soft)
+
+ def test_create_host_config_obj_ulimit(self):
+ ulimit_dct = Ulimit(name='nofile', soft=8096)
+ config = create_host_config(
+ ulimits=[ulimit_dct], version=DEFAULT_DOCKER_API_VERSION
+ )
+ self.assertIn('Ulimits', config)
+ self.assertEqual(len(config['Ulimits']), 1)
+ ulimit_obj = config['Ulimits'][0]
+ self.assertTrue(isinstance(ulimit_obj, Ulimit))
+ self.assertEqual(ulimit_obj, ulimit_dct)
+
+ def test_ulimit_invalid_type(self):
+ self.assertRaises(ValueError, lambda: Ulimit(name=None))
+ self.assertRaises(ValueError, lambda: Ulimit(name='hello', soft='123'))
+ self.assertRaises(ValueError, lambda: Ulimit(name='hello', hard='456'))
+
+
+class LogConfigTest(base.BaseTestCase):
+ def test_create_host_config_dict_logconfig(self):
+ dct = {'type': LogConfig.types.SYSLOG, 'config': {'key1': 'val1'}}
+ config = create_host_config(
+ version=DEFAULT_DOCKER_API_VERSION, log_config=dct
+ )
+ self.assertIn('LogConfig', config)
+ self.assertTrue(isinstance(config['LogConfig'], LogConfig))
+ self.assertEqual(dct['type'], config['LogConfig'].type)
+
+ def test_create_host_config_obj_logconfig(self):
+ obj = LogConfig(type=LogConfig.types.SYSLOG, config={'key1': 'val1'})
+ config = create_host_config(
+ version=DEFAULT_DOCKER_API_VERSION, log_config=obj
+ )
+ self.assertIn('LogConfig', config)
+ self.assertTrue(isinstance(config['LogConfig'], LogConfig))
+ self.assertEqual(obj, config['LogConfig'])
+
+ def test_logconfig_invalid_config_type(self):
+ with pytest.raises(ValueError):
+ LogConfig(type=LogConfig.types.JSON, config='helloworld')
+
+
+class KwargsFromEnvTest(base.BaseTestCase):
+ def setUp(self):
+ self.os_environ = os.environ.copy()
+
+ def tearDown(self):
+ os.environ = self.os_environ
+
+ def test_kwargs_from_env_empty(self):
+ os.environ.update(DOCKER_HOST='',
+ DOCKER_CERT_PATH='',
+ DOCKER_TLS_VERIFY='')
+
+ kwargs = kwargs_from_env()
+ self.assertEqual(None, kwargs.get('base_url'))
+ self.assertEqual(None, kwargs.get('tls'))
+
+ def test_kwargs_from_env_tls(self):
+ os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
+ DOCKER_CERT_PATH=TEST_CERT_DIR,
+ DOCKER_TLS_VERIFY='1')
+ kwargs = kwargs_from_env(assert_hostname=False)
+ self.assertEqual('https://192.168.59.103:2376', kwargs['base_url'])
+ self.assertTrue('ca.pem' in kwargs['tls'].verify)
+ self.assertTrue('cert.pem' in kwargs['tls'].cert[0])
+ self.assertTrue('key.pem' in kwargs['tls'].cert[1])
+ self.assertEqual(False, kwargs['tls'].assert_hostname)
+ try:
+ client = Client(**kwargs)
+ self.assertEqual(kwargs['base_url'], client.base_url)
+ self.assertEqual(kwargs['tls'].verify, client.verify)
+ self.assertEqual(kwargs['tls'].cert, client.cert)
+ except TypeError as e:
+ self.fail(e)
+
+ def test_kwargs_from_env_no_cert_path(self):
+ try:
+ temp_dir = tempfile.mkdtemp()
+ cert_dir = os.path.join(temp_dir, '.docker')
+ shutil.copytree(TEST_CERT_DIR, cert_dir)
+
+ os.environ.update(HOME=temp_dir,
+ DOCKER_CERT_PATH='',
+ DOCKER_TLS_VERIFY='1')
+
+ kwargs = kwargs_from_env()
+ self.assertIn(cert_dir, kwargs['tls'].verify)
+ self.assertIn(cert_dir, kwargs['tls'].cert[0])
+ self.assertIn(cert_dir, kwargs['tls'].cert[1])
+ finally:
+ if temp_dir:
+ shutil.rmtree(temp_dir)
+
+
class UtilsTest(base.BaseTestCase):
longMessage = True
@@ -39,12 +192,6 @@ class UtilsTest(base.BaseTestCase):
local_tempfile.close()
return local_tempfile.name
- def setUp(self):
- self.os_environ = os.environ.copy()
-
- def tearDown(self):
- os.environ = self.os_environ
-
def test_parse_repository_tag(self):
self.assertEqual(parse_repository_tag("root"),
("root", None))
@@ -103,51 +250,6 @@ class UtilsTest(base.BaseTestCase):
assert parse_host(val, 'win32') == tcp_port
- def test_kwargs_from_env_empty(self):
- os.environ.update(DOCKER_HOST='',
- DOCKER_CERT_PATH='',
- DOCKER_TLS_VERIFY='')
-
- kwargs = kwargs_from_env()
- self.assertEqual(None, kwargs.get('base_url'))
- self.assertEqual(None, kwargs.get('tls'))
-
- def test_kwargs_from_env_tls(self):
- os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
- DOCKER_CERT_PATH=TEST_CERT_DIR,
- DOCKER_TLS_VERIFY='1')
- kwargs = kwargs_from_env(assert_hostname=False)
- self.assertEqual('https://192.168.59.103:2376', kwargs['base_url'])
- self.assertTrue('ca.pem' in kwargs['tls'].verify)
- self.assertTrue('cert.pem' in kwargs['tls'].cert[0])
- self.assertTrue('key.pem' in kwargs['tls'].cert[1])
- self.assertEqual(False, kwargs['tls'].assert_hostname)
- try:
- client = Client(**kwargs)
- self.assertEqual(kwargs['base_url'], client.base_url)
- self.assertEqual(kwargs['tls'].verify, client.verify)
- self.assertEqual(kwargs['tls'].cert, client.cert)
- except TypeError as e:
- self.fail(e)
-
- def test_kwargs_from_env_no_cert_path(self):
- try:
- temp_dir = tempfile.mkdtemp()
- cert_dir = os.path.join(temp_dir, '.docker')
- shutil.copytree(TEST_CERT_DIR, cert_dir)
-
- os.environ.update(HOME=temp_dir,
- DOCKER_CERT_PATH='',
- DOCKER_TLS_VERIFY='1')
-
- kwargs = kwargs_from_env()
- self.assertIn(cert_dir, kwargs['tls'].verify)
- self.assertIn(cert_dir, kwargs['tls'].cert[0])
- self.assertIn(cert_dir, kwargs['tls'].cert[1])
- finally:
- if temp_dir:
- shutil.rmtree(temp_dir)
-
def test_parse_env_file_proper(self):
env_file = self.generate_tempfile(
file_content='USER=jdoe\nPASS=secret')
@@ -181,79 +283,6 @@ class UtilsTest(base.BaseTestCase):
for filters, expected in tests:
self.assertEqual(convert_filters(filters), expected)
- def test_create_host_config_no_options(self):
- config = create_host_config(version='1.19')
- self.assertFalse('NetworkMode' in config)
-
- def test_create_host_config_no_options_newer_api_version(self):
- config = create_host_config(version='1.20')
- self.assertEqual(config['NetworkMode'], 'default')
-
- def test_create_host_config_dict_ulimit(self):
- ulimit_dct = {'name': 'nofile', 'soft': 8096}
- config = create_host_config(
- ulimits=[ulimit_dct], version=DEFAULT_DOCKER_API_VERSION
- )
- self.assertIn('Ulimits', config)
- self.assertEqual(len(config['Ulimits']), 1)
- ulimit_obj = config['Ulimits'][0]
- self.assertTrue(isinstance(ulimit_obj, Ulimit))
- self.assertEqual(ulimit_obj.name, ulimit_dct['name'])
- self.assertEqual(ulimit_obj.soft, ulimit_dct['soft'])
- self.assertEqual(ulimit_obj['Soft'], ulimit_obj.soft)
-
- def test_create_host_config_dict_ulimit_capitals(self):
- ulimit_dct = {'Name': 'nofile', 'Soft': 8096, 'Hard': 8096 * 4}
- config = create_host_config(
- ulimits=[ulimit_dct], version=DEFAULT_DOCKER_API_VERSION
- )
- self.assertIn('Ulimits', config)
- self.assertEqual(len(config['Ulimits']), 1)
- ulimit_obj = config['Ulimits'][0]
- self.assertTrue(isinstance(ulimit_obj, Ulimit))
- self.assertEqual(ulimit_obj.name, ulimit_dct['Name'])
- self.assertEqual(ulimit_obj.soft, ulimit_dct['Soft'])
- self.assertEqual(ulimit_obj.hard, ulimit_dct['Hard'])
- self.assertEqual(ulimit_obj['Soft'], ulimit_obj.soft)
-
- def test_create_host_config_obj_ulimit(self):
- ulimit_dct = Ulimit(name='nofile', soft=8096)
- config = create_host_config(
- ulimits=[ulimit_dct], version=DEFAULT_DOCKER_API_VERSION
- )
- self.assertIn('Ulimits', config)
- self.assertEqual(len(config['Ulimits']), 1)
- ulimit_obj = config['Ulimits'][0]
- self.assertTrue(isinstance(ulimit_obj, Ulimit))
- self.assertEqual(ulimit_obj, ulimit_dct)
-
- def test_ulimit_invalid_type(self):
- self.assertRaises(ValueError, lambda: Ulimit(name=None))
- self.assertRaises(ValueError, lambda: Ulimit(name='hello', soft='123'))
- self.assertRaises(ValueError, lambda: Ulimit(name='hello', hard='456'))
-
- def test_create_host_config_dict_logconfig(self):
- dct = {'type': LogConfig.types.SYSLOG, 'config': {'key1': 'val1'}}
- config = create_host_config(
- version=DEFAULT_DOCKER_API_VERSION, log_config=dct
- )
- self.assertIn('LogConfig', config)
- self.assertTrue(isinstance(config['LogConfig'], LogConfig))
- self.assertEqual(dct['type'], config['LogConfig'].type)
-
- def test_create_host_config_obj_logconfig(self):
- obj = LogConfig(type=LogConfig.types.SYSLOG, config={'key1': 'val1'})
- config = create_host_config(
- version=DEFAULT_DOCKER_API_VERSION, log_config=obj
- )
- self.assertIn('LogConfig', config)
- self.assertTrue(isinstance(config['LogConfig'], LogConfig))
- self.assertEqual(obj, config['LogConfig'])
-
- def test_logconfig_invalid_config_type(self):
- with pytest.raises(ValueError):
- LogConfig(type=LogConfig.types.JSON, config='helloworld')
-
def test_resolve_repository_name(self):
# docker hub library image
self.assertEqual(
@@ -407,6 +436,8 @@ class UtilsTest(base.BaseTestCase):
None,
)
+
+class PortsTest(base.BaseTestCase):
def test_split_port_with_host_ip(self):
internal_port, external_port = split_port("127.0.0.1:1000:2000")
self.assertEqual(internal_port, ["2000"])