Skip to content

Commit

Permalink
add support for runtime option in service definitions
Browse files Browse the repository at this point in the history
close #5360

Signed-off-by: Yafeng Shan <cuckoo@kokonur.me>
  • Loading branch information
Yafeng Shan committed Dec 4, 2017
1 parent a204e50 commit b9beda1
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 0 deletions.
1 change: 1 addition & 0 deletions compose/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
'privileged',
'read_only',
'restart',
'runtime',
'secrets',
'security_opt',
'shm_size',
Expand Down
1 change: 1 addition & 0 deletions compose/config/config_schema_v2.3.json
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@
"privileged": {"type": "boolean"},
"read_only": {"type": "boolean"},
"restart": {"type": "string"},
"runtime": {"type": "string"},
"scale": {"type": "integer"},
"security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"shm_size": {"type": ["number", "string"]},
Expand Down
2 changes: 2 additions & 0 deletions compose/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
'pids_limit',
'privileged',
'restart',
'runtime',
'security_opt',
'shm_size',
'storage_opt',
Expand Down Expand Up @@ -858,6 +859,7 @@ def _get_container_host_config(self, override_options, one_off=False):
dns_opt=options.get('dns_opt'),
dns_search=options.get('dns_search'),
restart_policy=options.get('restart'),
runtime=options.get('runtime'),
cap_add=options.get('cap_add'),
cap_drop=options.get('cap_drop'),
mem_limit=options.get('mem_limit'),
Expand Down
63 changes: 63 additions & 0 deletions tests/integration/project_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
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_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 LABEL_PROJECT
from compose.const import LABEL_SERVICE
Expand All @@ -31,10 +32,12 @@
from compose.project import Project
from compose.project import ProjectError
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 no_cluster
from tests.integration.testcases import v2_1_only
from tests.integration.testcases import v2_2_only
from tests.integration.testcases import v2_3_only
from tests.integration.testcases import v2_only
from tests.integration.testcases import v3_only

Expand Down Expand Up @@ -971,6 +974,66 @@ def test_up_with_invalid_isolation(self):
with self.assertRaises(ProjectError):
project.up()

@v2_3_only()
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()
def test_project_up_with_network_internal(self):
self.require_api_version('1.23')
Expand Down
20 changes: 20 additions & 0 deletions tests/integration/testcases.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from __future__ import unicode_literals

import functools
import shutil
import six
import os

import pytest
Expand Down Expand Up @@ -155,6 +157,24 @@ def get_volume_data(self, volume_name):
return self.client.inspect_volume(volumes[0]['Name'])


def if_runtime_available(runtime):
if runtime == 'nvidia':
command = 'nvidia-container-runtime'
if six.PY3:
return pytest.mark.skipif(
shutil.which(command) is None,
reason="Nvida runtime not exists"
)
return pytest.mark.skipif(
any(
os.access(os.path.join(path, command), os.X_OK)
for path in os.environ["PATH"].split(os.pathsep)
) is False,
reason="Nvida runtime not exists"
)
return pytest.skip("Runtime %s not exists", runtime)


def is_cluster(client):
if SWARM_ASSUME_MULTINODE:
return True
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/config/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,25 @@ def test_isolation_option(self):
}
]

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):
base = {
'volumes': ['.:/app'],
Expand Down

0 comments on commit b9beda1

Please sign in to comment.