+ Runtime: mount volumes from a host directory with 'docker run -b'
This commit is contained in:
parent
cd0f22ef72
commit
4fdf11b2e6
14 changed files with 273 additions and 58 deletions
11
api.go
11
api.go
|
@ -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 {
|
||||
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 {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
name := vars["name"]
|
||||
if err := srv.ContainerStart(name); err != nil {
|
||||
if err := srv.ContainerStart(name, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
|
26
api_test.go
26
api_test.go
|
@ -873,7 +873,8 @@ func TestPostContainersKill(t *testing.T) {
|
|||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -917,7 +918,8 @@ func TestPostContainersRestart(t *testing.T) {
|
|||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -973,8 +975,15 @@ func TestPostContainersStart(t *testing.T) {
|
|||
}
|
||||
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()
|
||||
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)
|
||||
}
|
||||
if r.Code != http.StatusNoContent {
|
||||
|
@ -989,7 +998,7 @@ func TestPostContainersStart(t *testing.T) {
|
|||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1028,8 @@ func TestPostContainersStop(t *testing.T) {
|
|||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -1068,7 +1078,8 @@ func TestPostContainersWait(t *testing.T) {
|
|||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -1113,7 +1124,8 @@ func TestPostContainersAttach(t *testing.T) {
|
|||
defer runtime.Destroy(container)
|
||||
|
||||
// Start the process
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ func (b *buildFile) CmdRun(args string) error {
|
|||
if b.image == "" {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -263,7 +263,8 @@ func (b *buildFile) run() (string, error) {
|
|||
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
|
||||
|
||||
//start the container
|
||||
if err := c.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := c.Start(hostConfig); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
|
@ -1235,7 +1235,7 @@ func (cli *DockerCli) CmdTag(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 {
|
||||
return err
|
||||
}
|
||||
|
@ -1274,7 +1274,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||
}
|
||||
|
||||
//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
|
||||
}
|
||||
|
||||
|
|
82
container.go
82
container.go
|
@ -52,6 +52,8 @@ type Container struct {
|
|||
|
||||
waitLock chan struct{}
|
||||
Volumes map[string]string
|
||||
|
||||
Binds []BindMap
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
|
@ -75,7 +77,17 @@ type Config struct {
|
|||
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")
|
||||
if len(args) > 0 && args[0] != "--help" {
|
||||
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")
|
||||
|
||||
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 {
|
||||
return nil, cmd, err
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
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 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()
|
||||
runCmd := []string{}
|
||||
image := ""
|
||||
|
@ -154,6 +178,9 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *flag.FlagSet
|
|||
Volumes: flVolumes,
|
||||
VolumesFrom: *flVolumesFrom,
|
||||
}
|
||||
hostConfig := &HostConfig{
|
||||
Binds: flBinds,
|
||||
}
|
||||
|
||||
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
|
||||
//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 {
|
||||
config.StdinOnce = true
|
||||
}
|
||||
return config, cmd, nil
|
||||
return config, hostConfig, cmd, nil
|
||||
}
|
||||
|
||||
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()
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -552,7 +615,8 @@ func (container *Container) Start() error {
|
|||
}
|
||||
|
||||
func (container *Container) Run() error {
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
container.Wait()
|
||||
|
@ -565,7 +629,8 @@ func (container *Container) Output() (output []byte, err error) {
|
|||
return nil, err
|
||||
}
|
||||
defer pipe.Close()
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output, err = ioutil.ReadAll(pipe)
|
||||
|
@ -768,7 +833,8 @@ func (container *Container) Restart(seconds int) error {
|
|||
if err := container.Stop(seconds); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
@ -70,7 +71,8 @@ func TestMultipleAttachRestart(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
l1, err := bufio.NewReader(stdout1).ReadString('\n')
|
||||
|
@ -111,7 +113,7 @@ func TestMultipleAttachRestart(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -306,7 +308,8 @@ func TestCommitAutoRun(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container2.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container2.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2.Wait()
|
||||
|
@ -388,7 +391,8 @@ func TestCommitRun(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container2.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container2.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2.Wait()
|
||||
|
@ -436,7 +440,8 @@ func TestStart(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -446,7 +451,7 @@ func TestStart(t *testing.T) {
|
|||
if !container.State.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")
|
||||
}
|
||||
|
||||
|
@ -528,7 +533,8 @@ func TestKillDifferentUser(t *testing.T) {
|
|||
if container.State.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)
|
||||
}
|
||||
|
||||
|
@ -599,7 +605,8 @@ func TestKill(t *testing.T) {
|
|||
if container.State.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)
|
||||
}
|
||||
|
||||
|
@ -724,7 +731,8 @@ func TestRestartStdin(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := io.WriteString(stdin, "hello world"); err != nil {
|
||||
|
@ -754,7 +762,7 @@ func TestRestartStdin(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := io.WriteString(stdin, "hello world #2"); err != nil {
|
||||
|
@ -916,10 +924,11 @@ func TestMultipleContainers(t *testing.T) {
|
|||
defer runtime.Destroy(container2)
|
||||
|
||||
// Start both containers
|
||||
if err := container1.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container1.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container2.Start(); err != nil {
|
||||
if err := container2.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -971,7 +980,8 @@ func TestStdin(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stdin.Close()
|
||||
|
@ -1018,7 +1028,8 @@ func TestTty(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stdin.Close()
|
||||
|
@ -1060,7 +1071,8 @@ func TestEnv(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
defer stdout.Close()
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container.Wait()
|
||||
|
@ -1196,7 +1208,8 @@ func BenchmarkRunParallel(b *testing.B) {
|
|||
return
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
if err := container.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
complete <- err
|
||||
return
|
||||
}
|
||||
|
@ -1225,3 +1238,98 @@ func BenchmarkRunParallel(b *testing.B) {
|
|||
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")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ List containers (/containers/json):
|
|||
|
||||
- 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`
|
||||
*****************************
|
||||
|
|
|
@ -294,23 +294,30 @@ Start a container
|
|||
|
||||
.. 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
|
||||
|
||||
**Example response**:
|
||||
POST /containers/(id)/start HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
.. sourcecode:: http
|
||||
{
|
||||
"Binds":["/tmp:/tmp"]
|
||||
}
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
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
|
||||
|
|
|
@ -25,3 +25,4 @@
|
|||
-d=[]: Set custom dns servers for the container
|
||||
-v=[]: Creates a new volume and mounts it at the specified path.
|
||||
-volumes-from="": Mount all volumes from the given container.
|
||||
-b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]
|
||||
|
|
|
@ -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
|
||||
{{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)
|
||||
# (Note: 'lxc.cap.keep' is coming soon and should replace this under the
|
||||
|
|
|
@ -144,7 +144,9 @@ func (runtime *Runtime) Register(container *Container) error {
|
|||
utils.Debugf("Restarting")
|
||||
container.State.Ghost = false
|
||||
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
|
||||
}
|
||||
nomonitor = true
|
||||
|
|
|
@ -327,7 +327,8 @@ func findAvailalblePort(runtime *Runtime, port int) (*Container, error) {
|
|||
if err != nil {
|
||||
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") {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -437,7 +438,8 @@ func TestRestore(t *testing.T) {
|
|||
defer runtime1.Destroy(container2)
|
||||
|
||||
// Start the container non blocking
|
||||
if err := container2.Start(); err != nil {
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container2.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
|
|||
}
|
||||
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 {
|
||||
return "", err
|
||||
}
|
||||
|
@ -934,9 +934,9 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
|
|||
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 err := container.Start(); err != nil {
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
return fmt.Errorf("Error starting container %s: %s", name, err.Error())
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -65,7 +65,7 @@ func TestCreateRm(t *testing.T) {
|
|||
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
|||
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
|||
t.Errorf("Expected 1 container, %v found", len(runtime.List()))
|
||||
}
|
||||
|
||||
err = srv.ContainerStart(id)
|
||||
err = srv.ContainerStart(id, hostConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = srv.ContainerStart(id)
|
||||
err = srv.ContainerStart(id, hostConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue