Repository: docker/docker-py

Issue:
Specify "ro"/"rw" for volumes
It would be nice to have ability to specify mode for volume, e.g. read only.

Currently this can be done in this not obvious way:

```
c.start(container_id, binds={"/home/host-data/": "/mnt/data:ro"})
```



Discussion:
Thanks for the hint, @rutsky.  Would like to see proper support for this, as well.

@blalor , @rutsky, Curious in what manner would you like to see this properly supported?Something like..

``` python
c.start(container_id, binds={"/home/host-data/": "/mnt/data"}, mode="ro")
```

???

You'd want the mode to be part of the individual bind; maybe `{"/home/host-data/": ("/mnt/data", False)}` to indicate that writing is forbidden.  If it's a string, or if the 2nd value of the tuple's `True` then it would be read-only.  Feels kludgy, but you certainly don't want to force all binds to be rw or ro.

agreed, I think the idea was to be explicit in that you setting mode to rw or ro. 
:+1: for keeping it part of the individual bind. 

Some ideas,
I believe the True/False dictation may be useful, if you use "docker inspect" volumes come up as 

```
...stuff
"VolumesRW": {
      "/foo/bar/myvol": true
}
...more stuff
```

though its not very informative, heres a sample of two ways, yours and another.

Your example

```
{"/home/host-data/": ("/mnt/data", False)}
```

change start () from

```
if binds:
      bind_pairs = [
          '{0}:{1}'.format(host, dest) for host, dest in binds.items()
      ]
      start_config['Binds'] = bind_pairs
```

to (setting rw if True is set, ro if False)

```
if binds:
      bind_pairs = [
          '%s:%s:rw' % (h,d[0]) if d[1] else '%s:%s:ro' % (h,d[0]) for h, d in binds.items()]
      start_config['Binds'] = bind_pairs
```

Or use more explicit keys

```
{"/home/host-data/": { "bind" : "/mnt/data", "rw" : True }}
```

Then in the start() def we could change it to

```
if binds:
      bind_pairs = [
          '%s:%s:rw' % (h,d['bind']) if d['rw'] else '%s:%s:ro' % (h,d['bind']) for h, d in binds.items()
       ]
      start_config['Binds'] = bind_pairs
```

I think explicit key name is better, but it should remain read-write by default, since that's the current behavior.

``` python
{"/home/host-data/": {
    "bind": "/mnt/data",
    "ro": True,
}}
```

With the modification to `start()` that goes along with it obviously.

forgot to change README with this, can always do this after or redo a pull request if this is something that eventually gets merged. 

@mpetazzoni , this should reflect changes, mind the small second pull request, i had a small comma typo in the README, the parent of that has the changes.


Resolving patch:
diff --git a/docker/client.py b/docker/client.py
--- a/docker/client.py
+++ b/docker/client.py
@@ -680,8 +680,12 @@ def start(self, container, binds=None, port_bindings=None, lxc_conf=None,
         }
         if binds:
             bind_pairs = [
-                '{0}:{1}'.format(host, dest) for host, dest in binds.items()
+                '%s:%s:%s' % (
+                    h, d['bind'],
+                    'ro' if 'ro' in d and d['ro'] else 'rw'
+                ) for h, d in binds.items()
             ]
+
             start_config['Binds'] = bind_pairs
 
         if port_bindings:


Test patch:
diff --git a/tests/test.py b/tests/test.py
--- a/tests/test.py
+++ b/tests/test.py
@@ -441,12 +441,15 @@ def test_start_container_with_lxc_conf_compat(self):
             docker.client.DEFAULT_TIMEOUT_SECONDS
         )
 
-    def test_start_container_with_binds(self):
+    def test_start_container_with_binds_ro(self):
         try:
             mount_dest = '/mnt'
             mount_origin = '/tmp'
             self.client.start(fake_api.FAKE_CONTAINER_ID,
-                              binds={mount_origin: mount_dest})
+                              binds={mount_origin: {
+                                  "bind": mount_dest,
+                                  "ro": True
+                              }})
         except Exception as e:
             self.fail('Command should not raise exception: {0}'.format(e))
 
@@ -454,7 +457,30 @@ def test_start_container_with_binds(self):
         self.assertEqual(args[0][0], url_prefix +
                          'containers/3cc2351ab11b/start')
         self.assertEqual(json.loads(args[1]['data']),
-                         {"Binds": ["/tmp:/mnt"],
+                         {"Binds": ["/tmp:/mnt:ro"],
+                          "PublishAllPorts": False,
+                          "Privileged": False})
+        self.assertEqual(args[1]['headers'],
+                         {'Content-Type': 'application/json'})
+        self.assertEqual(
+            args[1]['timeout'],
+            docker.client.DEFAULT_TIMEOUT_SECONDS)
+
+    def test_start_container_with_binds_rw(self):
+        try:
+            mount_dest = '/mnt'
+            mount_origin = '/tmp'
+            self.client.start(fake_api.FAKE_CONTAINER_ID,
+                              binds={mount_origin: {
+                                     "bind": mount_dest, "ro": False}})
+        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']),
+                         {"Binds": ["/tmp:/mnt:rw"],
                           "PublishAllPorts": False,
                           "Privileged": False})
         self.assertEqual(args[1]['headers'],