Merge branch 'cuckoohello-5360-add-runtime-support'

This commit is contained in:
Joffrey F 2018-01-04 12:46:26 -08:00
commit ddbc9e30b0
6 changed files with 103 additions and 5 deletions

View File

@ -98,6 +98,7 @@ DOCKER_CONFIG_KEYS = [
'privileged', 'privileged',
'read_only', 'read_only',
'restart', 'restart',
'runtime',
'secrets', 'secrets',
'security_opt', 'security_opt',
'shm_size', 'shm_size',

View File

@ -261,6 +261,7 @@
"privileged": {"type": "boolean"}, "privileged": {"type": "boolean"},
"read_only": {"type": "boolean"}, "read_only": {"type": "boolean"},
"restart": {"type": "string"}, "restart": {"type": "string"},
"runtime": {"type": "string"},
"scale": {"type": "integer"}, "scale": {"type": "integer"},
"security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"shm_size": {"type": ["number", "string"]}, "shm_size": {"type": ["number", "string"]},

View File

@ -87,6 +87,7 @@ HOST_CONFIG_KEYS = [
'pids_limit', 'pids_limit',
'privileged', 'privileged',
'restart', 'restart',
'runtime',
'security_opt', 'security_opt',
'shm_size', 'shm_size',
'storage_opt', 'storage_opt',
@ -878,6 +879,7 @@ class Service(object):
dns_opt=options.get('dns_opt'), dns_opt=options.get('dns_opt'),
dns_search=options.get('dns_search'), dns_search=options.get('dns_search'),
restart_policy=options.get('restart'), restart_policy=options.get('restart'),
runtime=options.get('runtime'),
cap_add=options.get('cap_add'), cap_add=options.get('cap_add'),
cap_drop=options.get('cap_drop'), cap_drop=options.get('cap_drop'),
mem_limit=options.get('mem_limit'), mem_limit=options.get('mem_limit'),

View File

@ -22,6 +22,7 @@ from compose.config.types import VolumeSpec
from compose.const import COMPOSEFILE_V2_0 as V2_0 from compose.const import COMPOSEFILE_V2_0 as V2_0
from compose.const import COMPOSEFILE_V2_1 as V2_1 from compose.const import COMPOSEFILE_V2_1 as V2_1
from compose.const import COMPOSEFILE_V2_2 as V2_2 from compose.const import COMPOSEFILE_V2_2 as V2_2
from compose.const import COMPOSEFILE_V2_3 as V2_3
from compose.const import COMPOSEFILE_V3_1 as V3_1 from compose.const import COMPOSEFILE_V3_1 as V3_1
from compose.const import LABEL_PROJECT from compose.const import LABEL_PROJECT
from compose.const import LABEL_SERVICE from compose.const import LABEL_SERVICE
@ -31,6 +32,7 @@ from compose.errors import NoHealthCheckConfigured
from compose.project import Project from compose.project import Project
from compose.project import ProjectError from compose.project import ProjectError
from compose.service import ConvergenceStrategy from compose.service import ConvergenceStrategy
from tests.integration.testcases import if_runtime_available
from tests.integration.testcases import is_cluster from tests.integration.testcases import is_cluster
from tests.integration.testcases import no_cluster from tests.integration.testcases import no_cluster
from tests.integration.testcases import v2_1_only from tests.integration.testcases import v2_1_only
@ -832,11 +834,11 @@ class ProjectTest(DockerClientTestCase):
service_container = project.get_service('web').containers()[0] service_container = project.get_service('web').containers()[0]
IPAMConfig = (service_container.inspect().get('NetworkSettings', {}). ipam_config = (service_container.inspect().get('NetworkSettings', {}).
get('Networks', {}).get('composetest_static_test', {}). get('Networks', {}).get('composetest_static_test', {}).
get('IPAMConfig', {})) get('IPAMConfig', {}))
assert IPAMConfig.get('IPv4Address') == '172.16.100.100' assert ipam_config.get('IPv4Address') == '172.16.100.100'
assert IPAMConfig.get('IPv6Address') == 'fe80::1001:102' assert ipam_config.get('IPv6Address') == 'fe80::1001:102'
@v2_1_only() @v2_1_only()
def test_up_with_enable_ipv6(self): def test_up_with_enable_ipv6(self):
@ -1029,6 +1031,67 @@ class ProjectTest(DockerClientTestCase):
with self.assertRaises(ProjectError): with self.assertRaises(ProjectError):
project.up() project.up()
@v2_3_only()
@if_runtime_available('runc')
def test_up_with_runtime(self):
self.require_api_version('1.30')
config_data = build_config(
version=V2_3,
services=[{
'name': 'web',
'image': 'busybox:latest',
'runtime': 'runc'
}],
)
project = Project.from_config(
client=self.client,
name='composetest',
config_data=config_data
)
project.up(detached=True)
service_container = project.get_service('web').containers(stopped=True)[0]
assert service_container.inspect()['HostConfig']['Runtime'] == 'runc'
@v2_3_only()
def test_up_with_invalid_runtime(self):
self.require_api_version('1.30')
config_data = build_config(
version=V2_3,
services=[{
'name': 'web',
'image': 'busybox:latest',
'runtime': 'foobar'
}],
)
project = Project.from_config(
client=self.client,
name='composetest',
config_data=config_data
)
with self.assertRaises(ProjectError):
project.up()
@v2_3_only()
@if_runtime_available('nvidia')
def test_up_with_nvidia_runtime(self):
self.require_api_version('1.30')
config_data = build_config(
version=V2_3,
services=[{
'name': 'web',
'image': 'busybox:latest',
'runtime': 'nvidia'
}],
)
project = Project.from_config(
client=self.client,
name='composetest',
config_data=config_data
)
project.up(detached=True)
service_container = project.get_service('web').containers(stopped=True)[0]
assert service_container.inspect()['HostConfig']['Runtime'] == 'nvidia'
@v2_only() @v2_only()
def test_project_up_with_network_internal(self): def test_project_up_with_network_internal(self):
self.require_api_version('1.23') self.require_api_version('1.23')

View File

@ -155,6 +155,18 @@ class DockerClientTestCase(unittest.TestCase):
return self.client.inspect_volume(volumes[0]['Name']) return self.client.inspect_volume(volumes[0]['Name'])
def if_runtime_available(runtime):
def decorator(f):
@functools.wraps(f)
def wrapper(self, *args, **kwargs):
if runtime not in self.client.info().get('Runtimes', {}):
return pytest.skip("This daemon does not support the '{}'' runtime".format(runtime))
return f(self, *args, **kwargs)
return wrapper
return decorator
def is_cluster(client): def is_cluster(client):
if SWARM_ASSUME_MULTINODE: if SWARM_ASSUME_MULTINODE:
return True return True

View File

@ -1784,6 +1784,25 @@ class ConfigTest(unittest.TestCase):
} }
] ]
def test_runtime_option(self):
actual = config.load(build_config_details({
'version': str(V2_3),
'services': {
'web': {
'image': 'nvidia/cuda',
'runtime': 'nvidia'
}
}
}))
assert actual.services == [
{
'name': 'web',
'image': 'nvidia/cuda',
'runtime': 'nvidia',
}
]
def test_merge_service_dicts_from_files_with_extends_in_base(self): def test_merge_service_dicts_from_files_with_extends_in_base(self):
base = { base = {
'volumes': ['.:/app'], 'volumes': ['.:/app'],