Ability to specify Host Devices during container start

The command line and daemon started supporting --device
parameter during docker start a while ago in the following commit:
docker/docker@e855c4b

Since the command line looks like this,
--device=[] Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc)
This patch allows a list of strings to be passed into the start() method
and we parse out the 3 components just like in the above mentioned commit
This commit is contained in:
Davanum Srinivas 2014-10-23 22:47:30 -04:00
parent b93fca639e
commit 7a917cc7a0
4 changed files with 76 additions and 1 deletions

View File

@ -385,6 +385,23 @@ c.start(container_id, binds={
})
```
Access to devices on the host
=============================
If you need to directly expose some host devices to a container, you can use
the devices parameter in the `Client.start` method as shown below
```python
c.start(container_id, devices=['/dev/sda:/dev/xvda:rwm'])
```
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.
Connection to daemon using HTTPS
================================

View File

@ -827,7 +827,7 @@ class Client(requests.Session):
def start(self, container, binds=None, port_bindings=None, lxc_conf=None,
publish_all_ports=False, links=None, privileged=False,
dns=None, dns_search=None, volumes_from=None, network_mode=None,
restart_policy=None, cap_add=None, cap_drop=None):
restart_policy=None, cap_add=None, cap_drop=None, devices=None):
if isinstance(container, dict):
container = container.get('Id')
@ -895,6 +895,9 @@ class Client(requests.Session):
if cap_drop:
start_config['CapDrop'] = cap_drop
if devices:
start_config['Devices'] = utils.parse_devices(devices)
url = self._url("/containers/{0}/start".format(container))
res = self._post_json(url, data=start_config)
self._raise_for_status(res)

View File

@ -233,3 +233,23 @@ def parse_host(addr):
if proto == "http+unix":
return "%s://%s" % (proto, host)
return "%s://%s:%d" % (proto, host, port)
def parse_devices(devices):
device_list = []
for device in devices:
device_mapping = device.split(",")
if device_mapping:
path_on_host = device_mapping[0]
if len(device_mapping) > 1:
path_in_container = device_mapping[1]
else:
path_in_container = path_on_host
if len(device_mapping) > 2:
permissions = device_mapping[2]
else:
permissions = 'rwm'
device_list.append({"PathOnHost": path_on_host,
"PathInContainer": path_in_container,
"CgroupPermissions": permissions})
return device_list

View File

@ -891,6 +891,41 @@ class DockerClientTest(Cleanup, unittest.TestCase):
docker.client.DEFAULT_TIMEOUT_SECONDS
)
def test_start_container_with_devices(self):
try:
self.client.start(fake_api.FAKE_CONTAINER_ID,
devices=['/dev/sda:/dev/xvda:rwm',
'/dev/sdb:/dev/xvdb',
'/dev/sdc'])
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(
args[0][0],
url_prefix + 'containers/3cc2351ab11b/start'
)
self.assertEqual(
json.loads(args[1]['data']),
{"PublishAllPorts": False, "Privileged": False,
"Devices": [{'CgroupPermissions': 'rwm',
'PathInContainer': '/dev/sda:/dev/xvda:rwm',
'PathOnHost': '/dev/sda:/dev/xvda:rwm'},
{'CgroupPermissions': 'rwm',
'PathInContainer': '/dev/sdb:/dev/xvdb',
'PathOnHost': '/dev/sdb:/dev/xvdb'},
{'CgroupPermissions': 'rwm',
'PathInContainer': '/dev/sdc',
'PathOnHost': '/dev/sdc'}]}
)
self.assertEqual(
args[1]['headers'],
{'Content-Type': 'application/json'}
)
self.assertEqual(
args[1]['timeout'],
docker.client.DEFAULT_TIMEOUT_SECONDS
)
def test_resize_container(self):
try:
self.client.resize(