... | ... |
@@ -1249,10 +1249,22 @@ func (opts PathOpts) String() string { |
1249 | 1249 |
} |
1250 | 1250 |
|
1251 | 1251 |
func (opts PathOpts) Set(val string) error { |
1252 |
- if !filepath.IsAbs(val) { |
|
1253 |
- return fmt.Errorf("%s is not an absolute path", val) |
|
1252 |
+ var containerPath string |
|
1253 |
+ |
|
1254 |
+ splited := strings.SplitN(val, ":", 2) |
|
1255 |
+ if len(splited) == 1 { |
|
1256 |
+ containerPath = splited[0] |
|
1257 |
+ val = filepath.Clean(splited[0]) |
|
1258 |
+ } else { |
|
1259 |
+ containerPath = splited[1] |
|
1260 |
+ val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1])) |
|
1261 |
+ } |
|
1262 |
+ |
|
1263 |
+ if !filepath.IsAbs(containerPath) { |
|
1264 |
+ utils.Debugf("%s is not an absolute path", containerPath) |
|
1265 |
+ return fmt.Errorf("%s is not an absolute path", containerPath) |
|
1254 | 1266 |
} |
1255 |
- opts[filepath.Clean(val)] = struct{}{} |
|
1267 |
+ opts[val] = struct{}{} |
|
1256 | 1268 |
return nil |
1257 | 1269 |
} |
1258 | 1270 |
|
... | ... |
@@ -121,14 +121,11 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, |
121 | 121 |
cmd.Var(&flDns, "dns", "Set custom dns servers") |
122 | 122 |
|
123 | 123 |
flVolumes := NewPathOpts() |
124 |
- cmd.Var(flVolumes, "v", "Attach a data volume") |
|
124 |
+ cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)") |
|
125 | 125 |
|
126 | 126 |
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container") |
127 | 127 |
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image") |
128 | 128 |
|
129 |
- var flBinds ListOpts |
|
130 |
- cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)") |
|
131 |
- |
|
132 | 129 |
if err := cmd.Parse(args); err != nil { |
133 | 130 |
return nil, nil, cmd, err |
134 | 131 |
} |
... | ... |
@@ -146,11 +143,17 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, |
146 | 146 |
} |
147 | 147 |
} |
148 | 148 |
|
149 |
+ var binds []string |
|
150 |
+ |
|
149 | 151 |
// add any bind targets to the list of container volumes |
150 |
- for _, bind := range flBinds { |
|
152 |
+ for bind := range flVolumes { |
|
151 | 153 |
arr := strings.Split(bind, ":") |
152 |
- dstDir := arr[1] |
|
153 |
- flVolumes[dstDir] = struct{}{} |
|
154 |
+ if len(arr) > 1 { |
|
155 |
+ dstDir := arr[1] |
|
156 |
+ flVolumes[dstDir] = struct{}{} |
|
157 |
+ binds = append(binds, bind) |
|
158 |
+ delete(flVolumes, bind) |
|
159 |
+ } |
|
154 | 160 |
} |
155 | 161 |
|
156 | 162 |
parsedArgs := cmd.Args() |
... | ... |
@@ -187,7 +190,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, |
187 | 187 |
Entrypoint: entrypoint, |
188 | 188 |
} |
189 | 189 |
hostConfig := &HostConfig{ |
190 |
- Binds: flBinds, |
|
190 |
+ Binds: binds, |
|
191 | 191 |
} |
192 | 192 |
|
193 | 193 |
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit { |
... | ... |
@@ -493,6 +496,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
493 | 493 |
func (container *Container) Start(hostConfig *HostConfig) error { |
494 | 494 |
container.State.Lock() |
495 | 495 |
defer container.State.Unlock() |
496 |
+ |
|
496 | 497 |
if len(hostConfig.Binds) == 0 { |
497 | 498 |
hostConfig, _ = container.ReadHostConfig() |
498 | 499 |
} |
... | ... |
@@ -1231,19 +1231,18 @@ func TestBindMounts(t *testing.T) { |
1231 | 1231 |
writeFile(path.Join(tmpDir, "touch-me"), "", t) |
1232 | 1232 |
|
1233 | 1233 |
// Test reading from a read-only bind mount |
1234 |
- stdout, _ := runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t) |
|
1234 |
+ stdout, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t) |
|
1235 | 1235 |
if !strings.Contains(stdout, "touch-me") { |
1236 | 1236 |
t.Fatal("Container failed to read from bind mount") |
1237 | 1237 |
} |
1238 | 1238 |
|
1239 | 1239 |
// test writing to bind mount |
1240 |
- runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t) |
|
1240 |
+ runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t) |
|
1241 | 1241 |
readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist |
1242 | 1242 |
|
1243 | 1243 |
// test mounting to an illegal destination directory |
1244 |
- if _, err := runContainer(r, []string{"-b", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil { |
|
1244 |
+ if _, err := runContainer(r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil { |
|
1245 | 1245 |
t.Fatal("Container bind mounted illegal directory") |
1246 |
- |
|
1247 | 1246 |
} |
1248 | 1247 |
} |
1249 | 1248 |
|
... | ... |
@@ -1,13 +1,13 @@ |
1 | 1 |
package docker |
2 | 2 |
|
3 | 3 |
import ( |
4 |
+ "github.com/dotcloud/docker/utils" |
|
4 | 5 |
"io" |
5 | 6 |
"io/ioutil" |
6 | 7 |
"os" |
7 | 8 |
"path" |
8 | 9 |
"strings" |
9 | 10 |
"testing" |
10 |
- "github.com/dotcloud/docker/utils" |
|
11 | 11 |
) |
12 | 12 |
|
13 | 13 |
// This file contains utility functions for docker's unit test suite. |
... | ... |
@@ -87,17 +87,18 @@ func readFile(src string, t *testing.T) (content string) { |
87 | 87 |
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image. |
88 | 88 |
// The caller is responsible for destroying the container. |
89 | 89 |
// Call t.Fatal() at the first error. |
90 |
-func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig) { |
|
90 |
+func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig, error) { |
|
91 | 91 |
config, hostConfig, _, err := ParseRun(args, nil) |
92 | 92 |
if err != nil { |
93 |
- t.Fatal(err) |
|
93 |
+ return nil, nil, err |
|
94 | 94 |
} |
95 | 95 |
config.Image = GetTestImage(r).ID |
96 | 96 |
c, err := NewBuilder(r).Create(config) |
97 | 97 |
if err != nil { |
98 | 98 |
t.Fatal(err) |
99 |
+ return nil, nil, err |
|
99 | 100 |
} |
100 |
- return c, hostConfig |
|
101 |
+ return c, hostConfig, nil |
|
101 | 102 |
} |
102 | 103 |
|
103 | 104 |
// Create a test container, start it, wait for it to complete, destroy it, |
... | ... |
@@ -110,7 +111,10 @@ func runContainer(r *Runtime, args []string, t *testing.T) (output string, err e |
110 | 110 |
t.Fatal(err) |
111 | 111 |
} |
112 | 112 |
}() |
113 |
- container, hostConfig := mkContainer(r, args, t) |
|
113 |
+ container, hostConfig, err := mkContainer(r, args, t) |
|
114 |
+ if err != nil { |
|
115 |
+ return "", err |
|
116 |
+ } |
|
114 | 117 |
defer r.Destroy(container) |
115 | 118 |
stdout, err := container.StdoutPipe() |
116 | 119 |
if err != nil { |