+ Runtime: mount volumes from a host directory with 'docker run -b'

This commit is contained in:
Gabriel Monroy 2013-05-13 17:39:54 -06:00 committed by Solomon Hykes
parent cd0f22ef72
commit 4fdf11b2e6
14 changed files with 273 additions and 58 deletions

11
api.go
View File

@ -551,11 +551,20 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
} }
func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
hostConfig := &HostConfig{}
// allow a nil body for backwards compatibility
if r.Body != nil {
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
return err
}
}
if vars == nil { if vars == nil {
return fmt.Errorf("Missing parameter") return fmt.Errorf("Missing parameter")
} }
name := vars["name"] name := vars["name"]
if err := srv.ContainerStart(name); err != nil { if err := srv.ContainerStart(name, hostConfig); err != nil {
return err return err
} }
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)

View File

@ -873,7 +873,8 @@ func TestPostContainersKill(t *testing.T) {
} }
defer runtime.Destroy(container) defer runtime.Destroy(container)
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -917,7 +918,8 @@ func TestPostContainersRestart(t *testing.T) {
} }
defer runtime.Destroy(container) defer runtime.Destroy(container)
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -973,8 +975,15 @@ func TestPostContainersStart(t *testing.T) {
} }
defer runtime.Destroy(container) defer runtime.Destroy(container)
hostConfigJSON, err := json.Marshal(&HostConfig{})
req, err := http.NewRequest("POST", "/containers/"+container.ID+"/start", bytes.NewReader(hostConfigJSON))
if err != nil {
t.Fatal(err)
}
r := httptest.NewRecorder() r := httptest.NewRecorder()
if err := postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil { if err := postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if r.Code != http.StatusNoContent { if r.Code != http.StatusNoContent {
@ -989,7 +998,7 @@ func TestPostContainersStart(t *testing.T) {
} }
r = httptest.NewRecorder() r = httptest.NewRecorder()
if err = postContainersStart(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err == nil { if err = postContainersStart(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err == nil {
t.Fatalf("A running containter should be able to be started") t.Fatalf("A running containter should be able to be started")
} }
@ -1019,7 +1028,8 @@ func TestPostContainersStop(t *testing.T) {
} }
defer runtime.Destroy(container) defer runtime.Destroy(container)
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1068,7 +1078,8 @@ func TestPostContainersWait(t *testing.T) {
} }
defer runtime.Destroy(container) defer runtime.Destroy(container)
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1113,7 +1124,8 @@ func TestPostContainersAttach(t *testing.T) {
defer runtime.Destroy(container) defer runtime.Destroy(container)
// Start the process // Start the process
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -87,7 +87,7 @@ func (b *buildFile) CmdRun(args string) error {
if b.image == "" { if b.image == "" {
return fmt.Errorf("Please provide a source image with `from` prior to run") return fmt.Errorf("Please provide a source image with `from` prior to run")
} }
config, _, err := ParseRun([]string{b.image, "/bin/sh", "-c", args}, nil) config, _, _, err := ParseRun([]string{b.image, "/bin/sh", "-c", args}, nil)
if err != nil { if err != nil {
return err return err
} }
@ -263,7 +263,8 @@ func (b *buildFile) run() (string, error) {
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID)) fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
//start the container //start the container
if err := c.Start(); err != nil { hostConfig := &HostConfig{}
if err := c.Start(hostConfig); err != nil {
return "", err return "", err
} }

View File

@ -1235,7 +1235,7 @@ func (cli *DockerCli) CmdTag(args ...string) error {
} }
func (cli *DockerCli) CmdRun(args ...string) error { func (cli *DockerCli) CmdRun(args ...string) error {
config, cmd, err := ParseRun(args, nil) config, hostConfig, cmd, err := ParseRun(args, nil)
if err != nil { if err != nil {
return err return err
} }
@ -1274,7 +1274,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
} }
//start the container //start the container
if _, _, err = cli.call("POST", "/containers/"+runResult.ID+"/start", nil); err != nil { if _, _, err = cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig); err != nil {
return err return err
} }

View File

@ -52,6 +52,8 @@ type Container struct {
waitLock chan struct{} waitLock chan struct{}
Volumes map[string]string Volumes map[string]string
Binds []BindMap
} }
type Config struct { type Config struct {
@ -75,7 +77,17 @@ type Config struct {
VolumesFrom string VolumesFrom string
} }
func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet, error) { type HostConfig struct {
Binds []string
}
type BindMap struct {
SrcPath string
DstPath string
Mode string
}
func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, *flag.FlagSet, error) {
cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container") cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
if len(args) > 0 && args[0] != "--help" { if len(args) > 0 && args[0] != "--help" {
cmd.SetOutput(ioutil.Discard) cmd.SetOutput(ioutil.Discard)
@ -111,11 +123,14 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container") flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
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, cmd, err return nil, nil, cmd, err
} }
if *flDetach && len(flAttach) > 0 { if *flDetach && len(flAttach) > 0 {
return nil, cmd, fmt.Errorf("Conflicting options: -a and -d") return nil, nil, cmd, fmt.Errorf("Conflicting options: -a and -d")
} }
// If neither -d or -a are set, attach to everything by default // If neither -d or -a are set, attach to everything by default
if len(flAttach) == 0 && !*flDetach { if len(flAttach) == 0 && !*flDetach {
@ -127,6 +142,15 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
} }
} }
} }
// add any bind targets to the list of container volumes
type empty struct{}
for _, bind := range flBinds {
arr := strings.Split(bind, ":")
dstDir := arr[1]
flVolumes[dstDir] = empty{}
}
parsedArgs := cmd.Args() parsedArgs := cmd.Args()
runCmd := []string{} runCmd := []string{}
image := "" image := ""
@ -154,6 +178,9 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
Volumes: flVolumes, Volumes: flVolumes,
VolumesFrom: *flVolumesFrom, VolumesFrom: *flVolumesFrom,
} }
hostConfig := &HostConfig{
Binds: flBinds,
}
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit { if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n") //fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
@ -164,7 +191,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
if config.OpenStdin && config.AttachStdin { if config.OpenStdin && config.AttachStdin {
config.StdinOnce = true config.StdinOnce = true
} }
return config, cmd, nil return config, hostConfig, cmd, nil
} }
type NetworkSettings struct { type NetworkSettings struct {
@ -430,7 +457,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
}) })
} }
func (container *Container) Start() error { func (container *Container) Start(hostConfig *HostConfig) error {
container.State.lock() container.State.lock()
defer container.State.unlock() defer container.State.unlock()
@ -483,6 +510,42 @@ func (container *Container) Start() error {
} }
} }
// Create the requested bind mounts
binds := []BindMap{}
// Define illegal container destinations
illegal_dsts := []string{"/", "."}
for _, bind := range hostConfig.Binds {
var src, dst, mode string
arr := strings.Split(bind, ":")
if len(arr) == 2 {
src = arr[0]
dst = arr[1]
mode = "rw"
} else if len(arr) == 3 {
src = arr[0]
dst = arr[1]
mode = arr[2]
} else {
return fmt.Errorf("Invalid bind specification: %s", bind)
}
// Bail if trying to mount to an illegal destination
for _, illegal := range illegal_dsts {
if dst == illegal {
return fmt.Errorf("Illegal bind destination: %s", dst)
}
}
bindMap := BindMap{
SrcPath: src,
DstPath: dst,
Mode: mode,
}
binds = append(binds, bindMap)
}
container.Binds = binds
if err := container.generateLXCConfig(); err != nil { if err := container.generateLXCConfig(); err != nil {
return err return err
} }
@ -552,7 +615,8 @@ func (container *Container) Start() error {
} }
func (container *Container) Run() error { func (container *Container) Run() error {
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
return err return err
} }
container.Wait() container.Wait()
@ -565,7 +629,8 @@ func (container *Container) Output() (output []byte, err error) {
return nil, err return nil, err
} }
defer pipe.Close() defer pipe.Close()
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
return nil, err return nil, err
} }
output, err = ioutil.ReadAll(pipe) output, err = ioutil.ReadAll(pipe)
@ -768,7 +833,8 @@ func (container *Container) Restart(seconds int) error {
if err := container.Stop(seconds); err != nil { if err := container.Stop(seconds); err != nil {
return err return err
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
return err return err
} }
return nil return nil

View File

@ -7,6 +7,7 @@ import (
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
"os" "os"
"path"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@ -70,7 +71,8 @@ func TestMultipleAttachRestart(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
l1, err := bufio.NewReader(stdout1).ReadString('\n') l1, err := bufio.NewReader(stdout1).ReadString('\n')
@ -111,7 +113,7 @@ func TestMultipleAttachRestart(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -306,7 +308,8 @@ func TestCommitAutoRun(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container2.Start(); err != nil { hostConfig := &HostConfig{}
if err := container2.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
container2.Wait() container2.Wait()
@ -388,7 +391,8 @@ func TestCommitRun(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container2.Start(); err != nil { hostConfig := &HostConfig{}
if err := container2.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
container2.Wait() container2.Wait()
@ -436,7 +440,8 @@ func TestStart(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -446,7 +451,7 @@ func TestStart(t *testing.T) {
if !container.State.Running { if !container.State.Running {
t.Errorf("Container should be running") t.Errorf("Container should be running")
} }
if err := container.Start(); err == nil { if err := container.Start(hostConfig); err == nil {
t.Fatalf("A running containter should be able to be started") t.Fatalf("A running containter should be able to be started")
} }
@ -528,7 +533,8 @@ func TestKillDifferentUser(t *testing.T) {
if container.State.Running { if container.State.Running {
t.Errorf("Container shouldn't be running") t.Errorf("Container shouldn't be running")
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -599,7 +605,8 @@ func TestKill(t *testing.T) {
if container.State.Running { if container.State.Running {
t.Errorf("Container shouldn't be running") t.Errorf("Container shouldn't be running")
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -724,7 +731,8 @@ func TestRestartStdin(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, err := io.WriteString(stdin, "hello world"); err != nil { if _, err := io.WriteString(stdin, "hello world"); err != nil {
@ -754,7 +762,7 @@ func TestRestartStdin(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, err := io.WriteString(stdin, "hello world #2"); err != nil { if _, err := io.WriteString(stdin, "hello world #2"); err != nil {
@ -916,10 +924,11 @@ func TestMultipleContainers(t *testing.T) {
defer runtime.Destroy(container2) defer runtime.Destroy(container2)
// Start both containers // Start both containers
if err := container1.Start(); err != nil { hostConfig := &HostConfig{}
if err := container1.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container2.Start(); err != nil { if err := container2.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -971,7 +980,8 @@ func TestStdin(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer stdin.Close() defer stdin.Close()
@ -1018,7 +1028,8 @@ func TestTty(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer stdin.Close() defer stdin.Close()
@ -1060,7 +1071,8 @@ func TestEnv(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer stdout.Close() defer stdout.Close()
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }
container.Wait() container.Wait()
@ -1196,7 +1208,8 @@ func BenchmarkRunParallel(b *testing.B) {
return return
} }
defer runtime.Destroy(container) defer runtime.Destroy(container)
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
complete <- err complete <- err
return return
} }
@ -1225,3 +1238,98 @@ func BenchmarkRunParallel(b *testing.B) {
b.Fatal(errors) b.Fatal(errors)
} }
} }
func TestBindMounts(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
tmpDir, err := ioutil.TempDir("", "docker-test")
if err != nil {
t.Fatal(err)
}
tmpFile := path.Join(tmpDir, "touch-me")
_, err = os.Create(tmpFile)
if err != nil {
t.Fatal(err)
}
// test reading from bind mount
bind_str := fmt.Sprintf("%s:/tmp:ro", tmpDir)
container, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ls", "/tmp"},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
stdout, err := container.StdoutPipe()
if err != nil {
t.Fatal(err)
}
defer stdout.Close()
hostConfig := &HostConfig{
Binds: []string{bind_str},
}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err)
}
container.Wait()
output, err := ioutil.ReadAll(stdout)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(output), "touch-me") {
t.Fatal("Container failed to read from bind mount")
}
// test writing to bind mount
bind_str2 := fmt.Sprintf("%s:/tmp:rw", tmpDir)
container2, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"touch", "/tmp/holla"},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container2)
hostConfig2 := &HostConfig{
Binds: []string{bind_str2},
}
if err := container2.Start(hostConfig2); err != nil {
t.Fatal(err)
}
container2.Wait()
_, err = ioutil.ReadFile(tmpDir + "/holla")
if err != nil {
t.Fatal("Container failed to write to bind mount")
}
// test mounting to an illegal destination directory
bind_str3 := fmt.Sprintf("%s:.", tmpDir)
container3, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ls", "."},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container3)
stdout3, err := container3.StdoutPipe()
if err != nil {
t.Fatal(err)
}
defer stdout3.Close()
hostConfig3 := &HostConfig{
Binds: []string{bind_str3},
}
if err := container3.Start(hostConfig3); err == nil {
t.Fatal("Container bind mounted illegal directory")
}
}

View File

@ -42,6 +42,9 @@ List containers (/containers/json):
- You can use size=1 to get the size of the containers - You can use size=1 to get the size of the containers
Start containers (/containers/<id>/start):
- You can now pass host-specific configuration (e.g. bind mounts) in the POST body for start calls
:doc:`docker_remote_api_v1.2` :doc:`docker_remote_api_v1.2`
***************************** *****************************

View File

@ -294,23 +294,30 @@ Start a container
.. http:post:: /containers/(id)/start .. http:post:: /containers/(id)/start
Start the container ``id`` Start the container ``id``
**Example request**: **Example request**:
.. sourcecode:: http .. sourcecode:: http
POST /containers/e90e34656806/start HTTP/1.1 POST /containers/(id)/start HTTP/1.1
Content-Type: application/json
**Example response**:
.. sourcecode:: http {
"Binds":["/tmp:/tmp"]
}
HTTP/1.1 200 OK **Example response**:
:statuscode 200: no error .. sourcecode:: http
:statuscode 404: no such container
:statuscode 500: server error HTTP/1.1 204 No Content
Content-Type: text/plain
:jsonparam hostConfig: the container's host configuration (optional)
:statuscode 200: no error
:statuscode 404: no such container
:statuscode 500: server error
Stop a contaier Stop a contaier

View File

@ -25,3 +25,4 @@
-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=[]: Creates a new volume and mounts it at the specified path.
-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]

View File

@ -88,6 +88,10 @@ lxc.mount.entry = {{.ResolvConfPath}} {{$ROOTFS}}/etc/resolv.conf none bind,ro 0
lxc.mount.entry = {{$realPath}} {{$ROOTFS}}/{{$virtualPath}} none bind,rw 0 0 lxc.mount.entry = {{$realPath}} {{$ROOTFS}}/{{$virtualPath}} none bind,rw 0 0
{{end}} {{end}}
{{end}} {{end}}
{{if .Binds}}# User-defined bind mounts
{{range $bindMap := .Binds}}lxc.mount.entry = {{$bindMap.SrcPath}} {{$ROOTFS}}{{$bindMap.DstPath}} none bind,{{$bindMap.Mode}} 0 0
{{end}}
{{end}}
# drop linux capabilities (apply mainly to the user root in the container) # drop linux capabilities (apply mainly to the user root in the container)
# (Note: 'lxc.cap.keep' is coming soon and should replace this under the # (Note: 'lxc.cap.keep' is coming soon and should replace this under the

View File

@ -144,7 +144,9 @@ func (runtime *Runtime) Register(container *Container) error {
utils.Debugf("Restarting") utils.Debugf("Restarting")
container.State.Ghost = false container.State.Ghost = false
container.State.setStopped(0) container.State.setStopped(0)
if err := container.Start(); err != nil { // assume empty host config
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
return err return err
} }
nomonitor = true nomonitor = true

View File

@ -327,7 +327,8 @@ func findAvailalblePort(runtime *Runtime, port int) (*Container, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := container.Start(); err != nil { hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if strings.Contains(err.Error(), "address already in use") { if strings.Contains(err.Error(), "address already in use") {
return nil, nil return nil, nil
} }
@ -437,7 +438,8 @@ func TestRestore(t *testing.T) {
defer runtime1.Destroy(container2) defer runtime1.Destroy(container2)
// Start the container non blocking // Start the container non blocking
if err := container2.Start(); err != nil { hostConfig := &HostConfig{}
if err := container2.Start(hostConfig); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -87,7 +87,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
} }
defer file.Body.Close() defer file.Body.Close()
config, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities) config, _, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -934,9 +934,9 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
return nil, nil return nil, nil
} }
func (srv *Server) ContainerStart(name string) error { func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
if container := srv.runtime.Get(name); container != nil { if container := srv.runtime.Get(name); container != nil {
if err := container.Start(); err != nil { if err := container.Start(hostConfig); err != nil {
return fmt.Errorf("Error starting container %s: %s", name, err.Error()) return fmt.Errorf("Error starting container %s: %s", name, err.Error())
} }
} else { } else {

View File

@ -65,7 +65,7 @@ func TestCreateRm(t *testing.T) {
srv := &Server{runtime: runtime} srv := &Server{runtime: runtime}
config, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil) config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -98,7 +98,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
srv := &Server{runtime: runtime} srv := &Server{runtime: runtime}
config, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil) config, hostConfig, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -112,7 +112,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
t.Errorf("Expected 1 container, %v found", len(runtime.List())) t.Errorf("Expected 1 container, %v found", len(runtime.List()))
} }
err = srv.ContainerStart(id) err = srv.ContainerStart(id, hostConfig)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -127,7 +127,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = srv.ContainerStart(id) err = srv.ContainerStart(id, hostConfig)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }