mirror of https://github.com/docker/docker-py.git
Merge pull request #889 from docker/725-devices-format
Improve host devices support
This commit is contained in:
commit
57b79cb1e7
|
@ -4,7 +4,7 @@ from .utils import (
|
||||||
kwargs_from_env, convert_filters, datetime_to_timestamp, create_host_config,
|
kwargs_from_env, convert_filters, datetime_to_timestamp, create_host_config,
|
||||||
create_container_config, parse_bytes, ping_registry, parse_env_file,
|
create_container_config, parse_bytes, ping_registry, parse_env_file,
|
||||||
version_lt, version_gte, decode_json_header, split_command,
|
version_lt, version_gte, decode_json_header, split_command,
|
||||||
create_ipam_config, create_ipam_pool,
|
create_ipam_config, create_ipam_pool, parse_devices
|
||||||
) # flake8: noqa
|
) # flake8: noqa
|
||||||
|
|
||||||
from .types import Ulimit, LogConfig # flake8: noqa
|
from .types import Ulimit, LogConfig # flake8: noqa
|
||||||
|
|
|
@ -400,7 +400,7 @@ def parse_host(addr, platform=None):
|
||||||
port = int(port)
|
port = int(port)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise errors.DockerException(
|
raise errors.DockerException(
|
||||||
"Invalid port: %s", addr
|
"Invalid port: {0}".format(addr)
|
||||||
)
|
)
|
||||||
|
|
||||||
elif proto in ("http", "https") and ':' not in addr:
|
elif proto in ("http", "https") and ':' not in addr:
|
||||||
|
@ -417,7 +417,14 @@ def parse_host(addr, platform=None):
|
||||||
def parse_devices(devices):
|
def parse_devices(devices):
|
||||||
device_list = []
|
device_list = []
|
||||||
for device in devices:
|
for device in devices:
|
||||||
device_mapping = device.split(":")
|
if isinstance(device, dict):
|
||||||
|
device_list.append(device)
|
||||||
|
continue
|
||||||
|
if not isinstance(device, six.string_types):
|
||||||
|
raise errors.DockerException(
|
||||||
|
'Invalid device type {0}'.format(type(device))
|
||||||
|
)
|
||||||
|
device_mapping = device.split(':')
|
||||||
if device_mapping:
|
if device_mapping:
|
||||||
path_on_host = device_mapping[0]
|
path_on_host = device_mapping[0]
|
||||||
if len(device_mapping) > 1:
|
if len(device_mapping) > 1:
|
||||||
|
@ -428,9 +435,11 @@ def parse_devices(devices):
|
||||||
permissions = device_mapping[2]
|
permissions = device_mapping[2]
|
||||||
else:
|
else:
|
||||||
permissions = 'rwm'
|
permissions = 'rwm'
|
||||||
device_list.append({"PathOnHost": path_on_host,
|
device_list.append({
|
||||||
"PathInContainer": path_in_container,
|
'PathOnHost': path_on_host,
|
||||||
"CgroupPermissions": permissions})
|
'PathInContainer': path_in_container,
|
||||||
|
'CgroupPermissions': permissions
|
||||||
|
})
|
||||||
return device_list
|
return device_list
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,18 @@ cli.create_container(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Each string is a single mapping using the colon (':') as the separator. So the
|
Each string is a single mapping using the following format:
|
||||||
above example essentially allow the container to have read write permissions to
|
`<path_on_host>:<path_in_container>:<cgroup_permissions>`
|
||||||
access the host's /dev/sda via a node named /dev/xvda in the container. The
|
The above example allows the container to have read-write access to
|
||||||
devices parameter is a list to allow multiple devices to be mapped.
|
the host's `/dev/sda` via a node named `/dev/xvda` inside the container.
|
||||||
|
|
||||||
|
As a more verbose alternative, each host device definition can be specified as
|
||||||
|
a dictionary with the following keys:
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/xvda',
|
||||||
|
'CgroupPermissions': 'rwm'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -104,17 +104,12 @@ for example:
|
||||||
* mem_swappiness (int): Tune a container's memory swappiness behavior.
|
* mem_swappiness (int): Tune a container's memory swappiness behavior.
|
||||||
Accepts number between 0 and 100.
|
Accepts number between 0 and 100.
|
||||||
* cpu_group (int): The length of a CPU period in microseconds.
|
* cpu_group (int): The length of a CPU period in microseconds.
|
||||||
* cpu_period (int): Microseconds of CPU time that the container can get in a CPU period.
|
* cpu_period (int): Microseconds of CPU time that the container can get in a
|
||||||
|
CPU period.
|
||||||
* group_add (list): List of additional group names and/or IDs that the
|
* group_add (list): List of additional group names and/or IDs that the
|
||||||
container process will run as.
|
container process will run as.
|
||||||
* devices (list): A list of devices to add to the container specified as dicts
|
* devices (list): Host device bindings. See [host devices](host-devices.md)
|
||||||
in the form:
|
for more information.
|
||||||
```
|
|
||||||
{ "PathOnHost": "/dev/deviceName",
|
|
||||||
"PathInContainer": "/dev/deviceName",
|
|
||||||
"CgroupPermissions": "mrw"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Returns** (dict) HostConfig dictionary
|
**Returns** (dict) HostConfig dictionary
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ from docker.utils import (
|
||||||
parse_repository_tag, parse_host, convert_filters, kwargs_from_env,
|
parse_repository_tag, parse_host, convert_filters, kwargs_from_env,
|
||||||
create_host_config, Ulimit, LogConfig, parse_bytes, parse_env_file,
|
create_host_config, Ulimit, LogConfig, parse_bytes, parse_env_file,
|
||||||
exclude_paths, convert_volume_binds, decode_json_header, tar,
|
exclude_paths, convert_volume_binds, decode_json_header, tar,
|
||||||
split_command, create_ipam_config, create_ipam_pool,
|
split_command, create_ipam_config, create_ipam_pool, parse_devices,
|
||||||
)
|
)
|
||||||
from docker.utils.utils import create_endpoint_config
|
from docker.utils.utils import create_endpoint_config
|
||||||
from docker.utils.ports import build_port_bindings, split_port
|
from docker.utils.ports import build_port_bindings, split_port
|
||||||
|
@ -406,6 +406,65 @@ class ParseRepositoryTagTest(base.BaseTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ParseDeviceTest(base.BaseTestCase):
|
||||||
|
def test_dict(self):
|
||||||
|
devices = parse_devices([{
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/mnt1',
|
||||||
|
'CgroupPermissions': 'r'
|
||||||
|
}])
|
||||||
|
self.assertEqual(devices[0], {
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/mnt1',
|
||||||
|
'CgroupPermissions': 'r'
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_partial_string_definition(self):
|
||||||
|
devices = parse_devices(['/dev/sda1'])
|
||||||
|
self.assertEqual(devices[0], {
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/sda1',
|
||||||
|
'CgroupPermissions': 'rwm'
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_permissionless_string_definition(self):
|
||||||
|
devices = parse_devices(['/dev/sda1:/dev/mnt1'])
|
||||||
|
self.assertEqual(devices[0], {
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/mnt1',
|
||||||
|
'CgroupPermissions': 'rwm'
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_full_string_definition(self):
|
||||||
|
devices = parse_devices(['/dev/sda1:/dev/mnt1:r'])
|
||||||
|
self.assertEqual(devices[0], {
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/mnt1',
|
||||||
|
'CgroupPermissions': 'r'
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_hybrid_list(self):
|
||||||
|
devices = parse_devices([
|
||||||
|
'/dev/sda1:/dev/mnt1:rw',
|
||||||
|
{
|
||||||
|
'PathOnHost': '/dev/sda2',
|
||||||
|
'PathInContainer': '/dev/mnt2',
|
||||||
|
'CgroupPermissions': 'r'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
self.assertEqual(devices[0], {
|
||||||
|
'PathOnHost': '/dev/sda1',
|
||||||
|
'PathInContainer': '/dev/mnt1',
|
||||||
|
'CgroupPermissions': 'rw'
|
||||||
|
})
|
||||||
|
self.assertEqual(devices[1], {
|
||||||
|
'PathOnHost': '/dev/sda2',
|
||||||
|
'PathInContainer': '/dev/mnt2',
|
||||||
|
'CgroupPermissions': 'r'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class UtilsTest(base.BaseTestCase):
|
class UtilsTest(base.BaseTestCase):
|
||||||
longMessage = True
|
longMessage = True
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue