Merge pull request #1212 from dotcloud/merge_v_b_options

* Runtime: Merge -b and -v options
This commit is contained in:
Guillaume J. Charmes 2013-07-17 11:43:47 -07:00
commit 578e888915
5 changed files with 39 additions and 21 deletions

View File

@ -1249,10 +1249,22 @@ func (opts PathOpts) String() string {
} }
func (opts PathOpts) Set(val string) error { func (opts PathOpts) Set(val string) error {
if !filepath.IsAbs(val) { var containerPath string
return fmt.Errorf("%s is not an absolute path", val)
splited := strings.SplitN(val, ":", 2)
if len(splited) == 1 {
containerPath = splited[0]
val = filepath.Clean(splited[0])
} else {
containerPath = splited[1]
val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1]))
} }
opts[filepath.Clean(val)] = struct{}{}
if !filepath.IsAbs(containerPath) {
utils.Debugf("%s is not an absolute path", containerPath)
return fmt.Errorf("%s is not an absolute path", containerPath)
}
opts[val] = struct{}{}
return nil return nil
} }

View File

@ -121,14 +121,11 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
cmd.Var(&flDns, "dns", "Set custom dns servers") cmd.Var(&flDns, "dns", "Set custom dns servers")
flVolumes := NewPathOpts() flVolumes := NewPathOpts()
cmd.Var(flVolumes, "v", "Attach a data volume") cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container") flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image") flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
var flBinds ListOpts
cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)")
if err := cmd.Parse(args); err != nil { if err := cmd.Parse(args); err != nil {
return nil, nil, cmd, err return nil, nil, cmd, err
} }
@ -146,11 +143,17 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
} }
} }
var binds []string
// add any bind targets to the list of container volumes // add any bind targets to the list of container volumes
for _, bind := range flBinds { for bind := range flVolumes {
arr := strings.Split(bind, ":") arr := strings.Split(bind, ":")
dstDir := arr[1] if len(arr) > 1 {
flVolumes[dstDir] = struct{}{} dstDir := arr[1]
flVolumes[dstDir] = struct{}{}
binds = append(binds, bind)
delete(flVolumes, bind)
}
} }
parsedArgs := cmd.Args() parsedArgs := cmd.Args()
@ -187,7 +190,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
Entrypoint: entrypoint, Entrypoint: entrypoint,
} }
hostConfig := &HostConfig{ hostConfig := &HostConfig{
Binds: flBinds, Binds: binds,
} }
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit { if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
@ -493,6 +496,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
func (container *Container) Start(hostConfig *HostConfig) error { func (container *Container) Start(hostConfig *HostConfig) error {
container.State.Lock() container.State.Lock()
defer container.State.Unlock() defer container.State.Unlock()
if len(hostConfig.Binds) == 0 { if len(hostConfig.Binds) == 0 {
hostConfig, _ = container.ReadHostConfig() hostConfig, _ = container.ReadHostConfig()
} }

View File

@ -1231,19 +1231,18 @@ func TestBindMounts(t *testing.T) {
writeFile(path.Join(tmpDir, "touch-me"), "", t) writeFile(path.Join(tmpDir, "touch-me"), "", t)
// Test reading from a read-only bind mount // Test reading from a read-only bind mount
stdout, _ := runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t) stdout, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
if !strings.Contains(stdout, "touch-me") { if !strings.Contains(stdout, "touch-me") {
t.Fatal("Container failed to read from bind mount") t.Fatal("Container failed to read from bind mount")
} }
// test writing to bind mount // test writing to bind mount
runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t) runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
// test mounting to an illegal destination directory // test mounting to an illegal destination directory
if _, err := runContainer(r, []string{"-b", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil { if _, err := runContainer(r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
t.Fatal("Container bind mounted illegal directory") t.Fatal("Container bind mounted illegal directory")
} }
} }

View File

@ -23,7 +23,6 @@
-t=false: Allocate a pseudo-tty -t=false: Allocate a pseudo-tty
-u="": Username or UID -u="": Username or UID
-d=[]: Set custom dns servers for the container -d=[]: Set custom dns servers for the container
-v=[]: Creates a new volume and mounts it at the specified path. -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "host-dir" is missing, then docker creates a new volume.
-volumes-from="": Mount all volumes from the given container. -volumes-from="": Mount all volumes from the given container.
-b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]
-entrypoint="": Overwrite the default entrypoint set by the image. -entrypoint="": Overwrite the default entrypoint set by the image.

View File

@ -87,17 +87,18 @@ func readFile(src string, t *testing.T) (content string) {
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image. // The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
// The caller is responsible for destroying the container. // The caller is responsible for destroying the container.
// Call t.Fatal() at the first error. // Call t.Fatal() at the first error.
func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig) { func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConfig, error) {
config, hostConfig, _, err := ParseRun(args, nil) config, hostConfig, _, err := ParseRun(args, nil)
if err != nil { if err != nil {
t.Fatal(err) return nil, nil, err
} }
config.Image = GetTestImage(r).ID config.Image = GetTestImage(r).ID
c, err := NewBuilder(r).Create(config) c, err := NewBuilder(r).Create(config)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return nil, nil, err
} }
return c, hostConfig return c, hostConfig, nil
} }
// Create a test container, start it, wait for it to complete, destroy it, // 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
t.Fatal(err) t.Fatal(err)
} }
}() }()
container, hostConfig := mkContainer(r, args, t) container, hostConfig, err := mkContainer(r, args, t)
if err != nil {
return "", err
}
defer r.Destroy(container) defer r.Destroy(container)
stdout, err := container.StdoutPipe() stdout, err := container.StdoutPipe()
if err != nil { if err != nil {