summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoffrey F <joffrey@docker.com>2016-01-04 17:59:52 -0800
committerJoffrey F <joffrey@docker.com>2016-01-04 17:59:52 -0800
commitba0543e4acb6bf3268ae453fa6fead1a06ba660a (patch)
tree32e9cfbd95f56a1e9200e80ad06f78ae96a1048b
parentee0788e4ad07349bb2856a0f1bb40b3e9501d622 (diff)
downloaddocker-py-725-devices-format.tar.gz
Improve host devices support725-devices-format
Add unit tests for utils.parse_devices Rewrite documentation Support dict and string format for device declaration Signed-off-by: Joffrey F <joffrey@docker.com>
-rw-r--r--docker/utils/__init__.py2
-rw-r--r--docker/utils/utils.py19
-rw-r--r--docs/host-devices.md8
-rw-r--r--docs/hostconfig.md13
-rw-r--r--tests/unit/utils_test.py61
5 files changed, 83 insertions, 20 deletions
diff --git a/docker/utils/__init__.py b/docker/utils/__init__.py
index e86b724..0f18584 100644
--- a/docker/utils/__init__.py
+++ b/docker/utils/__init__.py
@@ -3,7 +3,7 @@ from .utils import (
mkbuildcontext, tar, exclude_paths, parse_repository_tag, parse_host,
kwargs_from_env, convert_filters, datetime_to_timestamp, create_host_config,
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, parse_devices,
) # flake8: noqa
from .types import Ulimit, LogConfig # flake8: noqa
diff --git a/docker/utils/utils.py b/docker/utils/utils.py
index 03b4c35..b02236f 100644
--- a/docker/utils/utils.py
+++ b/docker/utils/utils.py
@@ -383,7 +383,7 @@ def parse_host(addr, platform=None):
port = int(port)
except Exception:
raise errors.DockerException(
- "Invalid port: %s", addr
+ "Invalid port: {0}".format(addr)
)
elif proto in ("http", "https") and ':' not in addr:
@@ -400,7 +400,14 @@ def parse_host(addr, platform=None):
def parse_devices(devices):
device_list = []
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:
path_on_host = device_mapping[0]
if len(device_mapping) > 1:
@@ -411,9 +418,11 @@ def parse_devices(devices):
permissions = device_mapping[2]
else:
permissions = 'rwm'
- device_list.append({"PathOnHost": path_on_host,
- "PathInContainer": path_in_container,
- "CgroupPermissions": permissions})
+ device_list.append({
+ 'PathOnHost': path_on_host,
+ 'PathInContainer': path_in_container,
+ 'CgroupPermissions': permissions
+ })
return device_list
diff --git a/docs/host-devices.md b/docs/host-devices.md
index a35d340..d0d6669 100644
--- a/docs/host-devices.md
+++ b/docs/host-devices.md
@@ -12,7 +12,7 @@ cli.create_container(
)
```
-Each string is a single mapping using the colon (':') as the separator. So the
-above example essentially allow the container to have read write permissions to
-access the host's /dev/sda via a node named /dev/xvda in the container. The
-devices parameter is a list to allow multiple devices to be mapped.
+Each string is a single mapping using the following format:
+`<path_on_host>:<path_in_container>:<cgroup_permissions>`
+The above example allows the container to have read-write access to
+the host's `/dev/sda` via a node named `/dev/xvda` inside the container.
diff --git a/docs/hostconfig.md b/docs/hostconfig.md
index 6b11798..b7b3b66 100644
--- a/docs/hostconfig.md
+++ b/docs/hostconfig.md
@@ -104,17 +104,12 @@ for example:
* mem_swappiness (int): Tune a container's memory swappiness behavior.
Accepts number between 0 and 100.
* 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
container process will run as.
-* devices (list): A list of devices to add to the container specified as dicts
- in the form:
- ```
- { "PathOnHost": "/dev/deviceName",
- "PathInContainer": "/dev/deviceName",
- "CgroupPermissions": "mrw"
- }
- ```
+* devices (list): Host device bindings. See [host devices](host-devices.md)
+ for more information.
**Returns** (dict) HostConfig dictionary
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index a68e1e7..626254e 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -18,7 +18,7 @@ from docker.utils import (
parse_repository_tag, parse_host, convert_filters, kwargs_from_env,
create_host_config, Ulimit, LogConfig, parse_bytes, parse_env_file,
exclude_paths, convert_volume_binds, decode_json_header, tar,
- split_command,
+ split_command, parse_devices
)
from docker.utils.ports import build_port_bindings, split_port
@@ -398,6 +398,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):
longMessage = True